1 /**
2  * Perform constant folding of arithmetic expressions.
3  *
4  * The routines in this module are called from `optimize.d`.
5  *
6  * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
7  *
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
14  */
15 
16 module dmd.constfold;
17 
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.dcast;
24 import dmd.declaration;
25 import dmd.dstruct;
26 import dmd.errors;
27 import dmd.expression;
28 import dmd.globals;
29 import dmd.location;
30 import dmd.mtype;
31 import dmd.root.complex;
32 import dmd.root.ctfloat;
33 import dmd.root.port;
34 import dmd.root.rmem;
35 import dmd.root.utf;
36 import dmd.sideeffect;
37 import dmd.target;
38 import dmd.tokens;
39 
40 private enum LOG = false;
41 
42 private Expression expType(Type type, Expression e)
43 {
44     if (type != e.type)
45     {
46         e = e.copy();
47         e.type = type;
48     }
49     return e;
50 }
51 
52 /**********************************
53  * Initialize a EXP.cantExpression Expression.
54  * Params:
55  *      ue = where to write it
56  */
57 void cantExp(out UnionExp ue)
58 {
59     emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
60 }
61 
62 /* =============================== constFold() ============================== */
63 /* The constFold() functions were redundant with the optimize() ones,
64  * and so have been folded in with them.
65  */
66 /* ========================================================================== */
67 UnionExp Neg(Type type, Expression e1)
68 {
69     UnionExp ue = void;
70     Loc loc = e1.loc;
71     if (e1.type.isreal())
72     {
73         emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
74     }
75     else if (e1.type.isimaginary())
76     {
77         emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
78     }
79     else if (e1.type.iscomplex())
80     {
81         emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
82     }
83     else
84     {
85         emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
86     }
87     return ue;
88 }
89 
90 UnionExp Com(Type type, Expression e1)
91 {
92     UnionExp ue = void;
93     Loc loc = e1.loc;
94     emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
95     return ue;
96 }
97 
98 UnionExp Not(Type type, Expression e1)
99 {
100     UnionExp ue = void;
101     Loc loc = e1.loc;
102     // BUG: Should be replaced with e1.toBool().get(), but this is apparently
103     //      executed for some expressions that cannot be const-folded
104     //      To be fixed in another PR
105     emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
106     return ue;
107 }
108 
109 UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
110 {
111     UnionExp ue = void;
112     static if (LOG)
113     {
114         printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
115     }
116     if (type.isreal())
117     {
118         emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
119     }
120     else if (type.isimaginary())
121     {
122         emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
123     }
124     else if (type.iscomplex())
125     {
126         // This rigamarole is necessary so that -0.0 doesn't get
127         // converted to +0.0 by doing an extraneous add with +0.0
128         auto c1 = complex_t(CTFloat.zero);
129         real_t r1 = CTFloat.zero;
130         real_t i1 = CTFloat.zero;
131         auto c2 = complex_t(CTFloat.zero);
132         real_t r2 = CTFloat.zero;
133         real_t i2 = CTFloat.zero;
134         auto v = complex_t(CTFloat.zero);
135         int x;
136         if (e1.type.isreal())
137         {
138             r1 = e1.toReal();
139             x = 0;
140         }
141         else if (e1.type.isimaginary())
142         {
143             i1 = e1.toImaginary();
144             x = 3;
145         }
146         else
147         {
148             c1 = e1.toComplex();
149             x = 6;
150         }
151         if (e2.type.isreal())
152         {
153             r2 = e2.toReal();
154         }
155         else if (e2.type.isimaginary())
156         {
157             i2 = e2.toImaginary();
158             x += 1;
159         }
160         else
161         {
162             c2 = e2.toComplex();
163             x += 2;
164         }
165         switch (x)
166         {
167         case 0 + 0:
168             v = complex_t(r1 + r2);
169             break;
170         case 0 + 1:
171             v = complex_t(r1, i2);
172             break;
173         case 0 + 2:
174             v = complex_t(r1 + creall(c2), cimagl(c2));
175             break;
176         case 3 + 0:
177             v = complex_t(r2, i1);
178             break;
179         case 3 + 1:
180             v = complex_t(CTFloat.zero, i1 + i2);
181             break;
182         case 3 + 2:
183             v = complex_t(creall(c2), i1 + cimagl(c2));
184             break;
185         case 6 + 0:
186             v = complex_t(creall(c1) + r2, cimagl(c2));
187             break;
188         case 6 + 1:
189             v = complex_t(creall(c1), cimagl(c1) + i2);
190             break;
191         case 6 + 2:
192             v = c1 + c2;
193             break;
194         default:
195             assert(0);
196         }
197         emplaceExp!(ComplexExp)(&ue, loc, v, type);
198     }
199     else if (SymOffExp soe = e1.isSymOffExp())
200     {
201         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
202         ue.exp().type = type;
203     }
204     else if (SymOffExp soe = e2.isSymOffExp())
205     {
206         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
207         ue.exp().type = type;
208     }
209     else
210         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
211     return ue;
212 }
213 
214 UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
215 {
216     // Compute e1-e2 as e1+(-e2)
217     UnionExp neg = Neg(e2.type, e2);
218     UnionExp ue = Add(loc, type, e1, neg.exp());
219     return ue;
220 }
221 
222 UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
223 {
224     UnionExp ue = void;
225     if (type.isfloating())
226     {
227         auto c = complex_t(CTFloat.zero);
228         real_t r = CTFloat.zero;
229         if (e1.type.isreal())
230         {
231             r = e1.toReal();
232             c = e2.toComplex();
233             c = complex_t(r * creall(c), r * cimagl(c));
234         }
235         else if (e1.type.isimaginary())
236         {
237             r = e1.toImaginary();
238             c = e2.toComplex();
239             c = complex_t(-r * cimagl(c), r * creall(c));
240         }
241         else if (e2.type.isreal())
242         {
243             r = e2.toReal();
244             c = e1.toComplex();
245             c = complex_t(r * creall(c), r * cimagl(c));
246         }
247         else if (e2.type.isimaginary())
248         {
249             r = e2.toImaginary();
250             c = e1.toComplex();
251             c = complex_t(-r * cimagl(c), r * creall(c));
252         }
253         else
254             c = e1.toComplex() * e2.toComplex();
255         if (type.isreal())
256             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
257         else if (type.isimaginary())
258             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
259         else if (type.iscomplex())
260             emplaceExp!(ComplexExp)(&ue, loc, c, type);
261         else
262             assert(0);
263     }
264     else
265     {
266         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
267     }
268     return ue;
269 }
270 
271 UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
272 {
273     UnionExp ue = void;
274     if (type.isfloating())
275     {
276         auto c = complex_t(CTFloat.zero);
277         if (e2.type.isreal())
278         {
279             if (e1.type.isreal())
280             {
281                 emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
282                 return ue;
283             }
284             const r = e2.toReal();
285             c = e1.toComplex();
286             c = complex_t(creall(c) / r, cimagl(c) / r);
287         }
288         else if (e2.type.isimaginary())
289         {
290             const r = e2.toImaginary();
291             c = e1.toComplex();
292             c = complex_t(cimagl(c) / r, -creall(c) / r);
293         }
294         else
295         {
296             c = e1.toComplex() / e2.toComplex();
297         }
298 
299         if (type.isreal())
300             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
301         else if (type.isimaginary())
302             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
303         else if (type.iscomplex())
304             emplaceExp!(ComplexExp)(&ue, loc, c, type);
305         else
306             assert(0);
307     }
308     else
309     {
310         sinteger_t n1;
311         sinteger_t n2;
312         sinteger_t n;
313         n1 = e1.toInteger();
314         n2 = e2.toInteger();
315         if (n2 == 0)
316         {
317             error(e2.loc, "divide by 0");
318             emplaceExp!(ErrorExp)(&ue);
319             return ue;
320         }
321         if (n2 == -1 && !type.isunsigned())
322         {
323             // Check for int.min / -1
324             if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
325             {
326                 error(e2.loc, "integer overflow: `int.min / -1`");
327                 emplaceExp!(ErrorExp)(&ue);
328                 return ue;
329             }
330             else if (n1 == 0x8000000000000000L) // long.min / -1
331             {
332                 error(e2.loc, "integer overflow: `long.min / -1L`");
333                 emplaceExp!(ErrorExp)(&ue);
334                 return ue;
335             }
336         }
337         if (e1.type.isunsigned() || e2.type.isunsigned())
338             n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
339         else
340             n = n1 / n2;
341         emplaceExp!(IntegerExp)(&ue, loc, n, type);
342     }
343     return ue;
344 }
345 
346 UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
347 {
348     UnionExp ue = void;
349     if (type.isfloating())
350     {
351         auto c = complex_t(CTFloat.zero);
352         if (e2.type.isreal())
353         {
354             const r2 = e2.toReal();
355             c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
356         }
357         else if (e2.type.isimaginary())
358         {
359             const i2 = e2.toImaginary();
360             c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
361         }
362         else
363             assert(0);
364         if (type.isreal())
365             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
366         else if (type.isimaginary())
367             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
368         else if (type.iscomplex())
369             emplaceExp!(ComplexExp)(&ue, loc, c, type);
370         else
371             assert(0);
372     }
373     else
374     {
375         sinteger_t n1;
376         sinteger_t n2;
377         sinteger_t n;
378         n1 = e1.toInteger();
379         n2 = e2.toInteger();
380         if (n2 == 0)
381         {
382             error(e2.loc, "divide by 0");
383             emplaceExp!(ErrorExp)(&ue);
384             return ue;
385         }
386         if (n2 == -1 && !type.isunsigned())
387         {
388             // Check for int.min % -1
389             if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
390             {
391                 error(e2.loc, "integer overflow: `int.min %% -1`");
392                 emplaceExp!(ErrorExp)(&ue);
393                 return ue;
394             }
395             else if (n1 == 0x8000000000000000L) // long.min % -1
396             {
397                 error(e2.loc, "integer overflow: `long.min %% -1L`");
398                 emplaceExp!(ErrorExp)(&ue);
399                 return ue;
400             }
401         }
402         if (e1.type.isunsigned() || e2.type.isunsigned())
403             n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
404         else
405             n = n1 % n2;
406         emplaceExp!(IntegerExp)(&ue, loc, n, type);
407     }
408     return ue;
409 }
410 
411 UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
412 {
413     //printf("Pow()\n");
414     UnionExp ue;
415     // Handle integer power operations.
416     if (e2.type.isintegral())
417     {
418         dinteger_t n = e2.toInteger();
419         bool neg;
420         if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
421         {
422             if (e1.type.isintegral())
423             {
424                 cantExp(ue);
425                 return ue;
426             }
427             // Don't worry about overflow, from now on n is unsigned.
428             neg = true;
429             n = -n;
430         }
431         else
432             neg = false;
433         UnionExp ur, uv;
434         if (e1.type.iscomplex())
435         {
436             emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
437             emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
438         }
439         else if (e1.type.isfloating())
440         {
441             emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
442             emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
443         }
444         else
445         {
446             emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
447             emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
448         }
449         Expression r = ur.exp();
450         Expression v = uv.exp();
451         while (n != 0)
452         {
453             if (n & 1)
454             {
455                 // v = v * r;
456                 uv = Mul(loc, v.type, v, r);
457             }
458             n >>= 1;
459             // r = r * r
460             ur = Mul(loc, r.type, r, r);
461         }
462         if (neg)
463         {
464             // ue = 1.0 / v
465             UnionExp one;
466             emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
467             uv = Div(loc, v.type, one.exp(), v);
468         }
469         if (type.iscomplex())
470             emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
471         else if (type.isintegral())
472             emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
473         else
474             emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
475     }
476     else if (e2.type.isfloating())
477     {
478         // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
479         if (e1.toReal() < CTFloat.zero)
480         {
481             emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
482         }
483         else
484             cantExp(ue);
485     }
486     else
487         cantExp(ue);
488     return ue;
489 }
490 
491 UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
492 {
493     UnionExp ue = void;
494     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
495     return ue;
496 }
497 
498 UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
499 {
500     UnionExp ue = void;
501     dinteger_t value = e1.toInteger();
502     dinteger_t dcount = e2.toInteger();
503     assert(dcount <= 0xFFFFFFFF);
504     uint count = cast(uint)dcount;
505     switch (e1.type.toBasetype().ty)
506     {
507     case Tint8:
508         value = cast(byte)value >> count;
509         break;
510     case Tuns8:
511     case Tchar:
512         value = cast(ubyte)value >> count;
513         break;
514     case Tint16:
515         value = cast(short)value >> count;
516         break;
517     case Tuns16:
518     case Twchar:
519         value = cast(ushort)value >> count;
520         break;
521     case Tint32:
522         value = cast(int)value >> count;
523         break;
524     case Tuns32:
525     case Tdchar:
526         value = cast(uint)value >> count;
527         break;
528     case Tint64:
529         value = cast(long)value >> count;
530         break;
531     case Tuns64:
532         value = cast(ulong)value >> count;
533         break;
534     case Terror:
535         emplaceExp!(ErrorExp)(&ue);
536         return ue;
537     default:
538         assert(0);
539     }
540     emplaceExp!(IntegerExp)(&ue, loc, value, type);
541     return ue;
542 }
543 
544 UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
545 {
546     UnionExp ue = void;
547     dinteger_t value = e1.toInteger();
548     dinteger_t dcount = e2.toInteger();
549     assert(dcount <= 0xFFFFFFFF);
550     uint count = cast(uint)dcount;
551     switch (e1.type.toBasetype().ty)
552     {
553     case Tint8:
554     case Tuns8:
555     case Tchar:
556         // Possible only with >>>=. >>> always gets promoted to int.
557         value = (value & 0xFF) >>> count;
558         break;
559     case Tint16:
560     case Tuns16:
561     case Twchar:
562         // Possible only with >>>=. >>> always gets promoted to int.
563         value = (value & 0xFFFF) >>> count;
564         break;
565     case Tint32:
566     case Tuns32:
567     case Tdchar:
568         value = (value & 0xFFFFFFFF) >>> count;
569         break;
570     case Tint64:
571     case Tuns64:
572         value = value >>> count;
573         break;
574     case Terror:
575         emplaceExp!(ErrorExp)(&ue);
576         return ue;
577     default:
578         assert(0);
579     }
580     emplaceExp!(IntegerExp)(&ue, loc, value, type);
581     return ue;
582 }
583 
584 UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
585 {
586     UnionExp ue = void;
587     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
588     return ue;
589 }
590 
591 UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
592 {
593     UnionExp ue = void;
594     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
595     return ue;
596 }
597 
598 UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
599 {
600     //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
601     UnionExp ue = void;
602     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
603     return ue;
604 }
605 
606 /* Also returns EXP.cantExpression if cannot be computed.
607  */
608 UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
609 {
610     UnionExp ue = void;
611     int cmp = 0;
612     real_t r1 = CTFloat.zero;
613     real_t r2 = CTFloat.zero;
614     //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
615     assert(op == EXP.equal || op == EXP.notEqual);
616     if (e1.op == EXP.null_)
617     {
618         if (e2.op == EXP.null_)
619             cmp = 1;
620         else if (StringExp es2 = e2.isStringExp())
621         {
622             cmp = (0 == es2.len);
623         }
624         else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
625         {
626             cmp = !es2.elements || (0 == es2.elements.length);
627         }
628         else
629         {
630             cantExp(ue);
631             return ue;
632         }
633     }
634     else if (e2.op == EXP.null_)
635     {
636         if (StringExp es1 = e1.isStringExp())
637         {
638             cmp = (0 == es1.len);
639         }
640         else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
641         {
642             cmp = !es1.elements || (0 == es1.elements.length);
643         }
644         else
645         {
646             cantExp(ue);
647             return ue;
648         }
649     }
650     else if (e1.op == EXP.string_ && e2.op == EXP.string_)
651     {
652         StringExp es1 = e1.isStringExp();
653         StringExp es2 = e2.isStringExp();
654         if (es1.sz != es2.sz)
655         {
656             assert(global.errors);
657             cantExp(ue);
658             return ue;
659         }
660         const data1 = es1.peekData();
661         const data2 = es2.peekData();
662         if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
663             cmp = 1;
664         else
665             cmp = 0;
666     }
667     else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
668     {
669         ArrayLiteralExp es1 = e1.isArrayLiteralExp();
670         ArrayLiteralExp es2 = e2.isArrayLiteralExp();
671         if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
672             cmp = 1; // both arrays are empty
673         else if (!es1.elements || !es2.elements)
674             cmp = 0;
675         else if (es1.elements.length != es2.elements.length)
676             cmp = 0;
677         else
678         {
679             for (size_t i = 0; i < es1.elements.length; i++)
680             {
681                 auto ee1 = es1[i];
682                 auto ee2 = es2[i];
683                 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
684                 if (CTFEExp.isCantExp(ue.exp()))
685                     return ue;
686                 cmp = cast(int)ue.exp().toInteger();
687                 if (cmp == 0)
688                     break;
689             }
690         }
691     }
692     else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
693     {
694         // Swap operands and use common code
695         Expression etmp = e1;
696         e1 = e2;
697         e2 = etmp;
698         goto Lsa;
699     }
700     else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
701     {
702     Lsa:
703         StringExp es1 = e1.isStringExp();
704         ArrayLiteralExp es2 = e2.isArrayLiteralExp();
705         size_t dim1 = es1.len;
706         size_t dim2 = es2.elements ? es2.elements.length : 0;
707         if (dim1 != dim2)
708             cmp = 0;
709         else
710         {
711             cmp = 1; // if dim1 winds up being 0
712             foreach (i; 0 .. dim1)
713             {
714                 uinteger_t c = es1.getCodeUnit(i);
715                 auto ee2 = es2[i];
716                 if (ee2.isConst() != 1)
717                 {
718                     cantExp(ue);
719                     return ue;
720                 }
721                 cmp = (c == ee2.toInteger());
722                 if (cmp == 0)
723                     break;
724             }
725         }
726     }
727     else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
728     {
729         StructLiteralExp es1 = e1.isStructLiteralExp();
730         StructLiteralExp es2 = e2.isStructLiteralExp();
731         if (es1.sd != es2.sd)
732             cmp = 0;
733         else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
734             cmp = 1; // both arrays are empty
735         else if (!es1.elements || !es2.elements)
736             cmp = 0;
737         else if (es1.elements.length != es2.elements.length)
738             cmp = 0;
739         else
740         {
741             cmp = 1;
742             for (size_t i = 0; i < es1.elements.length; i++)
743             {
744                 Expression ee1 = (*es1.elements)[i];
745                 Expression ee2 = (*es2.elements)[i];
746                 if (ee1 == ee2)
747                     continue;
748                 if (!ee1 || !ee2)
749                 {
750                     cmp = 0;
751                     break;
752                 }
753                 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
754                 if (ue.exp().op == EXP.cantExpression)
755                     return ue;
756                 cmp = cast(int)ue.exp().toInteger();
757                 if (cmp == 0)
758                     break;
759             }
760         }
761     }
762     else if (e1.isConst() != 1 || e2.isConst() != 1)
763     {
764         cantExp(ue);
765         return ue;
766     }
767     else if (e1.type.isreal())
768     {
769         r1 = e1.toReal();
770         r2 = e2.toReal();
771         goto L1;
772     }
773     else if (e1.type.isimaginary())
774     {
775         r1 = e1.toImaginary();
776         r2 = e2.toImaginary();
777     L1:
778         if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
779         {
780             cmp = 0;
781         }
782         else
783         {
784             cmp = (r1 == r2);
785         }
786     }
787     else if (e1.type.iscomplex())
788     {
789         cmp = e1.toComplex() == e2.toComplex();
790     }
791     else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
792     {
793         cmp = (e1.toInteger() == e2.toInteger());
794     }
795     else
796     {
797         cantExp(ue);
798         return ue;
799     }
800     if (op == EXP.notEqual)
801         cmp ^= 1;
802     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
803     return ue;
804 }
805 
806 UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
807 {
808     UnionExp ue = void;
809     int cmp;
810     if (e1.op == EXP.null_)
811     {
812         cmp = (e2.op == EXP.null_);
813     }
814     else if (e2.op == EXP.null_)
815     {
816         cmp = 0;
817     }
818     else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
819     {
820         SymOffExp es1 = e1.isSymOffExp();
821         SymOffExp es2 = e2.isSymOffExp();
822         cmp = (es1.var == es2.var && es1.offset == es2.offset);
823     }
824     else
825     {
826         if (e1.type.isfloating())
827             cmp = e1.isIdentical(e2);
828         else
829         {
830             ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
831             return ue;
832         }
833     }
834     if (op == EXP.notIdentity)
835         cmp ^= 1;
836     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
837     return ue;
838 }
839 
840 UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
841 {
842     UnionExp ue = void;
843     dinteger_t n;
844     real_t r1 = CTFloat.zero;
845     real_t r2 = CTFloat.zero;
846     //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
847     if (e1.op == EXP.string_ && e2.op == EXP.string_)
848     {
849         StringExp es1 = e1.isStringExp();
850         StringExp es2 = e2.isStringExp();
851         size_t sz = es1.sz;
852         assert(sz == es2.sz);
853         size_t len = es1.len;
854         if (es2.len < len)
855             len = es2.len;
856         const data1 = es1.peekData();
857         const data2 = es1.peekData();
858         int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
859         if (rawCmp == 0)
860             rawCmp = cast(int)(es1.len - es2.len);
861         n = specificCmp(op, rawCmp);
862     }
863     else if (e1.isConst() != 1 || e2.isConst() != 1)
864     {
865         cantExp(ue);
866         return ue;
867     }
868     else if (e1.type.isreal())
869     {
870         r1 = e1.toReal();
871         r2 = e2.toReal();
872         goto L1;
873     }
874     else if (e1.type.isimaginary())
875     {
876         r1 = e1.toImaginary();
877         r2 = e2.toImaginary();
878     L1:
879         n = realCmp(op, r1, r2);
880     }
881     else if (e1.type.iscomplex())
882     {
883         assert(0);
884     }
885     else
886     {
887         sinteger_t n1;
888         sinteger_t n2;
889         n1 = e1.toInteger();
890         n2 = e2.toInteger();
891         if (e1.type.isunsigned() || e2.type.isunsigned())
892             n = intUnsignedCmp(op, n1, n2);
893         else
894             n = intSignedCmp(op, n1, n2);
895     }
896     emplaceExp!(IntegerExp)(&ue, loc, n, type);
897     return ue;
898 }
899 
900 /* Also returns EXP.cantExpression if cannot be computed.
901  *  to: type to cast to
902  *  type: type to paint the result
903  */
904 UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
905 {
906     UnionExp ue = void;
907     Type tb = to.toBasetype();
908     Type typeb = type.toBasetype();
909     //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
910     //printf("\te1.type = %s\n", e1.type.toChars());
911     if (e1.type.equals(type) && type.equals(to))
912     {
913         emplaceExp!(UnionExp)(&ue, e1);
914         return ue;
915     }
916     if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
917     {
918         Expression ex = e1.isVectorExp().e1;
919         emplaceExp!(UnionExp)(&ue, ex);
920         return ue;
921     }
922     if (e1.type.toBasetype.equals(type) && type.equals(to))
923     {
924         emplaceExp!(UnionExp)(&ue, e1);
925         ue.exp().type = type;
926         return ue;
927     }
928     if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
929     {
930         goto L1;
931     }
932     // Allow covariant converions of delegates
933     // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
934     // then we wouldn't need this extra check.)
935     if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
936     {
937         goto L1;
938     }
939     /* Allow casting from one string type to another
940      */
941     if (e1.op == EXP.string_)
942     {
943         if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
944         {
945             goto L1;
946         }
947     }
948     if (e1.op == EXP.arrayLiteral && typeb == tb)
949     {
950     L1:
951         Expression ex = expType(to, e1);
952         emplaceExp!(UnionExp)(&ue, ex);
953         return ue;
954     }
955     if (e1.isConst() != 1)
956     {
957         cantExp(ue);
958     }
959     else if (tb.ty == Tbool)
960     {
961         const opt = e1.toBool();
962         if (opt.isEmpty())
963         {
964             cantExp(ue);
965             return ue;
966         }
967 
968         emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
969     }
970     else if (type.isintegral())
971     {
972         if (e1.type.isfloating())
973         {
974             dinteger_t result;
975             real_t r = e1.toReal();
976             switch (typeb.ty)
977             {
978             case Tint8:
979                 result = cast(byte)cast(sinteger_t)r;
980                 break;
981             case Tchar:
982             case Tuns8:
983                 result = cast(ubyte)cast(dinteger_t)r;
984                 break;
985             case Tint16:
986                 result = cast(short)cast(sinteger_t)r;
987                 break;
988             case Twchar:
989             case Tuns16:
990                 result = cast(ushort)cast(dinteger_t)r;
991                 break;
992             case Tint32:
993                 result = cast(int)r;
994                 break;
995             case Tdchar:
996             case Tuns32:
997                 result = cast(uint)r;
998                 break;
999             case Tint64:
1000                 result = cast(long)r;
1001                 break;
1002             case Tuns64:
1003                 result = cast(ulong)r;
1004                 break;
1005             default:
1006                 assert(0);
1007             }
1008             emplaceExp!(IntegerExp)(&ue, loc, result, type);
1009         }
1010         else if (type.isunsigned())
1011             emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1012         else
1013             emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1014     }
1015     else if (tb.isreal())
1016     {
1017         real_t value = e1.toReal();
1018         emplaceExp!(RealExp)(&ue, loc, value, type);
1019     }
1020     else if (tb.isimaginary())
1021     {
1022         real_t value = e1.toImaginary();
1023         emplaceExp!(RealExp)(&ue, loc, value, type);
1024     }
1025     else if (tb.iscomplex())
1026     {
1027         complex_t value = e1.toComplex();
1028         emplaceExp!(ComplexExp)(&ue, loc, value, type);
1029     }
1030     else if (tb.isscalar())
1031     {
1032         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1033     }
1034     else if (tb.ty == Tvoid)
1035     {
1036         cantExp(ue);
1037     }
1038     else if (tb.ty == Tstruct && e1.op == EXP.int64)
1039     {
1040         // Struct = 0;
1041         StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
1042         assert(sd);
1043         auto elements = new Expressions();
1044         for (size_t i = 0; i < sd.fields.length; i++)
1045         {
1046             VarDeclaration v = sd.fields[i];
1047             UnionExp zero;
1048             emplaceExp!(IntegerExp)(&zero, 0);
1049             ue = Cast(loc, v.type, v.type, zero.exp());
1050             if (ue.exp().op == EXP.cantExpression)
1051                 return ue;
1052             elements.push(ue.exp().copy());
1053         }
1054         emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
1055         ue.exp().type = type;
1056     }
1057     else
1058     {
1059         if (type != Type.terror)
1060         {
1061             // have to change to internal compiler error
1062             // all invalid casts should be handled already in Expression::castTo().
1063             error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars());
1064         }
1065         emplaceExp!(ErrorExp)(&ue);
1066     }
1067     return ue;
1068 }
1069 
1070 UnionExp ArrayLength(Type type, Expression e1)
1071 {
1072     UnionExp ue = void;
1073     Loc loc = e1.loc;
1074     if (StringExp es1 = e1.isStringExp())
1075     {
1076         emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
1077     }
1078     else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1079     {
1080         size_t dim = ale.elements ? ale.elements.length : 0;
1081         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1082     }
1083     else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
1084     {
1085         size_t dim = ale.keys.length;
1086         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1087     }
1088     else if (e1.type.toBasetype().ty == Tsarray)
1089     {
1090         Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
1091         emplaceExp!(UnionExp)(&ue, e);
1092     }
1093     else if (e1.isNullExp())
1094     {
1095         emplaceExp!(IntegerExp)(&ue, loc, 0, type);
1096     }
1097     else
1098         cantExp(ue);
1099     return ue;
1100 }
1101 
1102 /* Also return EXP.cantExpression if this fails
1103  */
1104 UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
1105 {
1106     UnionExp ue = void;
1107     Loc loc = e1.loc;
1108     //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1109     assert(e1.type);
1110     if (e1.op == EXP.string_ && e2.op == EXP.int64)
1111     {
1112         StringExp es1 = e1.isStringExp();
1113         uinteger_t i = e2.toInteger();
1114         if (i >= es1.len)
1115         {
1116             error(e1.loc, "string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len);
1117             emplaceExp!(ErrorExp)(&ue);
1118         }
1119         else
1120         {
1121             emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type);
1122         }
1123     }
1124     else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
1125     {
1126         TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
1127         uinteger_t length = tsa.dim.toInteger();
1128         uinteger_t i = e2.toInteger();
1129         if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds))
1130         {
1131             // C code only checks bounds if an ArrayLiteralExp
1132             error(e1.loc, "array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
1133             emplaceExp!(ErrorExp)(&ue);
1134         }
1135         else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1136         {
1137             auto e = ale[cast(size_t)i];
1138             e.type = type;
1139             e.loc = loc;
1140             if (hasSideEffect(e))
1141                 cantExp(ue);
1142             else
1143                 emplaceExp!(UnionExp)(&ue, e);
1144         }
1145         else
1146             cantExp(ue);
1147     }
1148     else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
1149     {
1150         uinteger_t i = e2.toInteger();
1151         if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1152         {
1153             if (i >= ale.elements.length)
1154             {
1155                 error(e1.loc, "array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.length);
1156                 emplaceExp!(ErrorExp)(&ue);
1157             }
1158             else
1159             {
1160                 auto e = ale[cast(size_t)i];
1161                 e.type = type;
1162                 e.loc = loc;
1163                 if (hasSideEffect(e))
1164                     cantExp(ue);
1165                 else
1166                     emplaceExp!(UnionExp)(&ue, e);
1167             }
1168         }
1169         else
1170             cantExp(ue);
1171     }
1172     else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
1173     {
1174         /* Search the keys backwards, in case there are duplicate keys
1175          */
1176         for (size_t i = ae.keys.length; i;)
1177         {
1178             i--;
1179             Expression ekey = (*ae.keys)[i];
1180             ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2);
1181             if (CTFEExp.isCantExp(ue.exp()))
1182                 return ue;
1183             if (ue.exp().toBool().hasValue(true))
1184             {
1185                 Expression e = (*ae.values)[i];
1186                 e.type = type;
1187                 e.loc = loc;
1188                 if (hasSideEffect(e))
1189                     cantExp(ue);
1190                 else
1191                     emplaceExp!(UnionExp)(&ue, e);
1192                 return ue;
1193             }
1194         }
1195         cantExp(ue);
1196     }
1197     else
1198         cantExp(ue);
1199     return ue;
1200 }
1201 
1202 /* Also return EXP.cantExpression if this fails
1203  */
1204 UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
1205 {
1206     UnionExp ue = void;
1207     Loc loc = e1.loc;
1208     static if (LOG)
1209     {
1210         printf("Slice()\n");
1211         if (lwr)
1212         {
1213             printf("\te1 = %s\n", e1.toChars());
1214             printf("\tlwr = %s\n", lwr.toChars());
1215             printf("\tupr = %s\n", upr.toChars());
1216         }
1217     }
1218 
1219     if (!lwr)
1220     {
1221         if (e1.op == EXP.string_)
1222             emplaceExp(&ue, e1);
1223         else
1224             cantExp(ue);
1225     }
1226     else if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
1227     {
1228         StringExp es1 = e1.isStringExp();
1229         const uinteger_t ilwr = lwr.toInteger();
1230         const uinteger_t iupr = upr.toInteger();
1231         if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
1232             cantExp(ue);   // https://issues.dlang.org/show_bug.cgi?id=18115
1233         else
1234         {
1235             const len = cast(size_t)(iupr - ilwr);
1236             const sz = es1.sz;
1237             void* s = mem.xmalloc(len * sz);
1238             const data1 = es1.peekData();
1239             memcpy(s, data1.ptr + ilwr * sz, len * sz);
1240             emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
1241             StringExp es = ue.exp().isStringExp();
1242             es.committed = es1.committed;
1243             es.type = type;
1244         }
1245     }
1246     else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
1247     {
1248         ArrayLiteralExp es1 = e1.isArrayLiteralExp();
1249         const uinteger_t ilwr = lwr.toInteger();
1250         const uinteger_t iupr = upr.toInteger();
1251         if (sliceBoundsCheck(0, es1.elements.length, ilwr, iupr))
1252             cantExp(ue);
1253         else
1254         {
1255             auto elements = new Expressions(cast(size_t)(iupr - ilwr));
1256             memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
1257             emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements);
1258         }
1259     }
1260     else
1261         cantExp(ue);
1262     return ue;
1263 }
1264 
1265 /* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
1266  */
1267 bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure @safe
1268 {
1269     assert(lwr <= upr);
1270     return !(newlwr <= newupr &&
1271              lwr <= newlwr &&
1272              newupr <= upr);
1273 }
1274 
1275 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1276  * existingAE[firstIndex..firstIndex+newval.length] = newval.
1277  */
1278 void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
1279 {
1280     const len = newval.len;
1281     Type elemType = existingAE.type.nextOf();
1282     foreach (j; 0 .. len)
1283     {
1284         const val = newval.getCodeUnit(j);
1285         (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
1286     }
1287 }
1288 
1289 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1290  *   existingSE[firstIndex..firstIndex+newae.length] = newae.
1291  */
1292 void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
1293 {
1294     assert(existingSE.ownedByCtfe != OwnedBy.code);
1295     foreach (j; 0 .. newae.elements.length)
1296     {
1297         existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae[j].toInteger());
1298     }
1299 }
1300 
1301 /* Set a slice of string 'existingSE' from a string 'newstr'.
1302  *   existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1303  */
1304 void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
1305 {
1306     assert(existingSE.ownedByCtfe != OwnedBy.code);
1307     size_t sz = existingSE.sz;
1308     assert(sz == newstr.sz);
1309     auto data1 = existingSE.borrowData();
1310     const data2 = newstr.peekData();
1311     memcpy(data1.ptr + firstIndex * sz, data2.ptr, data2.length);
1312 }
1313 
1314 /* Compare a string slice with another string slice.
1315  * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  se2[lo2..lo2+len])
1316  */
1317 int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
1318 {
1319     size_t sz = se1.sz;
1320     assert(sz == se2.sz);
1321     const data1 = se1.peekData();
1322     const data2 = se2.peekData();
1323     return memcmp(data1.ptr + sz * lo1, data2.ptr + sz * lo2, sz * len);
1324 }
1325 
1326 /* Compare a string slice with an array literal slice
1327  * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  ae2[lo2..lo2+len])
1328  */
1329 int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
1330 {
1331     foreach (j; 0 .. len)
1332     {
1333         const val2 = cast(dchar)ae2[j + lo2].toInteger();
1334         const val1 = se1.getCodeUnit(j + lo1);
1335         const int c = val1 - val2;
1336         if (c)
1337             return c;
1338     }
1339     return 0;
1340 }
1341 
1342 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1343  * Params:
1344  *      e1  = If it's ArrayLiteralExp, its `elements` will be copied.
1345  *            Otherwise, `e1` itself will be pushed into the new `Expressions`.
1346  *      e2  = If it's not `null`, it will be pushed/appended to the new
1347  *            `Expressions` by the same way with `e1`.
1348  * Returns:
1349  *      Newly allocated `Expressions`. Note that it points to the original
1350  *      `Expression` values in e1 and e2.
1351  */
1352 private Expressions* copyElements(Expression e1, Expression e2 = null)
1353 {
1354     auto elems = new Expressions();
1355 
1356     void append(ArrayLiteralExp ale)
1357     {
1358         if (!ale.elements)
1359             return;
1360         auto d = elems.length;
1361         elems.append(ale.elements);
1362         foreach (ref el; (*elems)[d .. elems.length])
1363         {
1364             if (!el)
1365                 el = ale.basis;
1366         }
1367     }
1368 
1369     if (auto ale = e1.isArrayLiteralExp())
1370         append(ale);
1371     else
1372         elems.push(e1);
1373 
1374     if (e2)
1375     {
1376         if (auto ale = e2.isArrayLiteralExp())
1377             append(ale);
1378         else
1379             elems.push(e2);
1380     }
1381 
1382     return elems;
1383 }
1384 
1385 /* Also return EXP.cantExpression if this fails
1386  */
1387 UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
1388 {
1389     UnionExp ue = void;
1390     Expression e = CTFEExp.cantexp;
1391     Type t;
1392     Type t1 = e1.type.toBasetype();
1393     Type t2 = e2.type.toBasetype();
1394     //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1395     //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1396 
1397     /* e is the non-null operand, t is the type of the null operand
1398      */
1399     UnionExp catNull(Expression e, Type t)
1400     {
1401         Type tn = e.type.toBasetype();
1402         if (tn.ty.isSomeChar)
1403         {
1404             // Create a StringExp
1405             if (t.nextOf())
1406                 t = t.nextOf().toBasetype();
1407             const sz = cast(ubyte)t.size();
1408             dinteger_t v = e.toInteger();
1409             const len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
1410             void* s = mem.xmalloc(len * sz);
1411             if (t.ty == tn.ty)
1412                 Port.valcpy(s, v, sz);
1413             else
1414                 utf_encode(sz, s, cast(dchar)v);
1415             emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1416             StringExp es = ue.exp().isStringExp();
1417             es.type = type;
1418             es.committed = true;
1419         }
1420         else
1421         {
1422             // Create an ArrayLiteralExp
1423             auto elements = new Expressions();
1424             elements.push(e);
1425             emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
1426         }
1427         assert(ue.exp().type);
1428         return ue;
1429     }
1430 
1431     if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
1432     {
1433         return catNull(e2, t1);
1434     }
1435     else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
1436     {
1437         return catNull(e1, t2);
1438     }
1439     else if (e1.op == EXP.null_ && e2.op == EXP.null_)
1440     {
1441         if (type == e1.type)
1442         {
1443             // Handle null ~= null
1444             if (t1.ty == Tarray && t2 == t1.nextOf())
1445             {
1446                 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2);
1447                 assert(ue.exp().type);
1448                 return ue;
1449             }
1450             else
1451             {
1452                 emplaceExp!(UnionExp)(&ue, e1);
1453                 assert(ue.exp().type);
1454                 return ue;
1455             }
1456         }
1457         if (type == e2.type)
1458         {
1459             emplaceExp!(UnionExp)(&ue, e2);
1460             assert(ue.exp().type);
1461             return ue;
1462         }
1463         emplaceExp!(NullExp)(&ue, e1.loc, type);
1464         assert(ue.exp().type);
1465         return ue;
1466     }
1467     else if (e1.op == EXP.string_ && e2.op == EXP.string_)
1468     {
1469         // Concatenate the strings
1470         StringExp es1 = e1.isStringExp();
1471         StringExp es2 = e2.isStringExp();
1472         size_t len = es1.len + es2.len;
1473         ubyte sz = es1.sz;
1474         if (sz != es2.sz)
1475         {
1476             /* Can happen with:
1477              *   auto s = "foo"d ~ "bar"c;
1478              */
1479             assert(global.errors);
1480             cantExp(ue);
1481             assert(ue.exp().type);
1482             return ue;
1483         }
1484         void* s = mem.xmalloc(len * sz);
1485         const data1 = es1.peekData();
1486         const data2 = es2.peekData();
1487         memcpy(cast(char*)s, data1.ptr, es1.len * sz);
1488         memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
1489         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1490         StringExp es = ue.exp().isStringExp();
1491         es.committed = es1.committed | es2.committed;
1492         es.type = type;
1493         assert(ue.exp().type);
1494         return ue;
1495     }
1496     else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
1497     {
1498         // [chars] ~ string --> [chars]
1499         StringExp es = e2.isStringExp();
1500         ArrayLiteralExp ea = e1.isArrayLiteralExp();
1501         size_t len = es.len + ea.elements.length;
1502         auto elems = new Expressions(len);
1503         for (size_t i = 0; i < ea.elements.length; ++i)
1504         {
1505             (*elems)[i] = ea[i];
1506         }
1507         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1508         ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1509         sliceAssignArrayLiteralFromString(dest, es, ea.elements.length);
1510         assert(ue.exp().type);
1511         return ue;
1512     }
1513     else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
1514     {
1515         // string ~ [chars] --> [chars]
1516         StringExp es = e1.isStringExp();
1517         ArrayLiteralExp ea = e2.isArrayLiteralExp();
1518         size_t len = es.len + ea.elements.length;
1519         auto elems = new Expressions(len);
1520         for (size_t i = 0; i < ea.elements.length; ++i)
1521         {
1522             (*elems)[es.len + i] = ea[i];
1523         }
1524         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1525         ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1526         sliceAssignArrayLiteralFromString(dest, es, 0);
1527         assert(ue.exp().type);
1528         return ue;
1529     }
1530     else if (e1.op == EXP.string_ && e2.op == EXP.int64)
1531     {
1532         // string ~ char --> string
1533         StringExp es1 = e1.isStringExp();
1534         StringExp es;
1535         const sz = es1.sz;
1536         dinteger_t v = e2.toInteger();
1537         // Is it a concatenation of homogenous types?
1538         // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1539         bool homoConcat = (sz == t2.size());
1540         const len = es1.len + (homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v));
1541         void* s = mem.xmalloc(len * sz);
1542         const data1 = es1.peekData();
1543         memcpy(s, data1.ptr, data1.length);
1544         if (homoConcat)
1545             Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
1546         else
1547             utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
1548         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1549         es = ue.exp().isStringExp();
1550         es.committed = es1.committed;
1551         es.type = type;
1552         assert(ue.exp().type);
1553         return ue;
1554     }
1555     else if (e1.op == EXP.int64 && e2.op == EXP.string_)
1556     {
1557         // [w|d]?char ~ string --> string
1558         // We assume that we only ever prepend one char of the same type
1559         // (wchar,dchar) as the string's characters.
1560         StringExp es2 = e2.isStringExp();
1561         const len = 1 + es2.len;
1562         const sz = es2.sz;
1563         dinteger_t v = e1.toInteger();
1564         void* s = mem.xmalloc(len * sz);
1565         Port.valcpy(cast(char*)s, v, sz);
1566         const data2 = es2.peekData();
1567         memcpy(cast(char*)s + sz, data2.ptr, data2.length);
1568         emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1569         StringExp es = ue.exp().isStringExp();
1570         es.sz = sz;
1571         es.committed = es2.committed;
1572         es.type = type;
1573         assert(ue.exp().type);
1574         return ue;
1575     }
1576     else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1577     {
1578         // Concatenate the arrays
1579         auto elems = copyElements(e1, e2);
1580 
1581         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
1582 
1583         e = ue.exp();
1584         if (type.toBasetype().ty == Tsarray)
1585         {
1586             e.type = t1.nextOf().sarrayOf(elems.length);
1587         }
1588         else
1589             e.type = type;
1590         assert(ue.exp().type);
1591         return ue;
1592     }
1593     else if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
1594     {
1595         e = e1;
1596         goto L3;
1597     }
1598     else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1599     {
1600         e = e2;
1601     L3:
1602         // Concatenate the array with null
1603         auto elems = copyElements(e);
1604 
1605         emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems);
1606 
1607         e = ue.exp();
1608         if (type.toBasetype().ty == Tsarray)
1609         {
1610             e.type = t1.nextOf().sarrayOf(elems.length);
1611         }
1612         else
1613             e.type = type;
1614         assert(ue.exp().type);
1615         return ue;
1616     }
1617     else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
1618     {
1619         auto elems = (e1.op == EXP.arrayLiteral)
1620                 ? copyElements(e1) : new Expressions();
1621         elems.push(e2);
1622 
1623         emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1624 
1625         e = ue.exp();
1626         if (type.toBasetype().ty == Tsarray)
1627         {
1628             e.type = e2.type.sarrayOf(elems.length);
1629         }
1630         else
1631             e.type = type;
1632         assert(ue.exp().type);
1633         return ue;
1634     }
1635     else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
1636     {
1637         auto elems = copyElements(e1, e2);
1638 
1639         emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1640 
1641         e = ue.exp();
1642         if (type.toBasetype().ty == Tsarray)
1643         {
1644             e.type = e1.type.sarrayOf(elems.length);
1645         }
1646         else
1647             e.type = type;
1648         assert(ue.exp().type);
1649         return ue;
1650     }
1651     else if (e1.op == EXP.null_ && e2.op == EXP.string_)
1652     {
1653         t = e1.type;
1654         e = e2;
1655         goto L1;
1656     }
1657     else if (e1.op == EXP.string_ && e2.op == EXP.null_)
1658     {
1659         e = e1;
1660         t = e2.type;
1661     L1:
1662         Type tb = t.toBasetype();
1663         if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
1664         {
1665             auto expressions = new Expressions();
1666             expressions.push(e);
1667             emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
1668             e = ue.exp();
1669         }
1670         else
1671         {
1672             emplaceExp!(UnionExp)(&ue, e);
1673             e = ue.exp();
1674         }
1675         if (!e.type.equals(type))
1676         {
1677             StringExp se = e.copy().isStringExp();
1678             e = se.castTo(null, type);
1679             emplaceExp!(UnionExp)(&ue, e);
1680             e = ue.exp();
1681         }
1682     }
1683     else
1684         cantExp(ue);
1685     assert(ue.exp().type);
1686     return ue;
1687 }
1688 
1689 UnionExp Ptr(Type type, Expression e1)
1690 {
1691     //printf("Ptr(e1 = %s)\n", e1.toChars());
1692     UnionExp ue = void;
1693     if (AddExp ae = e1.isAddExp())
1694     {
1695         if (AddrExp ade = ae.e1.isAddrExp())
1696         {
1697             if (ae.e2.op == EXP.int64)
1698                 if (StructLiteralExp se = ade.e1.isStructLiteralExp())
1699                 {
1700                     uint offset = cast(uint)ae.e2.toInteger();
1701                     Expression e = se.getField(type, offset);
1702                     if (e)
1703                     {
1704                         emplaceExp!(UnionExp)(&ue, e);
1705                         return ue;
1706                     }
1707                 }
1708         }
1709     }
1710     cantExp(ue);
1711     return ue;
1712 }