d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[official-gcc.git] / gcc / d / dmd / constfold.d
blobe4be63cda3e5261122c2f24644e72174eefd9061
1 /**
2 * Perform constant folding of arithmetic expressions.
4 * The routines in this module are called from `optimize.d`.
6 * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
8 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
12 * Documentation: https://dlang.org/phobos/dmd_constfold.html
13 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d
16 module dmd.constfold;
18 import core.stdc.string;
19 import core.stdc.stdio;
20 import dmd.arraytypes;
21 import dmd.astenums;
22 import dmd.ctfeexpr;
23 import dmd.declaration;
24 import dmd.dstruct;
25 import dmd.errors;
26 import dmd.expression;
27 import dmd.globals;
28 import dmd.location;
29 import dmd.mtype;
30 import dmd.root.complex;
31 import dmd.root.ctfloat;
32 import dmd.root.port;
33 import dmd.root.rmem;
34 import dmd.root.utf;
35 import dmd.sideeffect;
36 import dmd.target;
37 import dmd.tokens;
39 private enum LOG = false;
41 private Expression expType(Type type, Expression e)
43 if (type != e.type)
45 e = e.copy();
46 e.type = type;
48 return e;
51 /************************************
52 * Returns:
53 * true if e is a constant
55 int isConst(Expression e)
57 //printf("Expression::isConst(): %s\n", e.toChars());
58 switch (e.op)
60 case EXP.int64:
61 case EXP.float64:
62 case EXP.complex80:
63 return 1;
64 case EXP.null_:
65 return 0;
66 case EXP.symbolOffset:
67 return 2;
68 default:
69 return 0;
71 assert(0);
74 /**********************************
75 * Initialize a EXP.cantExpression Expression.
76 * Params:
77 * ue = where to write it
79 void cantExp(out UnionExp ue)
81 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
84 /* =============================== constFold() ============================== */
85 /* The constFold() functions were redundant with the optimize() ones,
86 * and so have been folded in with them.
88 /* ========================================================================== */
89 UnionExp Neg(Type type, Expression e1)
91 UnionExp ue = void;
92 Loc loc = e1.loc;
93 if (e1.type.isreal())
95 emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
97 else if (e1.type.isimaginary())
99 emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
101 else if (e1.type.iscomplex())
103 emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
105 else
107 emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
109 return ue;
112 UnionExp Com(Type type, Expression e1)
114 UnionExp ue = void;
115 Loc loc = e1.loc;
116 emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
117 return ue;
120 UnionExp Not(Type type, Expression e1)
122 UnionExp ue = void;
123 Loc loc = e1.loc;
124 // BUG: Should be replaced with e1.toBool().get(), but this is apparently
125 // executed for some expressions that cannot be const-folded
126 // To be fixed in another PR
127 emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
128 return ue;
131 UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
133 UnionExp ue = void;
134 static if (LOG)
136 printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
138 if (type.isreal())
140 emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
142 else if (type.isimaginary())
144 emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
146 else if (type.iscomplex())
148 // This rigamarole is necessary so that -0.0 doesn't get
149 // converted to +0.0 by doing an extraneous add with +0.0
150 auto c1 = complex_t(CTFloat.zero);
151 real_t r1 = CTFloat.zero;
152 real_t i1 = CTFloat.zero;
153 auto c2 = complex_t(CTFloat.zero);
154 real_t r2 = CTFloat.zero;
155 real_t i2 = CTFloat.zero;
156 auto v = complex_t(CTFloat.zero);
157 int x;
158 if (e1.type.isreal())
160 r1 = e1.toReal();
161 x = 0;
163 else if (e1.type.isimaginary())
165 i1 = e1.toImaginary();
166 x = 3;
168 else
170 c1 = e1.toComplex();
171 x = 6;
173 if (e2.type.isreal())
175 r2 = e2.toReal();
177 else if (e2.type.isimaginary())
179 i2 = e2.toImaginary();
180 x += 1;
182 else
184 c2 = e2.toComplex();
185 x += 2;
187 switch (x)
189 case 0 + 0:
190 v = complex_t(r1 + r2);
191 break;
192 case 0 + 1:
193 v = complex_t(r1, i2);
194 break;
195 case 0 + 2:
196 v = complex_t(r1 + creall(c2), cimagl(c2));
197 break;
198 case 3 + 0:
199 v = complex_t(r2, i1);
200 break;
201 case 3 + 1:
202 v = complex_t(CTFloat.zero, i1 + i2);
203 break;
204 case 3 + 2:
205 v = complex_t(creall(c2), i1 + cimagl(c2));
206 break;
207 case 6 + 0:
208 v = complex_t(creall(c1) + r2, cimagl(c2));
209 break;
210 case 6 + 1:
211 v = complex_t(creall(c1), cimagl(c1) + i2);
212 break;
213 case 6 + 2:
214 v = c1 + c2;
215 break;
216 default:
217 assert(0);
219 emplaceExp!(ComplexExp)(&ue, loc, v, type);
221 else if (SymOffExp soe = e1.isSymOffExp())
223 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
224 ue.exp().type = type;
226 else if (SymOffExp soe = e2.isSymOffExp())
228 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
229 ue.exp().type = type;
231 else
232 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
233 return ue;
236 UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
238 // Compute e1-e2 as e1+(-e2)
239 UnionExp neg = Neg(e2.type, e2);
240 UnionExp ue = Add(loc, type, e1, neg.exp());
241 return ue;
244 UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
246 UnionExp ue = void;
247 if (type.isfloating())
249 auto c = complex_t(CTFloat.zero);
250 real_t r = CTFloat.zero;
251 if (e1.type.isreal())
253 r = e1.toReal();
254 c = e2.toComplex();
255 c = complex_t(r * creall(c), r * cimagl(c));
257 else if (e1.type.isimaginary())
259 r = e1.toImaginary();
260 c = e2.toComplex();
261 c = complex_t(-r * cimagl(c), r * creall(c));
263 else if (e2.type.isreal())
265 r = e2.toReal();
266 c = e1.toComplex();
267 c = complex_t(r * creall(c), r * cimagl(c));
269 else if (e2.type.isimaginary())
271 r = e2.toImaginary();
272 c = e1.toComplex();
273 c = complex_t(-r * cimagl(c), r * creall(c));
275 else
276 c = e1.toComplex() * e2.toComplex();
277 if (type.isreal())
278 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
279 else if (type.isimaginary())
280 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
281 else if (type.iscomplex())
282 emplaceExp!(ComplexExp)(&ue, loc, c, type);
283 else
284 assert(0);
286 else
288 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
290 return ue;
293 UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
295 UnionExp ue = void;
296 if (type.isfloating())
298 auto c = complex_t(CTFloat.zero);
299 if (e2.type.isreal())
301 if (e1.type.isreal())
303 emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
304 return ue;
306 const r = e2.toReal();
307 c = e1.toComplex();
308 c = complex_t(creall(c) / r, cimagl(c) / r);
310 else if (e2.type.isimaginary())
312 const r = e2.toImaginary();
313 c = e1.toComplex();
314 c = complex_t(cimagl(c) / r, -creall(c) / r);
316 else
318 c = e1.toComplex() / e2.toComplex();
321 if (type.isreal())
322 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
323 else if (type.isimaginary())
324 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
325 else if (type.iscomplex())
326 emplaceExp!(ComplexExp)(&ue, loc, c, type);
327 else
328 assert(0);
330 else
332 sinteger_t n1;
333 sinteger_t n2;
334 sinteger_t n;
335 n1 = e1.toInteger();
336 n2 = e2.toInteger();
337 if (n2 == 0)
339 e2.error("divide by 0");
340 emplaceExp!(ErrorExp)(&ue);
341 return ue;
343 if (n2 == -1 && !type.isunsigned())
345 // Check for int.min / -1
346 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
348 e2.error("integer overflow: `int.min / -1`");
349 emplaceExp!(ErrorExp)(&ue);
350 return ue;
352 else if (n1 == 0x8000000000000000L) // long.min / -1
354 e2.error("integer overflow: `long.min / -1L`");
355 emplaceExp!(ErrorExp)(&ue);
356 return ue;
359 if (e1.type.isunsigned() || e2.type.isunsigned())
360 n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
361 else
362 n = n1 / n2;
363 emplaceExp!(IntegerExp)(&ue, loc, n, type);
365 return ue;
368 UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
370 UnionExp ue = void;
371 if (type.isfloating())
373 auto c = complex_t(CTFloat.zero);
374 if (e2.type.isreal())
376 const r2 = e2.toReal();
377 c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
379 else if (e2.type.isimaginary())
381 const i2 = e2.toImaginary();
382 c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
384 else
385 assert(0);
386 if (type.isreal())
387 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
388 else if (type.isimaginary())
389 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
390 else if (type.iscomplex())
391 emplaceExp!(ComplexExp)(&ue, loc, c, type);
392 else
393 assert(0);
395 else
397 sinteger_t n1;
398 sinteger_t n2;
399 sinteger_t n;
400 n1 = e1.toInteger();
401 n2 = e2.toInteger();
402 if (n2 == 0)
404 e2.error("divide by 0");
405 emplaceExp!(ErrorExp)(&ue);
406 return ue;
408 if (n2 == -1 && !type.isunsigned())
410 // Check for int.min % -1
411 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
413 e2.error("integer overflow: `int.min %% -1`");
414 emplaceExp!(ErrorExp)(&ue);
415 return ue;
417 else if (n1 == 0x8000000000000000L) // long.min % -1
419 e2.error("integer overflow: `long.min %% -1L`");
420 emplaceExp!(ErrorExp)(&ue);
421 return ue;
424 if (e1.type.isunsigned() || e2.type.isunsigned())
425 n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
426 else
427 n = n1 % n2;
428 emplaceExp!(IntegerExp)(&ue, loc, n, type);
430 return ue;
433 UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
435 //printf("Pow()\n");
436 UnionExp ue;
437 // Handle integer power operations.
438 if (e2.type.isintegral())
440 dinteger_t n = e2.toInteger();
441 bool neg;
442 if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
444 if (e1.type.isintegral())
446 cantExp(ue);
447 return ue;
449 // Don't worry about overflow, from now on n is unsigned.
450 neg = true;
451 n = -n;
453 else
454 neg = false;
455 UnionExp ur, uv;
456 if (e1.type.iscomplex())
458 emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
459 emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
461 else if (e1.type.isfloating())
463 emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
464 emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
466 else
468 emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
469 emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
471 Expression r = ur.exp();
472 Expression v = uv.exp();
473 while (n != 0)
475 if (n & 1)
477 // v = v * r;
478 uv = Mul(loc, v.type, v, r);
480 n >>= 1;
481 // r = r * r
482 ur = Mul(loc, r.type, r, r);
484 if (neg)
486 // ue = 1.0 / v
487 UnionExp one;
488 emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
489 uv = Div(loc, v.type, one.exp(), v);
491 if (type.iscomplex())
492 emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
493 else if (type.isintegral())
494 emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
495 else
496 emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
498 else if (e2.type.isfloating())
500 // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
501 if (e1.toReal() < CTFloat.zero)
503 emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
505 else
506 cantExp(ue);
508 else
509 cantExp(ue);
510 return ue;
513 UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
515 UnionExp ue = void;
516 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
517 return ue;
520 UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
522 UnionExp ue = void;
523 dinteger_t value = e1.toInteger();
524 dinteger_t dcount = e2.toInteger();
525 assert(dcount <= 0xFFFFFFFF);
526 uint count = cast(uint)dcount;
527 switch (e1.type.toBasetype().ty)
529 case Tint8:
530 value = cast(byte)value >> count;
531 break;
532 case Tuns8:
533 case Tchar:
534 value = cast(ubyte)value >> count;
535 break;
536 case Tint16:
537 value = cast(short)value >> count;
538 break;
539 case Tuns16:
540 case Twchar:
541 value = cast(ushort)value >> count;
542 break;
543 case Tint32:
544 value = cast(int)value >> count;
545 break;
546 case Tuns32:
547 case Tdchar:
548 value = cast(uint)value >> count;
549 break;
550 case Tint64:
551 value = cast(long)value >> count;
552 break;
553 case Tuns64:
554 value = cast(ulong)value >> count;
555 break;
556 case Terror:
557 emplaceExp!(ErrorExp)(&ue);
558 return ue;
559 default:
560 assert(0);
562 emplaceExp!(IntegerExp)(&ue, loc, value, type);
563 return ue;
566 UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
568 UnionExp ue = void;
569 dinteger_t value = e1.toInteger();
570 dinteger_t dcount = e2.toInteger();
571 assert(dcount <= 0xFFFFFFFF);
572 uint count = cast(uint)dcount;
573 switch (e1.type.toBasetype().ty)
575 case Tint8:
576 case Tuns8:
577 case Tchar:
578 // Possible only with >>>=. >>> always gets promoted to int.
579 value = (value & 0xFF) >>> count;
580 break;
581 case Tint16:
582 case Tuns16:
583 case Twchar:
584 // Possible only with >>>=. >>> always gets promoted to int.
585 value = (value & 0xFFFF) >>> count;
586 break;
587 case Tint32:
588 case Tuns32:
589 case Tdchar:
590 value = (value & 0xFFFFFFFF) >>> count;
591 break;
592 case Tint64:
593 case Tuns64:
594 value = value >>> count;
595 break;
596 case Terror:
597 emplaceExp!(ErrorExp)(&ue);
598 return ue;
599 default:
600 assert(0);
602 emplaceExp!(IntegerExp)(&ue, loc, value, type);
603 return ue;
606 UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
608 UnionExp ue = void;
609 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
610 return ue;
613 UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
615 UnionExp ue = void;
616 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
617 return ue;
620 UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
622 //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
623 UnionExp ue = void;
624 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
625 return ue;
628 /* Also returns EXP.cantExpression if cannot be computed.
630 UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
632 UnionExp ue = void;
633 int cmp = 0;
634 real_t r1 = CTFloat.zero;
635 real_t r2 = CTFloat.zero;
636 //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
637 assert(op == EXP.equal || op == EXP.notEqual);
638 if (e1.op == EXP.null_)
640 if (e2.op == EXP.null_)
641 cmp = 1;
642 else if (StringExp es2 = e2.isStringExp())
644 cmp = (0 == es2.len);
646 else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
648 cmp = !es2.elements || (0 == es2.elements.length);
650 else
652 cantExp(ue);
653 return ue;
656 else if (e2.op == EXP.null_)
658 if (StringExp es1 = e1.isStringExp())
660 cmp = (0 == es1.len);
662 else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
664 cmp = !es1.elements || (0 == es1.elements.length);
666 else
668 cantExp(ue);
669 return ue;
672 else if (e1.op == EXP.string_ && e2.op == EXP.string_)
674 StringExp es1 = e1.isStringExp();
675 StringExp es2 = e2.isStringExp();
676 if (es1.sz != es2.sz)
678 assert(global.errors);
679 cantExp(ue);
680 return ue;
682 const data1 = es1.peekData();
683 const data2 = es2.peekData();
684 if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
685 cmp = 1;
686 else
687 cmp = 0;
689 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
691 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
692 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
693 if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
694 cmp = 1; // both arrays are empty
695 else if (!es1.elements || !es2.elements)
696 cmp = 0;
697 else if (es1.elements.length != es2.elements.length)
698 cmp = 0;
699 else
701 for (size_t i = 0; i < es1.elements.length; i++)
703 auto ee1 = es1[i];
704 auto ee2 = es2[i];
705 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
706 if (CTFEExp.isCantExp(ue.exp()))
707 return ue;
708 cmp = cast(int)ue.exp().toInteger();
709 if (cmp == 0)
710 break;
714 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
716 // Swap operands and use common code
717 Expression etmp = e1;
718 e1 = e2;
719 e2 = etmp;
720 goto Lsa;
722 else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
724 Lsa:
725 StringExp es1 = e1.isStringExp();
726 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
727 size_t dim1 = es1.len;
728 size_t dim2 = es2.elements ? es2.elements.length : 0;
729 if (dim1 != dim2)
730 cmp = 0;
731 else
733 cmp = 1; // if dim1 winds up being 0
734 foreach (i; 0 .. dim1)
736 uinteger_t c = es1.getCodeUnit(i);
737 auto ee2 = es2[i];
738 if (ee2.isConst() != 1)
740 cantExp(ue);
741 return ue;
743 cmp = (c == ee2.toInteger());
744 if (cmp == 0)
745 break;
749 else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
751 StructLiteralExp es1 = e1.isStructLiteralExp();
752 StructLiteralExp es2 = e2.isStructLiteralExp();
753 if (es1.sd != es2.sd)
754 cmp = 0;
755 else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
756 cmp = 1; // both arrays are empty
757 else if (!es1.elements || !es2.elements)
758 cmp = 0;
759 else if (es1.elements.length != es2.elements.length)
760 cmp = 0;
761 else
763 cmp = 1;
764 for (size_t i = 0; i < es1.elements.length; i++)
766 Expression ee1 = (*es1.elements)[i];
767 Expression ee2 = (*es2.elements)[i];
768 if (ee1 == ee2)
769 continue;
770 if (!ee1 || !ee2)
772 cmp = 0;
773 break;
775 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
776 if (ue.exp().op == EXP.cantExpression)
777 return ue;
778 cmp = cast(int)ue.exp().toInteger();
779 if (cmp == 0)
780 break;
784 else if (e1.isConst() != 1 || e2.isConst() != 1)
786 cantExp(ue);
787 return ue;
789 else if (e1.type.isreal())
791 r1 = e1.toReal();
792 r2 = e2.toReal();
793 goto L1;
795 else if (e1.type.isimaginary())
797 r1 = e1.toImaginary();
798 r2 = e2.toImaginary();
800 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
802 cmp = 0;
804 else
806 cmp = (r1 == r2);
809 else if (e1.type.iscomplex())
811 cmp = e1.toComplex() == e2.toComplex();
813 else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
815 cmp = (e1.toInteger() == e2.toInteger());
817 else
819 cantExp(ue);
820 return ue;
822 if (op == EXP.notEqual)
823 cmp ^= 1;
824 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
825 return ue;
828 UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
830 UnionExp ue = void;
831 int cmp;
832 if (e1.op == EXP.null_)
834 cmp = (e2.op == EXP.null_);
836 else if (e2.op == EXP.null_)
838 cmp = 0;
840 else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
842 SymOffExp es1 = e1.isSymOffExp();
843 SymOffExp es2 = e2.isSymOffExp();
844 cmp = (es1.var == es2.var && es1.offset == es2.offset);
846 else
848 if (e1.type.isfloating())
849 cmp = e1.isIdentical(e2);
850 else
852 ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
853 return ue;
856 if (op == EXP.notIdentity)
857 cmp ^= 1;
858 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
859 return ue;
862 UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
864 UnionExp ue = void;
865 dinteger_t n;
866 real_t r1 = CTFloat.zero;
867 real_t r2 = CTFloat.zero;
868 //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
869 if (e1.op == EXP.string_ && e2.op == EXP.string_)
871 StringExp es1 = e1.isStringExp();
872 StringExp es2 = e2.isStringExp();
873 size_t sz = es1.sz;
874 assert(sz == es2.sz);
875 size_t len = es1.len;
876 if (es2.len < len)
877 len = es2.len;
878 const data1 = es1.peekData();
879 const data2 = es1.peekData();
880 int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
881 if (rawCmp == 0)
882 rawCmp = cast(int)(es1.len - es2.len);
883 n = specificCmp(op, rawCmp);
885 else if (e1.isConst() != 1 || e2.isConst() != 1)
887 cantExp(ue);
888 return ue;
890 else if (e1.type.isreal())
892 r1 = e1.toReal();
893 r2 = e2.toReal();
894 goto L1;
896 else if (e1.type.isimaginary())
898 r1 = e1.toImaginary();
899 r2 = e2.toImaginary();
901 n = realCmp(op, r1, r2);
903 else if (e1.type.iscomplex())
905 assert(0);
907 else
909 sinteger_t n1;
910 sinteger_t n2;
911 n1 = e1.toInteger();
912 n2 = e2.toInteger();
913 if (e1.type.isunsigned() || e2.type.isunsigned())
914 n = intUnsignedCmp(op, n1, n2);
915 else
916 n = intSignedCmp(op, n1, n2);
918 emplaceExp!(IntegerExp)(&ue, loc, n, type);
919 return ue;
922 /* Also returns EXP.cantExpression if cannot be computed.
923 * to: type to cast to
924 * type: type to paint the result
926 UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
928 UnionExp ue = void;
929 Type tb = to.toBasetype();
930 Type typeb = type.toBasetype();
931 //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
932 //printf("\te1.type = %s\n", e1.type.toChars());
933 if (e1.type.equals(type) && type.equals(to))
935 emplaceExp!(UnionExp)(&ue, e1);
936 return ue;
938 if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
940 Expression ex = e1.isVectorExp().e1;
941 emplaceExp!(UnionExp)(&ue, ex);
942 return ue;
944 if (e1.type.toBasetype.equals(type) && type.equals(to))
946 emplaceExp!(UnionExp)(&ue, e1);
947 ue.exp().type = type;
948 return ue;
950 if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
952 goto L1;
954 // Allow covariant converions of delegates
955 // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
956 // then we wouldn't need this extra check.)
957 if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
959 goto L1;
961 /* Allow casting from one string type to another
963 if (e1.op == EXP.string_)
965 if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
967 goto L1;
970 if (e1.op == EXP.arrayLiteral && typeb == tb)
973 Expression ex = expType(to, e1);
974 emplaceExp!(UnionExp)(&ue, ex);
975 return ue;
977 if (e1.isConst() != 1)
979 cantExp(ue);
981 else if (tb.ty == Tbool)
983 const opt = e1.toBool();
984 if (opt.isEmpty())
986 cantExp(ue);
987 return ue;
990 emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
992 else if (type.isintegral())
994 if (e1.type.isfloating())
996 dinteger_t result;
997 real_t r = e1.toReal();
998 switch (typeb.ty)
1000 case Tint8:
1001 result = cast(byte)cast(sinteger_t)r;
1002 break;
1003 case Tchar:
1004 case Tuns8:
1005 result = cast(ubyte)cast(dinteger_t)r;
1006 break;
1007 case Tint16:
1008 result = cast(short)cast(sinteger_t)r;
1009 break;
1010 case Twchar:
1011 case Tuns16:
1012 result = cast(ushort)cast(dinteger_t)r;
1013 break;
1014 case Tint32:
1015 result = cast(int)r;
1016 break;
1017 case Tdchar:
1018 case Tuns32:
1019 result = cast(uint)r;
1020 break;
1021 case Tint64:
1022 result = cast(long)r;
1023 break;
1024 case Tuns64:
1025 result = cast(ulong)r;
1026 break;
1027 default:
1028 assert(0);
1030 emplaceExp!(IntegerExp)(&ue, loc, result, type);
1032 else if (type.isunsigned())
1033 emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1034 else
1035 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1037 else if (tb.isreal())
1039 real_t value = e1.toReal();
1040 emplaceExp!(RealExp)(&ue, loc, value, type);
1042 else if (tb.isimaginary())
1044 real_t value = e1.toImaginary();
1045 emplaceExp!(RealExp)(&ue, loc, value, type);
1047 else if (tb.iscomplex())
1049 complex_t value = e1.toComplex();
1050 emplaceExp!(ComplexExp)(&ue, loc, value, type);
1052 else if (tb.isscalar())
1054 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1056 else if (tb.ty == Tvoid)
1058 cantExp(ue);
1060 else if (tb.ty == Tstruct && e1.op == EXP.int64)
1062 // Struct = 0;
1063 StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
1064 assert(sd);
1065 auto elements = new Expressions();
1066 for (size_t i = 0; i < sd.fields.length; i++)
1068 VarDeclaration v = sd.fields[i];
1069 UnionExp zero;
1070 emplaceExp!(IntegerExp)(&zero, 0);
1071 ue = Cast(loc, v.type, v.type, zero.exp());
1072 if (ue.exp().op == EXP.cantExpression)
1073 return ue;
1074 elements.push(ue.exp().copy());
1076 emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
1077 ue.exp().type = type;
1079 else
1081 if (type != Type.terror)
1083 // have to change to internal compiler error
1084 // all invalid casts should be handled already in Expression::castTo().
1085 error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars());
1087 emplaceExp!(ErrorExp)(&ue);
1089 return ue;
1092 UnionExp ArrayLength(Type type, Expression e1)
1094 UnionExp ue = void;
1095 Loc loc = e1.loc;
1096 if (StringExp es1 = e1.isStringExp())
1098 emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
1100 else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1102 size_t dim = ale.elements ? ale.elements.length : 0;
1103 emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1105 else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
1107 size_t dim = ale.keys.length;
1108 emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1110 else if (e1.type.toBasetype().ty == Tsarray)
1112 Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
1113 emplaceExp!(UnionExp)(&ue, e);
1115 else if (e1.isNullExp())
1117 emplaceExp!(IntegerExp)(&ue, loc, 0, type);
1119 else
1120 cantExp(ue);
1121 return ue;
1124 /* Also return EXP.cantExpression if this fails
1126 UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
1128 UnionExp ue = void;
1129 Loc loc = e1.loc;
1130 //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1131 assert(e1.type);
1132 if (e1.op == EXP.string_ && e2.op == EXP.int64)
1134 StringExp es1 = e1.isStringExp();
1135 uinteger_t i = e2.toInteger();
1136 if (i >= es1.len)
1138 e1.error("string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len);
1139 emplaceExp!(ErrorExp)(&ue);
1141 else
1143 emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type);
1146 else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
1148 TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
1149 uinteger_t length = tsa.dim.toInteger();
1150 uinteger_t i = e2.toInteger();
1151 if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds))
1153 // C code only checks bounds if an ArrayLiteralExp
1154 e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
1155 emplaceExp!(ErrorExp)(&ue);
1157 else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1159 auto e = ale[cast(size_t)i];
1160 e.type = type;
1161 e.loc = loc;
1162 if (hasSideEffect(e))
1163 cantExp(ue);
1164 else
1165 emplaceExp!(UnionExp)(&ue, e);
1167 else
1168 cantExp(ue);
1170 else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
1172 uinteger_t i = e2.toInteger();
1173 if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1175 if (i >= ale.elements.length)
1177 e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.length);
1178 emplaceExp!(ErrorExp)(&ue);
1180 else
1182 auto e = ale[cast(size_t)i];
1183 e.type = type;
1184 e.loc = loc;
1185 if (hasSideEffect(e))
1186 cantExp(ue);
1187 else
1188 emplaceExp!(UnionExp)(&ue, e);
1191 else
1192 cantExp(ue);
1194 else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
1196 /* Search the keys backwards, in case there are duplicate keys
1198 for (size_t i = ae.keys.length; i;)
1200 i--;
1201 Expression ekey = (*ae.keys)[i];
1202 ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2);
1203 if (CTFEExp.isCantExp(ue.exp()))
1204 return ue;
1205 if (ue.exp().toBool().hasValue(true))
1207 Expression e = (*ae.values)[i];
1208 e.type = type;
1209 e.loc = loc;
1210 if (hasSideEffect(e))
1211 cantExp(ue);
1212 else
1213 emplaceExp!(UnionExp)(&ue, e);
1214 return ue;
1217 cantExp(ue);
1219 else
1220 cantExp(ue);
1221 return ue;
1224 /* Also return EXP.cantExpression if this fails
1226 UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
1228 UnionExp ue = void;
1229 Loc loc = e1.loc;
1230 static if (LOG)
1232 printf("Slice()\n");
1233 if (lwr)
1235 printf("\te1 = %s\n", e1.toChars());
1236 printf("\tlwr = %s\n", lwr.toChars());
1237 printf("\tupr = %s\n", upr.toChars());
1241 if (!lwr)
1243 if (e1.op == EXP.string_)
1244 emplaceExp(&ue, e1);
1245 else
1246 cantExp(ue);
1248 else if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
1250 StringExp es1 = e1.isStringExp();
1251 const uinteger_t ilwr = lwr.toInteger();
1252 const uinteger_t iupr = upr.toInteger();
1253 if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
1254 cantExp(ue); // https://issues.dlang.org/show_bug.cgi?id=18115
1255 else
1257 const len = cast(size_t)(iupr - ilwr);
1258 const sz = es1.sz;
1259 void* s = mem.xmalloc(len * sz);
1260 const data1 = es1.peekData();
1261 memcpy(s, data1.ptr + ilwr * sz, len * sz);
1262 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
1263 StringExp es = ue.exp().isStringExp();
1264 es.committed = es1.committed;
1265 es.type = type;
1268 else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
1270 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
1271 const uinteger_t ilwr = lwr.toInteger();
1272 const uinteger_t iupr = upr.toInteger();
1273 if (sliceBoundsCheck(0, es1.elements.length, ilwr, iupr))
1274 cantExp(ue);
1275 else
1277 auto elements = new Expressions(cast(size_t)(iupr - ilwr));
1278 memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
1279 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements);
1282 else
1283 cantExp(ue);
1284 return ue;
1287 /* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
1289 bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure
1291 assert(lwr <= upr);
1292 return !(newlwr <= newupr &&
1293 lwr <= newlwr &&
1294 newupr <= upr);
1297 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1298 * existingAE[firstIndex..firstIndex+newval.length] = newval.
1300 void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
1302 const len = newval.len;
1303 Type elemType = existingAE.type.nextOf();
1304 foreach (j; 0 .. len)
1306 const val = newval.getCodeUnit(j);
1307 (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
1311 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1312 * existingSE[firstIndex..firstIndex+newae.length] = newae.
1314 void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
1316 assert(existingSE.ownedByCtfe != OwnedBy.code);
1317 foreach (j; 0 .. newae.elements.length)
1319 existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae[j].toInteger());
1323 /* Set a slice of string 'existingSE' from a string 'newstr'.
1324 * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1326 void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
1328 assert(existingSE.ownedByCtfe != OwnedBy.code);
1329 size_t sz = existingSE.sz;
1330 assert(sz == newstr.sz);
1331 auto data1 = existingSE.borrowData();
1332 const data2 = newstr.peekData();
1333 memcpy(data1.ptr + firstIndex * sz, data2.ptr, data2.length);
1336 /* Compare a string slice with another string slice.
1337 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
1339 int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
1341 size_t sz = se1.sz;
1342 assert(sz == se2.sz);
1343 const data1 = se1.peekData();
1344 const data2 = se2.peekData();
1345 return memcmp(data1.ptr + sz * lo1, data2.ptr + sz * lo2, sz * len);
1348 /* Compare a string slice with an array literal slice
1349 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
1351 int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
1353 foreach (j; 0 .. len)
1355 const val2 = cast(dchar)ae2[j + lo2].toInteger();
1356 const val1 = se1.getCodeUnit(j + lo1);
1357 const int c = val1 - val2;
1358 if (c)
1359 return c;
1361 return 0;
1364 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1365 * Params:
1366 * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
1367 * Otherwise, `e1` itself will be pushed into the new `Expressions`.
1368 * e2 = If it's not `null`, it will be pushed/appended to the new
1369 * `Expressions` by the same way with `e1`.
1370 * Returns:
1371 * Newly allocated `Expressions`. Note that it points to the original
1372 * `Expression` values in e1 and e2.
1374 private Expressions* copyElements(Expression e1, Expression e2 = null)
1376 auto elems = new Expressions();
1378 void append(ArrayLiteralExp ale)
1380 if (!ale.elements)
1381 return;
1382 auto d = elems.length;
1383 elems.append(ale.elements);
1384 foreach (ref el; (*elems)[d .. elems.length])
1386 if (!el)
1387 el = ale.basis;
1391 if (auto ale = e1.isArrayLiteralExp())
1392 append(ale);
1393 else
1394 elems.push(e1);
1396 if (e2)
1398 if (auto ale = e2.isArrayLiteralExp())
1399 append(ale);
1400 else
1401 elems.push(e2);
1404 return elems;
1407 /* Also return EXP.cantExpression if this fails
1409 UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
1411 UnionExp ue = void;
1412 Expression e = CTFEExp.cantexp;
1413 Type t;
1414 Type t1 = e1.type.toBasetype();
1415 Type t2 = e2.type.toBasetype();
1416 //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1417 //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1419 /* e is the non-null operand, t is the type of the null operand
1421 UnionExp catNull(Expression e, Type t)
1423 Type tn = e.type.toBasetype();
1424 if (tn.ty.isSomeChar)
1426 // Create a StringExp
1427 if (t.nextOf())
1428 t = t.nextOf().toBasetype();
1429 const sz = cast(ubyte)t.size();
1430 dinteger_t v = e.toInteger();
1431 const len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
1432 void* s = mem.xmalloc(len * sz);
1433 if (t.ty == tn.ty)
1434 Port.valcpy(s, v, sz);
1435 else
1436 utf_encode(sz, s, cast(dchar)v);
1437 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1438 StringExp es = ue.exp().isStringExp();
1439 es.type = type;
1440 es.committed = 1;
1442 else
1444 // Create an ArrayLiteralExp
1445 auto elements = new Expressions();
1446 elements.push(e);
1447 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
1449 assert(ue.exp().type);
1450 return ue;
1453 if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
1455 return catNull(e2, t1);
1457 else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
1459 return catNull(e1, t2);
1461 else if (e1.op == EXP.null_ && e2.op == EXP.null_)
1463 if (type == e1.type)
1465 // Handle null ~= null
1466 if (t1.ty == Tarray && t2 == t1.nextOf())
1468 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2);
1469 assert(ue.exp().type);
1470 return ue;
1472 else
1474 emplaceExp!(UnionExp)(&ue, e1);
1475 assert(ue.exp().type);
1476 return ue;
1479 if (type == e2.type)
1481 emplaceExp!(UnionExp)(&ue, e2);
1482 assert(ue.exp().type);
1483 return ue;
1485 emplaceExp!(NullExp)(&ue, e1.loc, type);
1486 assert(ue.exp().type);
1487 return ue;
1489 else if (e1.op == EXP.string_ && e2.op == EXP.string_)
1491 // Concatenate the strings
1492 StringExp es1 = e1.isStringExp();
1493 StringExp es2 = e2.isStringExp();
1494 size_t len = es1.len + es2.len;
1495 ubyte sz = es1.sz;
1496 if (sz != es2.sz)
1498 /* Can happen with:
1499 * auto s = "foo"d ~ "bar"c;
1501 assert(global.errors);
1502 cantExp(ue);
1503 assert(ue.exp().type);
1504 return ue;
1506 void* s = mem.xmalloc(len * sz);
1507 const data1 = es1.peekData();
1508 const data2 = es2.peekData();
1509 memcpy(cast(char*)s, data1.ptr, es1.len * sz);
1510 memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
1511 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1512 StringExp es = ue.exp().isStringExp();
1513 es.committed = es1.committed | es2.committed;
1514 es.type = type;
1515 assert(ue.exp().type);
1516 return ue;
1518 else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
1520 // [chars] ~ string --> [chars]
1521 StringExp es = e2.isStringExp();
1522 ArrayLiteralExp ea = e1.isArrayLiteralExp();
1523 size_t len = es.len + ea.elements.length;
1524 auto elems = new Expressions(len);
1525 for (size_t i = 0; i < ea.elements.length; ++i)
1527 (*elems)[i] = ea[i];
1529 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1530 ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1531 sliceAssignArrayLiteralFromString(dest, es, ea.elements.length);
1532 assert(ue.exp().type);
1533 return ue;
1535 else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
1537 // string ~ [chars] --> [chars]
1538 StringExp es = e1.isStringExp();
1539 ArrayLiteralExp ea = e2.isArrayLiteralExp();
1540 size_t len = es.len + ea.elements.length;
1541 auto elems = new Expressions(len);
1542 for (size_t i = 0; i < ea.elements.length; ++i)
1544 (*elems)[es.len + i] = ea[i];
1546 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1547 ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1548 sliceAssignArrayLiteralFromString(dest, es, 0);
1549 assert(ue.exp().type);
1550 return ue;
1552 else if (e1.op == EXP.string_ && e2.op == EXP.int64)
1554 // string ~ char --> string
1555 StringExp es1 = e1.isStringExp();
1556 StringExp es;
1557 const sz = es1.sz;
1558 dinteger_t v = e2.toInteger();
1559 // Is it a concatenation of homogenous types?
1560 // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1561 bool homoConcat = (sz == t2.size());
1562 const len = es1.len + (homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v));
1563 void* s = mem.xmalloc(len * sz);
1564 const data1 = es1.peekData();
1565 memcpy(s, data1.ptr, data1.length);
1566 if (homoConcat)
1567 Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
1568 else
1569 utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
1570 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1571 es = ue.exp().isStringExp();
1572 es.committed = es1.committed;
1573 es.type = type;
1574 assert(ue.exp().type);
1575 return ue;
1577 else if (e1.op == EXP.int64 && e2.op == EXP.string_)
1579 // [w|d]?char ~ string --> string
1580 // We assume that we only ever prepend one char of the same type
1581 // (wchar,dchar) as the string's characters.
1582 StringExp es2 = e2.isStringExp();
1583 const len = 1 + es2.len;
1584 const sz = es2.sz;
1585 dinteger_t v = e1.toInteger();
1586 void* s = mem.xmalloc(len * sz);
1587 Port.valcpy(cast(char*)s, v, sz);
1588 const data2 = es2.peekData();
1589 memcpy(cast(char*)s + sz, data2.ptr, data2.length);
1590 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1591 StringExp es = ue.exp().isStringExp();
1592 es.sz = sz;
1593 es.committed = es2.committed;
1594 es.type = type;
1595 assert(ue.exp().type);
1596 return ue;
1598 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1600 // Concatenate the arrays
1601 auto elems = copyElements(e1, e2);
1603 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
1605 e = ue.exp();
1606 if (type.toBasetype().ty == Tsarray)
1608 e.type = t1.nextOf().sarrayOf(elems.length);
1610 else
1611 e.type = type;
1612 assert(ue.exp().type);
1613 return ue;
1615 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
1617 e = e1;
1618 goto L3;
1620 else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1622 e = e2;
1624 // Concatenate the array with null
1625 auto elems = copyElements(e);
1627 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems);
1629 e = ue.exp();
1630 if (type.toBasetype().ty == Tsarray)
1632 e.type = t1.nextOf().sarrayOf(elems.length);
1634 else
1635 e.type = type;
1636 assert(ue.exp().type);
1637 return ue;
1639 else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
1641 auto elems = (e1.op == EXP.arrayLiteral)
1642 ? copyElements(e1) : new Expressions();
1643 elems.push(e2);
1645 emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1647 e = ue.exp();
1648 if (type.toBasetype().ty == Tsarray)
1650 e.type = e2.type.sarrayOf(elems.length);
1652 else
1653 e.type = type;
1654 assert(ue.exp().type);
1655 return ue;
1657 else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
1659 auto elems = copyElements(e1, e2);
1661 emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1663 e = ue.exp();
1664 if (type.toBasetype().ty == Tsarray)
1666 e.type = e1.type.sarrayOf(elems.length);
1668 else
1669 e.type = type;
1670 assert(ue.exp().type);
1671 return ue;
1673 else if (e1.op == EXP.null_ && e2.op == EXP.string_)
1675 t = e1.type;
1676 e = e2;
1677 goto L1;
1679 else if (e1.op == EXP.string_ && e2.op == EXP.null_)
1681 e = e1;
1682 t = e2.type;
1684 Type tb = t.toBasetype();
1685 if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
1687 auto expressions = new Expressions();
1688 expressions.push(e);
1689 emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
1690 e = ue.exp();
1692 else
1694 emplaceExp!(UnionExp)(&ue, e);
1695 e = ue.exp();
1697 if (!e.type.equals(type))
1699 StringExp se = e.copy().isStringExp();
1700 e = se.castTo(null, type);
1701 emplaceExp!(UnionExp)(&ue, e);
1702 e = ue.exp();
1705 else
1706 cantExp(ue);
1707 assert(ue.exp().type);
1708 return ue;
1711 UnionExp Ptr(Type type, Expression e1)
1713 //printf("Ptr(e1 = %s)\n", e1.toChars());
1714 UnionExp ue = void;
1715 if (AddExp ae = e1.isAddExp())
1717 if (AddrExp ade = ae.e1.isAddrExp())
1719 if (ae.e2.op == EXP.int64)
1720 if (StructLiteralExp se = ade.e1.isStructLiteralExp())
1722 uint offset = cast(uint)ae.e2.toInteger();
1723 Expression e = se.getField(type, offset);
1724 if (e)
1726 emplaceExp!(UnionExp)(&ue, e);
1727 return ue;
1732 cantExp(ue);
1733 return ue;