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-2020 by The D Language Foundation, All Rights Reserved
9
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
10
 * License:     $(LINK2 http://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.complex;
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.mtype;
29
import dmd.root.ctfloat;
30
import dmd.root.port;
31
import dmd.root.rmem;
32
import dmd.sideeffect;
33
import dmd.target;
34
import dmd.tokens;
35
import dmd.utf;
36

37
private enum LOG = false;
38

39
private Expression expType(Type type, Expression e)
40
{
41 1
    if (type != e.type)
42
    {
43 1
        e = e.copy();
44 1
        e.type = type;
45
    }
46 1
    return e;
47
}
48

49
/************************************
50
 * Returns:
51
 *    true if e is a constant
52
 */
53
int isConst(Expression e)
54
{
55
    //printf("Expression::isConst(): %s\n", e.toChars());
56 1
    switch (e.op)
57
    {
58 1
    case TOK.int64:
59 1
    case TOK.float64:
60 1
    case TOK.complex80:
61 1
        return 1;
62 1
    case TOK.null_:
63 1
        return 0;
64 1
    case TOK.symbolOffset:
65 1
        return 2;
66 1
    default:
67 1
        return 0;
68
    }
69 0
    assert(0);
70
}
71

72
/**********************************
73
 * Initialize a TOK.cantExpression Expression.
74
 * Params:
75
 *      ue = where to write it
76
 */
77
void cantExp(out UnionExp ue)
78
{
79 1
    emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
80
}
81

82
/* =============================== constFold() ============================== */
83
/* The constFold() functions were redundant with the optimize() ones,
84
 * and so have been folded in with them.
85
 */
86
/* ========================================================================== */
87
UnionExp Neg(Type type, Expression e1)
88
{
89 1
    UnionExp ue = void;
90 1
    Loc loc = e1.loc;
91 1
    if (e1.type.isreal())
92
    {
93 1
        emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
94
    }
95 1
    else if (e1.type.isimaginary())
96
    {
97 1
        emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
98
    }
99 1
    else if (e1.type.iscomplex())
100
    {
101 1
        emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
102
    }
103
    else
104
    {
105 1
        emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
106
    }
107 1
    return ue;
108
}
109

110
UnionExp Com(Type type, Expression e1)
111
{
112 1
    UnionExp ue = void;
113 1
    Loc loc = e1.loc;
114 1
    emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
115 1
    return ue;
116
}
117

118
UnionExp Not(Type type, Expression e1)
119
{
120 1
    UnionExp ue = void;
121 1
    Loc loc = e1.loc;
122 1
    emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type);
123 1
    return ue;
124
}
125

126
private UnionExp Bool(Type type, Expression e1)
127
{
128 0
    UnionExp ue = void;
129 0
    Loc loc = e1.loc;
130 0
    emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type);
131 0
    return ue;
132
}
133

134
UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
135
{
136 1
    UnionExp ue = void;
137
    static if (LOG)
138
    {
139
        printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
140
    }
141 1
    if (type.isreal())
142
    {
143 1
        emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
144
    }
145 1
    else if (type.isimaginary())
146
    {
147 1
        emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
148
    }
149 1
    else if (type.iscomplex())
150
    {
151
        // This rigamarole is necessary so that -0.0 doesn't get
152
        // converted to +0.0 by doing an extraneous add with +0.0
153 1
        auto c1 = complex_t(CTFloat.zero);
154 1
        real_t r1 = CTFloat.zero;
155 1
        real_t i1 = CTFloat.zero;
156 1
        auto c2 = complex_t(CTFloat.zero);
157 1
        real_t r2 = CTFloat.zero;
158 1
        real_t i2 = CTFloat.zero;
159 1
        auto v = complex_t(CTFloat.zero);
160 1
        int x;
161 1
        if (e1.type.isreal())
162
        {
163 1
            r1 = e1.toReal();
164 1
            x = 0;
165
        }
166 1
        else if (e1.type.isimaginary())
167
        {
168 1
            i1 = e1.toImaginary();
169 1
            x = 3;
170
        }
171
        else
172
        {
173 0
            c1 = e1.toComplex();
174 0
            x = 6;
175
        }
176 1
        if (e2.type.isreal())
177
        {
178 1
            r2 = e2.toReal();
179
        }
180 1
        else if (e2.type.isimaginary())
181
        {
182 1
            i2 = e2.toImaginary();
183 1
            x += 1;
184
        }
185
        else
186
        {
187 0
            c2 = e2.toComplex();
188 0
            x += 2;
189
        }
190 1
        switch (x)
191
        {
192 0
        case 0 + 0:
193 0
            v = complex_t(r1 + r2);
194 0
            break;
195 1
        case 0 + 1:
196 1
            v = complex_t(r1, i2);
197 1
            break;
198 0
        case 0 + 2:
199 0
            v = complex_t(r1 + creall(c2), cimagl(c2));
200 0
            break;
201 1
        case 3 + 0:
202 1
            v = complex_t(r2, i1);
203 1
            break;
204 0
        case 3 + 1:
205 0
            v = complex_t(CTFloat.zero, i1 + i2);
206 0
            break;
207 0
        case 3 + 2:
208 0
            v = complex_t(creall(c2), i1 + cimagl(c2));
209 0
            break;
210 0
        case 6 + 0:
211 0
            v = complex_t(creall(c1) + r2, cimagl(c2));
212 0
            break;
213 0
        case 6 + 1:
214 0
            v = complex_t(creall(c1), cimagl(c1) + i2);
215 0
            break;
216 0
        case 6 + 2:
217 0
            v = c1 + c2;
218 0
            break;
219 0
        default:
220 0
            assert(0);
221
        }
222 1
        emplaceExp!(ComplexExp)(&ue, loc, v, type);
223
    }
224 1
    else if (e1.op == TOK.symbolOffset)
225
    {
226 1
        SymOffExp soe = cast(SymOffExp)e1;
227 1
        emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
228 1
        ue.exp().type = type;
229
    }
230 1
    else if (e2.op == TOK.symbolOffset)
231
    {
232 0
        SymOffExp soe = cast(SymOffExp)e2;
233 0
        emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
234 0
        ue.exp().type = type;
235
    }
236
    else
237 1
        emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
238 1
    return ue;
239
}
240

241
UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
242
{
243 1
    UnionExp ue = void;
244 1
    if (type.isreal())
245
    {
246 1
        emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type);
247
    }
248 1
    else if (type.isimaginary())
249
    {
250 1
        emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type);
251
    }
252 1
    else if (type.iscomplex())
253
    {
254
        // This rigamarole is necessary so that -0.0 doesn't get
255
        // converted to +0.0 by doing an extraneous add with +0.0
256 1
        auto c1 = complex_t(CTFloat.zero);
257 1
        real_t r1 = CTFloat.zero;
258 1
        real_t i1 = CTFloat.zero;
259 1
        auto c2 = complex_t(CTFloat.zero);
260 1
        real_t r2 = CTFloat.zero;
261 1
        real_t i2 = CTFloat.zero;
262 1
        auto v = complex_t(CTFloat.zero);
263 1
        int x;
264 1
        if (e1.type.isreal())
265
        {
266 1
            r1 = e1.toReal();
267 1
            x = 0;
268
        }
269 1
        else if (e1.type.isimaginary())
270
        {
271 1
            i1 = e1.toImaginary();
272 1
            x = 3;
273
        }
274
        else
275
        {
276 0
            c1 = e1.toComplex();
277 0
            x = 6;
278
        }
279 1
        if (e2.type.isreal())
280
        {
281 1
            r2 = e2.toReal();
282
        }
283 1
        else if (e2.type.isimaginary())
284
        {
285 1
            i2 = e2.toImaginary();
286 1
            x += 1;
287
        }
288
        else
289
        {
290 0
            c2 = e2.toComplex();
291 0
            x += 2;
292
        }
293 1
        switch (x)
294
        {
295 0
        case 0 + 0:
296 0
            v = complex_t(r1 - r2);
297 0
            break;
298 1
        case 0 + 1:
299 1
            v = complex_t(r1, -i2);
300 1
            break;
301 0
        case 0 + 2:
302 0
            v = complex_t(r1 - creall(c2), -cimagl(c2));
303 0
            break;
304 1
        case 3 + 0:
305 1
            v = complex_t(-r2, i1);
306 1
            break;
307 0
        case 3 + 1:
308 0
            v = complex_t(CTFloat.zero, i1 - i2);
309 0
            break;
310 0
        case 3 + 2:
311 0
            v = complex_t(-creall(c2), i1 - cimagl(c2));
312 0
            break;
313 0
        case 6 + 0:
314 0
            v = complex_t(creall(c1) - r2, cimagl(c1));
315 0
            break;
316 0
        case 6 + 1:
317 0
            v = complex_t(creall(c1), cimagl(c1) - i2);
318 0
            break;
319 0
        case 6 + 2:
320 0
            v = c1 - c2;
321 0
            break;
322 0
        default:
323 0
            assert(0);
324
        }
325 1
        emplaceExp!(ComplexExp)(&ue, loc, v, type);
326
    }
327 1
    else if (e1.op == TOK.symbolOffset)
328
    {
329 1
        SymOffExp soe = cast(SymOffExp)e1;
330 1
        emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
331 1
        ue.exp().type = type;
332
    }
333
    else
334
    {
335 1
        emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type);
336
    }
337 1
    return ue;
338
}
339

340
UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
341
{
342 1
    UnionExp ue = void;
343 1
    if (type.isfloating())
344
    {
345 1
        auto c = complex_t(CTFloat.zero);
346 1
        real_t r = CTFloat.zero;
347 1
        if (e1.type.isreal())
348
        {
349 1
            r = e1.toReal();
350 1
            c = e2.toComplex();
351 1
            c = complex_t(r * creall(c), r * cimagl(c));
352
        }
353 1
        else if (e1.type.isimaginary())
354
        {
355 1
            r = e1.toImaginary();
356 1
            c = e2.toComplex();
357 1
            c = complex_t(-r * cimagl(c), r * creall(c));
358
        }
359 1
        else if (e2.type.isreal())
360
        {
361 1
            r = e2.toReal();
362 1
            c = e1.toComplex();
363 1
            c = complex_t(r * creall(c), r * cimagl(c));
364
        }
365 1
        else if (e2.type.isimaginary())
366
        {
367 1
            r = e2.toImaginary();
368 1
            c = e1.toComplex();
369 1
            c = complex_t(-r * cimagl(c), r * creall(c));
370
        }
371
        else
372 1
            c = e1.toComplex() * e2.toComplex();
373 1
        if (type.isreal())
374 1
            emplaceExp!(RealExp)(&ue, loc, creall(c), type);
375 1
        else if (type.isimaginary())
376 1
            emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
377 1
        else if (type.iscomplex())
378 1
            emplaceExp!(ComplexExp)(&ue, loc, c, type);
379
        else
380 0
            assert(0);
381
    }
382
    else
383
    {
384 1
        emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
385
    }
386 1
    return ue;
387
}
388

389
UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
390
{
391 1
    UnionExp ue = void;
392 1
    if (type.isfloating())
393
    {
394 1
        auto c = complex_t(CTFloat.zero);
395 1
        if (e2.type.isreal())
396
        {
397 1
            if (e1.type.isreal())
398
            {
399 1
                emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
400 1
                return ue;
401
            }
402 1
            const r = e2.toReal();
403 1
            c = e1.toComplex();
404 1
            c = complex_t(creall(c) / r, cimagl(c) / r);
405
        }
406 1
        else if (e2.type.isimaginary())
407
        {
408 1
            const r = e2.toImaginary();
409 1
            c = e1.toComplex();
410 1
            c = complex_t(cimagl(c) / r, -creall(c) / r);
411
        }
412
        else
413
        {
414 1
            c = e1.toComplex() / e2.toComplex();
415
        }
416

417 1
        if (type.isreal())
418 1
            emplaceExp!(RealExp)(&ue, loc, creall(c), type);
419 1
        else if (type.isimaginary())
420 1
            emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
421 1
        else if (type.iscomplex())
422 1
            emplaceExp!(ComplexExp)(&ue, loc, c, type);
423
        else
424 0
            assert(0);
425
    }
426
    else
427
    {
428 1
        sinteger_t n1;
429 1
        sinteger_t n2;
430 1
        sinteger_t n;
431 1
        n1 = e1.toInteger();
432 1
        n2 = e2.toInteger();
433 1
        if (n2 == 0)
434
        {
435 1
            e2.error("divide by 0");
436 1
            emplaceExp!(ErrorExp)(&ue);
437 1
            return ue;
438
        }
439 1
        if (n2 == -1 && !type.isunsigned())
440
        {
441
            // Check for int.min / -1
442 1
            if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
443
            {
444 1
                e2.error("integer overflow: `int.min / -1`");
445 1
                emplaceExp!(ErrorExp)(&ue);
446 1
                return ue;
447
            }
448 1
            else if (n1 == 0x8000000000000000L) // long.min / -1
449
            {
450 1
                e2.error("integer overflow: `long.min / -1L`");
451 1
                emplaceExp!(ErrorExp)(&ue);
452 1
                return ue;
453
            }
454
        }
455 1
        if (e1.type.isunsigned() || e2.type.isunsigned())
456 1
            n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
457
        else
458 1
            n = n1 / n2;
459 1
        emplaceExp!(IntegerExp)(&ue, loc, n, type);
460
    }
461 1
    return ue;
462
}
463

464
UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
465
{
466 1
    UnionExp ue = void;
467 1
    if (type.isfloating())
468
    {
469 1
        auto c = complex_t(CTFloat.zero);
470 1
        if (e2.type.isreal())
471
        {
472 1
            const r2 = e2.toReal();
473 1
            c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
474
        }
475 1
        else if (e2.type.isimaginary())
476
        {
477 1
            const i2 = e2.toImaginary();
478 1
            c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
479
        }
480
        else
481 0
            assert(0);
482 1
        if (type.isreal())
483 1
            emplaceExp!(RealExp)(&ue, loc, creall(c), type);
484 1
        else if (type.isimaginary())
485 1
            emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
486 1
        else if (type.iscomplex())
487 1
            emplaceExp!(ComplexExp)(&ue, loc, c, type);
488
        else
489 0
            assert(0);
490
    }
491
    else
492
    {
493 1
        sinteger_t n1;
494 1
        sinteger_t n2;
495 1
        sinteger_t n;
496 1
        n1 = e1.toInteger();
497 1
        n2 = e2.toInteger();
498 1
        if (n2 == 0)
499
        {
500 1
            e2.error("divide by 0");
501 1
            emplaceExp!(ErrorExp)(&ue);
502 1
            return ue;
503
        }
504 1
        if (n2 == -1 && !type.isunsigned())
505
        {
506
            // Check for int.min % -1
507 1
            if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
508
            {
509 1
                e2.error("integer overflow: `int.min %% -1`");
510 1
                emplaceExp!(ErrorExp)(&ue);
511 1
                return ue;
512
            }
513 1
            else if (n1 == 0x8000000000000000L) // long.min % -1
514
            {
515 1
                e2.error("integer overflow: `long.min %% -1L`");
516 1
                emplaceExp!(ErrorExp)(&ue);
517 1
                return ue;
518
            }
519
        }
520 1
        if (e1.type.isunsigned() || e2.type.isunsigned())
521 1
            n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
522
        else
523 1
            n = n1 % n2;
524 1
        emplaceExp!(IntegerExp)(&ue, loc, n, type);
525
    }
526 1
    return ue;
527
}
528

529
UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
530
{
531
    //printf("Pow()\n");
532 1
    UnionExp ue;
533
    // Handle integer power operations.
534 1
    if (e2.type.isintegral())
535
    {
536 1
        dinteger_t n = e2.toInteger();
537 1
        bool neg;
538 1
        if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
539
        {
540 1
            if (e1.type.isintegral())
541
            {
542 0
                cantExp(ue);
543 0
                return ue;
544
            }
545
            // Don't worry about overflow, from now on n is unsigned.
546 1
            neg = true;
547 1
            n = -n;
548
        }
549
        else
550 1
            neg = false;
551 1
        UnionExp ur, uv;
552 1
        if (e1.type.iscomplex())
553
        {
554 1
            emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
555 1
            emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
556
        }
557 1
        else if (e1.type.isfloating())
558
        {
559 1
            emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
560 1
            emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
561
        }
562
        else
563
        {
564 1
            emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
565 1
            emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
566
        }
567 1
        Expression r = ur.exp();
568 1
        Expression v = uv.exp();
569 1
        while (n != 0)
570
        {
571 1
            if (n & 1)
572
            {
573
                // v = v * r;
574 1
                uv = Mul(loc, v.type, v, r);
575
            }
576 1
            n >>= 1;
577
            // r = r * r
578 1
            ur = Mul(loc, r.type, r, r);
579
        }
580 1
        if (neg)
581
        {
582
            // ue = 1.0 / v
583 1
            UnionExp one;
584 1
            emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
585 1
            uv = Div(loc, v.type, one.exp(), v);
586
        }
587 1
        if (type.iscomplex())
588 1
            emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
589 1
        else if (type.isintegral())
590 1
            emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
591
        else
592 1
            emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
593
    }
594 1
    else if (e2.type.isfloating())
595
    {
596
        // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
597 1
        if (e1.toReal() < CTFloat.zero)
598
        {
599 1
            emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
600
        }
601
        else
602 1
            cantExp(ue);
603
    }
604
    else
605 0
        cantExp(ue);
606 1
    return ue;
607
}
608

609
UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
610
{
611 1
    UnionExp ue = void;
612 1
    emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
613 1
    return ue;
614
}
615

616
UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
617
{
618 1
    UnionExp ue = void;
619 1
    dinteger_t value = e1.toInteger();
620 1
    dinteger_t dcount = e2.toInteger();
621 1
    assert(dcount <= 0xFFFFFFFF);
622 1
    uint count = cast(uint)dcount;
623 1
    switch (e1.type.toBasetype().ty)
624
    {
625 0
    case Tint8:
626 0
        value = cast(d_int8)value >> count;
627 0
        break;
628 1
    case Tuns8:
629 1
    case Tchar:
630 1
        value = cast(d_uns8)value >> count;
631 1
        break;
632 0
    case Tint16:
633 0
        value = cast(d_int16)value >> count;
634 0
        break;
635 0
    case Tuns16:
636 1
    case Twchar:
637 1
        value = cast(d_uns16)value >> count;
638 1
        break;
639 1
    case Tint32:
640 1
        value = cast(d_int32)value >> count;
641 1
        break;
642 1
    case Tuns32:
643 1
    case Tdchar:
644 1
        value = cast(d_uns32)value >> count;
645 1
        break;
646 1
    case Tint64:
647 1
        value = cast(d_int64)value >> count;
648 1
        break;
649 1
    case Tuns64:
650 1
        value = cast(d_uns64)value >> count;
651 1
        break;
652 0
    case Terror:
653 0
        emplaceExp!(ErrorExp)(&ue);
654 0
        return ue;
655 0
    default:
656 0
        assert(0);
657
    }
658 1
    emplaceExp!(IntegerExp)(&ue, loc, value, type);
659 1
    return ue;
660
}
661

662
UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
663
{
664 1
    UnionExp ue = void;
665 1
    dinteger_t value = e1.toInteger();
666 1
    dinteger_t dcount = e2.toInteger();
667 1
    assert(dcount <= 0xFFFFFFFF);
668 1
    uint count = cast(uint)dcount;
669 1
    switch (e1.type.toBasetype().ty)
670
    {
671 1
    case Tint8:
672 1
    case Tuns8:
673 1
    case Tchar:
674
        // Possible only with >>>=. >>> always gets promoted to int.
675 1
        value = (value & 0xFF) >> count;
676 1
        break;
677 0
    case Tint16:
678 1
    case Tuns16:
679 1
    case Twchar:
680
        // Possible only with >>>=. >>> always gets promoted to int.
681 1
        value = (value & 0xFFFF) >> count;
682 1
        break;
683 1
    case Tint32:
684 1
    case Tuns32:
685 1
    case Tdchar:
686 1
        value = (value & 0xFFFFFFFF) >> count;
687 1
        break;
688 1
    case Tint64:
689 1
    case Tuns64:
690 1
        value = cast(d_uns64)value >> count;
691 1
        break;
692 0
    case Terror:
693 0
        emplaceExp!(ErrorExp)(&ue);
694 0
        return ue;
695 0
    default:
696 0
        assert(0);
697
    }
698 1
    emplaceExp!(IntegerExp)(&ue, loc, value, type);
699 1
    return ue;
700
}
701

702
UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
703
{
704 1
    UnionExp ue = void;
705 1
    emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
706 1
    return ue;
707
}
708

709
UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
710
{
711 1
    UnionExp ue = void;
712 1
    emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
713 1
    return ue;
714
}
715

716
UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
717
{
718
    //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
719 1
    UnionExp ue = void;
720 1
    emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
721 1
    return ue;
722
}
723

724
/* Also returns TOK.cantExpression if cannot be computed.
725
 */
726
UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
727
{
728 1
    UnionExp ue = void;
729 1
    int cmp = 0;
730 1
    real_t r1 = CTFloat.zero;
731 1
    real_t r2 = CTFloat.zero;
732
    //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
733 1
    assert(op == TOK.equal || op == TOK.notEqual);
734 1
    if (e1.op == TOK.null_)
735
    {
736 1
        if (e2.op == TOK.null_)
737 1
            cmp = 1;
738 1
        else if (e2.op == TOK.string_)
739
        {
740 0
            StringExp es2 = cast(StringExp)e2;
741 0
            cmp = (0 == es2.len);
742
        }
743 1
        else if (e2.op == TOK.arrayLiteral)
744
        {
745 0
            ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
746 0
            cmp = !es2.elements || (0 == es2.elements.dim);
747
        }
748
        else
749
        {
750 1
            cantExp(ue);
751 1
            return ue;
752
        }
753
    }
754 1
    else if (e2.op == TOK.null_)
755
    {
756 1
        if (e1.op == TOK.string_)
757
        {
758 0
            StringExp es1 = cast(StringExp)e1;
759 0
            cmp = (0 == es1.len);
760
        }
761 1
        else if (e1.op == TOK.arrayLiteral)
762
        {
763 0
            ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
764 0
            cmp = !es1.elements || (0 == es1.elements.dim);
765
        }
766
        else
767
        {
768 1
            cantExp(ue);
769 1
            return ue;
770
        }
771
    }
772 1
    else if (e1.op == TOK.string_ && e2.op == TOK.string_)
773
    {
774 0
        StringExp es1 = cast(StringExp)e1;
775 0
        StringExp es2 = cast(StringExp)e2;
776 0
        if (es1.sz != es2.sz)
777
        {
778 0
            assert(global.errors);
779 0
            cantExp(ue);
780 0
            return ue;
781
        }
782 0
        const data1 = es1.peekData();
783 0
        const data2 = es2.peekData();
784 0
        if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
785 0
            cmp = 1;
786
        else
787 0
            cmp = 0;
788
    }
789 1
    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral)
790
    {
791 1
        ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
792 1
        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
793 1
        if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
794 1
            cmp = 1; // both arrays are empty
795 1
        else if (!es1.elements || !es2.elements)
796 0
            cmp = 0;
797 1
        else if (es1.elements.dim != es2.elements.dim)
798 0
            cmp = 0;
799
        else
800
        {
801 1
            for (size_t i = 0; i < es1.elements.dim; i++)
802
            {
803 1
                auto ee1 = es1[i];
804 1
                auto ee2 = es2[i];
805 1
                ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
806 1
                if (CTFEExp.isCantExp(ue.exp()))
807 0
                    return ue;
808 1
                cmp = cast(int)ue.exp().toInteger();
809 1
                if (cmp == 0)
810 1
                    break;
811
            }
812
        }
813
    }
814 1
    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_)
815
    {
816
        // Swap operands and use common code
817 1
        Expression etmp = e1;
818 1
        e1 = e2;
819 1
        e2 = etmp;
820 1
        goto Lsa;
821
    }
822 1
    else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral)
823
    {
824
    Lsa:
825 1
        StringExp es1 = cast(StringExp)e1;
826 1
        ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
827 1
        size_t dim1 = es1.len;
828 1
        size_t dim2 = es2.elements ? es2.elements.dim : 0;
829 1
        if (dim1 != dim2)
830 0
            cmp = 0;
831
        else
832
        {
833 1
            cmp = 1; // if dim1 winds up being 0
834 1
            for (size_t i = 0; i < dim1; i++)
835
            {
836 1
                uinteger_t c = es1.charAt(i);
837 1
                auto ee2 = es2[i];
838 1
                if (ee2.isConst() != 1)
839
                {
840 0
                    cantExp(ue);
841 0
                    return ue;
842
                }
843 1
                cmp = (c == ee2.toInteger());
844 1
                if (cmp == 0)
845 0
                    break;
846
            }
847
        }
848
    }
849 1
    else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
850
    {
851 0
        StructLiteralExp es1 = cast(StructLiteralExp)e1;
852 0
        StructLiteralExp es2 = cast(StructLiteralExp)e2;
853 0
        if (es1.sd != es2.sd)
854 0
            cmp = 0;
855 0
        else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
856 0
            cmp = 1; // both arrays are empty
857 0
        else if (!es1.elements || !es2.elements)
858 0
            cmp = 0;
859 0
        else if (es1.elements.dim != es2.elements.dim)
860 0
            cmp = 0;
861
        else
862
        {
863 0
            cmp = 1;
864 0
            for (size_t i = 0; i < es1.elements.dim; i++)
865
            {
866 0
                Expression ee1 = (*es1.elements)[i];
867 0
                Expression ee2 = (*es2.elements)[i];
868 0
                if (ee1 == ee2)
869 0
                    continue;
870 0
                if (!ee1 || !ee2)
871
                {
872 0
                    cmp = 0;
873 0
                    break;
874
                }
875 0
                ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
876 0
                if (ue.exp().op == TOK.cantExpression)
877 0
                    return ue;
878 0
                cmp = cast(int)ue.exp().toInteger();
879 0
                if (cmp == 0)
880 0
                    break;
881
            }
882
        }
883
    }
884 1
    else if (e1.isConst() != 1 || e2.isConst() != 1)
885
    {
886 1
        cantExp(ue);
887 1
        return ue;
888
    }
889 1
    else if (e1.type.isreal())
890
    {
891 1
        r1 = e1.toReal();
892 1
        r2 = e2.toReal();
893 1
        goto L1;
894
    }
895 1
    else if (e1.type.isimaginary())
896
    {
897 1
        r1 = e1.toImaginary();
898 1
        r2 = e2.toImaginary();
899
    L1:
900 1
        if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
901
        {
902 1
            cmp = 0;
903
        }
904
        else
905
        {
906 1
            cmp = (r1 == r2);
907
        }
908
    }
909 1
    else if (e1.type.iscomplex())
910
    {
911 1
        cmp = e1.toComplex() == e2.toComplex();
912
    }
913 1
    else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
914
    {
915 1
        cmp = (e1.toInteger() == e2.toInteger());
916
    }
917
    else
918
    {
919 0
        cantExp(ue);
920 0
        return ue;
921
    }
922 1
    if (op == TOK.notEqual)
923 1
        cmp ^= 1;
924 1
    emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
925 1
    return ue;
926
}
927

928
UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
929
{
930 1
    UnionExp ue = void;
931 1
    int cmp;
932 1
    if (e1.op == TOK.null_)
933
    {
934 1
        cmp = (e2.op == TOK.null_);
935
    }
936 1
    else if (e2.op == TOK.null_)
937
    {
938 0
        cmp = 0;
939
    }
940 1
    else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
941
    {
942 1
        SymOffExp es1 = cast(SymOffExp)e1;
943 1
        SymOffExp es2 = cast(SymOffExp)e2;
944 1
        cmp = (es1.var == es2.var && es1.offset == es2.offset);
945
    }
946
    else
947
    {
948 1
        if (e1.type.isreal())
949
        {
950 1
            cmp = RealIdentical(e1.toReal(), e2.toReal());
951
        }
952 1
        else if (e1.type.isimaginary())
953
        {
954 1
            cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
955
        }
956 1
        else if (e1.type.iscomplex())
957
        {
958 1
            complex_t v1 = e1.toComplex();
959 1
            complex_t v2 = e2.toComplex();
960 1
            cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1));
961
        }
962
        else
963
        {
964 1
            ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2);
965 1
            return ue;
966
        }
967
    }
968 1
    if (op == TOK.notIdentity)
969 1
        cmp ^= 1;
970 1
    emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
971 1
    return ue;
972
}
973

974
UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
975
{
976 1
    UnionExp ue = void;
977 1
    dinteger_t n;
978 1
    real_t r1 = CTFloat.zero;
979 1
    real_t r2 = CTFloat.zero;
980
    //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
981 1
    if (e1.op == TOK.string_ && e2.op == TOK.string_)
982
    {
983 0
        StringExp es1 = cast(StringExp)e1;
984 0
        StringExp es2 = cast(StringExp)e2;
985 0
        size_t sz = es1.sz;
986 0
        assert(sz == es2.sz);
987 0
        size_t len = es1.len;
988 0
        if (es2.len < len)
989 0
            len = es2.len;
990 0
        const data1 = es1.peekData();
991 0
        const data2 = es1.peekData();
992 0
        int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
993 0
        if (rawCmp == 0)
994 0
            rawCmp = cast(int)(es1.len - es2.len);
995 0
        n = specificCmp(op, rawCmp);
996
    }
997 1
    else if (e1.isConst() != 1 || e2.isConst() != 1)
998
    {
999 1
        cantExp(ue);
1000 1
        return ue;
1001
    }
1002 1
    else if (e1.type.isreal())
1003
    {
1004 1
        r1 = e1.toReal();
1005 1
        r2 = e2.toReal();
1006 1
        goto L1;
1007
    }
1008 1
    else if (e1.type.isimaginary())
1009
    {
1010 1
        r1 = e1.toImaginary();
1011 1
        r2 = e2.toImaginary();
1012
    L1:
1013 1
        n = realCmp(op, r1, r2);
1014
    }
1015 1
    else if (e1.type.iscomplex())
1016
    {
1017 0
        assert(0);
1018
    }
1019
    else
1020
    {
1021 1
        sinteger_t n1;
1022 1
        sinteger_t n2;
1023 1
        n1 = e1.toInteger();
1024 1
        n2 = e2.toInteger();
1025 1
        if (e1.type.isunsigned() || e2.type.isunsigned())
1026 1
            n = intUnsignedCmp(op, n1, n2);
1027
        else
1028 1
            n = intSignedCmp(op, n1, n2);
1029
    }
1030 1
    emplaceExp!(IntegerExp)(&ue, loc, n, type);
1031 1
    return ue;
1032
}
1033

1034
/* Also returns TOK.cantExpression if cannot be computed.
1035
 *  to: type to cast to
1036
 *  type: type to paint the result
1037
 */
1038
UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
1039
{
1040 1
    UnionExp ue = void;
1041 1
    Type tb = to.toBasetype();
1042 1
    Type typeb = type.toBasetype();
1043
    //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
1044
    //printf("\te1.type = %s\n", e1.type.toChars());
1045 1
    if (e1.type.equals(type) && type.equals(to))
1046
    {
1047 0
        emplaceExp!(UnionExp)(&ue, e1);
1048 0
        return ue;
1049
    }
1050 1
    if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
1051
    {
1052 0
        Expression ex = (cast(VectorExp)e1).e1;
1053 0
        emplaceExp!(UnionExp)(&ue, ex);
1054 0
        return ue;
1055
    }
1056 1
    if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
1057
    {
1058 1
        goto L1;
1059
    }
1060
    // Allow covariant converions of delegates
1061
    // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
1062
    // then we wouldn't need this extra check.)
1063 1
    if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
1064
    {
1065 0
        goto L1;
1066
    }
1067
    /* Allow casting from one string type to another
1068
     */
1069 1
    if (e1.op == TOK.string_)
1070
    {
1071 1
        if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
1072
        {
1073 0
            goto L1;
1074
        }
1075
    }
1076 1
    if (e1.op == TOK.arrayLiteral && typeb == tb)
1077
    {
1078
    L1:
1079 1
        Expression ex = expType(to, e1);
1080 1
        emplaceExp!(UnionExp)(&ue, ex);
1081 1
        return ue;
1082
    }
1083 1
    if (e1.isConst() != 1)
1084
    {
1085 1
        cantExp(ue);
1086
    }
1087 1
    else if (tb.ty == Tbool)
1088
    {
1089 1
        emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type);
1090
    }
1091 1
    else if (type.isintegral())
1092
    {
1093 1
        if (e1.type.isfloating())
1094
        {
1095 1
            dinteger_t result;
1096 1
            real_t r = e1.toReal();
1097 1
            switch (typeb.ty)
1098
            {
1099 0
            case Tint8:
1100 0
                result = cast(d_int8)cast(sinteger_t)r;
1101 0
                break;
1102 0
            case Tchar:
1103 0
            case Tuns8:
1104 0
                result = cast(d_uns8)cast(dinteger_t)r;
1105 0
                break;
1106 0
            case Tint16:
1107 0
                result = cast(d_int16)cast(sinteger_t)r;
1108 0
                break;
1109 0
            case Twchar:
1110 0
            case Tuns16:
1111 0
                result = cast(d_uns16)cast(dinteger_t)r;
1112 0
                break;
1113 1
            case Tint32:
1114 1
                result = cast(d_int32)r;
1115 1
                break;
1116 0
            case Tdchar:
1117 1
            case Tuns32:
1118 1
                result = cast(d_uns32)r;
1119 1
                break;
1120 1
            case Tint64:
1121 1
                result = cast(d_int64)r;
1122 1
                break;
1123 1
            case Tuns64:
1124 1
                result = cast(d_uns64)r;
1125 1
                break;
1126 0
            default:
1127 0
                assert(0);
1128
            }
1129 1
            emplaceExp!(IntegerExp)(&ue, loc, result, type);
1130
        }
1131 1
        else if (type.isunsigned())
1132 1
            emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1133
        else
1134 1
            emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1135
    }
1136 1
    else if (tb.isreal())
1137
    {
1138 1
        real_t value = e1.toReal();
1139 1
        emplaceExp!(RealExp)(&ue, loc, value, type);
1140
    }
1141 1
    else if (tb.isimaginary())
1142
    {
1143 1
        real_t value = e1.toImaginary();
1144 1
        emplaceExp!(RealExp)(&ue, loc, value, type);
1145
    }
1146 1
    else if (tb.iscomplex())
1147
    {
1148 1
        complex_t value = e1.toComplex();
1149 1
        emplaceExp!(ComplexExp)(&ue, loc, value, type);
1150
    }
1151 1
    else if (tb.isscalar())
1152
    {
1153 1
        emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1154
    }
1155 0
    else if (tb.ty == Tvoid)
1156
    {
1157 0
        cantExp(ue);
1158
    }
1159 0
    else if (tb.ty == Tstruct && e1.op == TOK.int64)
1160
    {
1161
        // Struct = 0;
1162 0
        StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
1163 0
        assert(sd);
1164 0
        auto elements = new Expressions();
1165 0
        for (size_t i = 0; i < sd.fields.dim; i++)
1166
        {
1167 0
            VarDeclaration v = sd.fields[i];
1168 0
            UnionExp zero;
1169 0
            emplaceExp!(IntegerExp)(&zero, 0);
1170 0
            ue = Cast(loc, v.type, v.type, zero.exp());
1171 0
            if (ue.exp().op == TOK.cantExpression)
1172 0
                return ue;
1173 0
            elements.push(ue.exp().copy());
1174
        }
1175 0
        emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
1176 0
        ue.exp().type = type;
1177
    }
1178
    else
1179
    {
1180 0
        if (type != Type.terror)
1181
        {
1182
            // have to change to Internal Compiler Error
1183
            // all invalid casts should be handled already in Expression::castTo().
1184 0
            error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars());
1185
        }
1186 0
        emplaceExp!(ErrorExp)(&ue);
1187
    }
1188 1
    return ue;
1189
}
1190

1191
UnionExp ArrayLength(Type type, Expression e1)
1192
{
1193 1
    UnionExp ue = void;
1194 1
    Loc loc = e1.loc;
1195 1
    if (e1.op == TOK.string_)
1196
    {
1197 1
        StringExp es1 = cast(StringExp)e1;
1198 1
        emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
1199
    }
1200 1
    else if (e1.op == TOK.arrayLiteral)
1201
    {
1202 1
        ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1203 1
        size_t dim = ale.elements ? ale.elements.dim : 0;
1204 1
        emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1205
    }
1206 1
    else if (e1.op == TOK.assocArrayLiteral)
1207
    {
1208 0
        AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
1209 0
        size_t dim = ale.keys.dim;
1210 0
        emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1211
    }
1212 1
    else if (e1.type.toBasetype().ty == Tsarray)
1213
    {
1214 1
        Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
1215 1
        emplaceExp!(UnionExp)(&ue, e);
1216
    }
1217
    else
1218 0
        cantExp(ue);
1219 1
    return ue;
1220
}
1221

1222
/* Also return TOK.cantExpression if this fails
1223
 */
1224
UnionExp Index(Type type, Expression e1, Expression e2)
1225
{
1226 1
    UnionExp ue = void;
1227 1
    Loc loc = e1.loc;
1228
    //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1229 1
    assert(e1.type);
1230 1
    if (e1.op == TOK.string_ && e2.op == TOK.int64)
1231
    {
1232 1
        StringExp es1 = cast(StringExp)e1;
1233 1
        uinteger_t i = e2.toInteger();
1234 1
        if (i >= es1.len)
1235
        {
1236 0
            e1.error("string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len);
1237 0
            emplaceExp!(ErrorExp)(&ue);
1238
        }
1239
        else
1240
        {
1241 1
            emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
1242
        }
1243
    }
1244 1
    else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64)
1245
    {
1246 1
        TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
1247 1
        uinteger_t length = tsa.dim.toInteger();
1248 1
        uinteger_t i = e2.toInteger();
1249 1
        if (i >= length)
1250
        {
1251 1
            e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
1252 1
            emplaceExp!(ErrorExp)(&ue);
1253
        }
1254 1
        else if (e1.op == TOK.arrayLiteral)
1255
        {
1256 1
            ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1257 1
            auto e = ale[cast(size_t)i];
1258 1
            e.type = type;
1259 1
            e.loc = loc;
1260 1
            if (hasSideEffect(e))
1261 0
                cantExp(ue);
1262
            else
1263 1
                emplaceExp!(UnionExp)(&ue, e);
1264
        }
1265
        else
1266 1
            cantExp(ue);
1267
    }
1268 1
    else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64)
1269
    {
1270 1
        uinteger_t i = e2.toInteger();
1271 1
        if (e1.op == TOK.arrayLiteral)
1272
        {
1273 1
            ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1274 1
            if (i >= ale.elements.dim)
1275
            {
1276 1
                e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim);
1277 1
                emplaceExp!(ErrorExp)(&ue);
1278
            }
1279
            else
1280
            {
1281 1
                auto e = ale[cast(size_t)i];
1282 1
                e.type = type;
1283 1
                e.loc = loc;
1284 1
                if (hasSideEffect(e))
1285 0
                    cantExp(ue);
1286
                else
1287 1
                    emplaceExp!(UnionExp)(&ue, e);
1288
            }
1289
        }
1290
        else
1291 1
            cantExp(ue);
1292
    }
1293 1
    else if (e1.op == TOK.assocArrayLiteral)
1294
    {
1295 1
        AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
1296
        /* Search the keys backwards, in case there are duplicate keys
1297
         */
1298 1
        for (size_t i = ae.keys.dim; i;)
1299
        {
1300 1
            i--;
1301 1
            Expression ekey = (*ae.keys)[i];
1302 1
            ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2);
1303 1
            if (CTFEExp.isCantExp(ue.exp()))
1304 0
                return ue;
1305 1
            if (ue.exp().isBool(true))
1306
            {
1307 1
                Expression e = (*ae.values)[i];
1308 1
                e.type = type;
1309 1
                e.loc = loc;
1310 1
                if (hasSideEffect(e))
1311 0
                    cantExp(ue);
1312
                else
1313 1
                    emplaceExp!(UnionExp)(&ue, e);
1314 1
                return ue;
1315
            }
1316
        }
1317 0
        cantExp(ue);
1318
    }
1319
    else
1320 1
        cantExp(ue);
1321 1
    return ue;
1322
}
1323

1324
/* Also return TOK.cantExpression if this fails
1325
 */
1326
UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
1327
{
1328 1
    UnionExp ue = void;
1329 1
    Loc loc = e1.loc;
1330
    static if (LOG)
1331
    {
1332
        printf("Slice()\n");
1333
        if (lwr)
1334
        {
1335
            printf("\te1 = %s\n", e1.toChars());
1336
            printf("\tlwr = %s\n", lwr.toChars());
1337
            printf("\tupr = %s\n", upr.toChars());
1338
        }
1339
    }
1340

1341
    static bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure
1342
    {
1343 1
        assert(lwr <= upr);
1344 1
        return !(newlwr <= newupr &&
1345 1
                 lwr <= newlwr &&
1346 1
                 newupr <= upr);
1347
    }
1348

1349 1
    if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64)
1350
    {
1351 1
        StringExp es1 = cast(StringExp)e1;
1352 1
        const uinteger_t ilwr = lwr.toInteger();
1353 1
        const uinteger_t iupr = upr.toInteger();
1354 1
        if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
1355 1
            cantExp(ue);   // https://issues.dlang.org/show_bug.cgi?id=18115
1356
        else
1357
        {
1358 1
            const len = cast(size_t)(iupr - ilwr);
1359 1
            const sz = es1.sz;
1360 1
            void* s = mem.xmalloc(len * sz);
1361 1
            const data1 = es1.peekData();
1362 1
            memcpy(s, data1.ptr + ilwr * sz, len * sz);
1363 1
            emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
1364 1
            StringExp es = cast(StringExp)ue.exp();
1365 1
            es.committed = es1.committed;
1366 1
            es.type = type;
1367
        }
1368
    }
1369 1
    else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1))
1370
    {
1371 1
        ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
1372 1
        const uinteger_t ilwr = lwr.toInteger();
1373 1
        const uinteger_t iupr = upr.toInteger();
1374 1
        if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr))
1375 0
            cantExp(ue);
1376
        else
1377
        {
1378 1
            auto elements = new Expressions(cast(size_t)(iupr - ilwr));
1379 1
            memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
1380 1
            emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements);
1381
        }
1382
    }
1383
    else
1384 1
        cantExp(ue);
1385 1
    return ue;
1386
}
1387

1388
/* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1389
 * existingAE[firstIndex..firstIndex+newval.length] = newval.
1390
 */
1391
void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
1392
{
1393 1
    const len = newval.len;
1394 1
    Type elemType = existingAE.type.nextOf();
1395 1
    foreach (j; 0 .. len)
1396
    {
1397 1
        const val = newval.getCodeUnit(j);
1398 1
        (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
1399
    }
1400
}
1401

1402
/* Set a slice of string 'existingSE' from a char array literal 'newae'.
1403
 *   existingSE[firstIndex..firstIndex+newae.length] = newae.
1404
 */
1405
void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
1406
{
1407 1
    assert(existingSE.ownedByCtfe != OwnedBy.code);
1408 1
    foreach (j; 0 .. newae.elements.dim)
1409
    {
1410 1
        existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae[j].toInteger());
1411
    }
1412
}
1413

1414
/* Set a slice of string 'existingSE' from a string 'newstr'.
1415
 *   existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1416
 */
1417
void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
1418
{
1419 1
    assert(existingSE.ownedByCtfe != OwnedBy.code);
1420 1
    size_t sz = existingSE.sz;
1421 1
    assert(sz == newstr.sz);
1422 1
    auto data1 = existingSE.borrowData();
1423 1
    const data2 = newstr.peekData();
1424 1
    memcpy(data1.ptr + firstIndex * sz, data2.ptr, data2.length);
1425
}
1426

1427
/* Compare a string slice with another string slice.
1428
 * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  se2[lo2..lo2+len])
1429
 */
1430
int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
1431
{
1432 1
    size_t sz = se1.sz;
1433 1
    assert(sz == se2.sz);
1434 1
    const data1 = se1.peekData();
1435 1
    const data2 = se2.peekData();
1436 1
    return memcmp(data1.ptr + sz * lo1, data2.ptr + sz * lo2, sz * len);
1437
}
1438

1439
/* Compare a string slice with an array literal slice
1440
 * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  ae2[lo2..lo2+len])
1441
 */
1442
int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
1443
{
1444 0
    foreach (j; 0 .. len)
1445
    {
1446 0
        const val2 = cast(dchar)ae2[j + lo2].toInteger();
1447 0
        const val1 = se1.getCodeUnit(j + lo1);
1448 0
        const int c = val1 - val2;
1449 0
        if (c)
1450 0
            return c;
1451
    }
1452 0
    return 0;
1453
}
1454

1455
/** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1456
 * Params:
1457
 *      e1  = If it's ArrayLiteralExp, its `elements` will be copied.
1458
 *            Otherwise, `e1` itself will be pushed into the new `Expressions`.
1459
 *      e2  = If it's not `null`, it will be pushed/appended to the new
1460
 *            `Expressions` by the same way with `e1`.
1461
 * Returns:
1462
 *      Newly allocated `Expressions`. Note that it points to the original
1463
 *      `Expression` values in e1 and e2.
1464
 */
1465
private Expressions* copyElements(Expression e1, Expression e2 = null)
1466
{
1467 1
    auto elems = new Expressions();
1468

1469
    void append(ArrayLiteralExp ale)
1470
    {
1471 1
        if (!ale.elements)
1472 0
            return;
1473 1
        auto d = elems.dim;
1474 1
        elems.append(ale.elements);
1475 1
        foreach (ref el; (*elems)[d .. elems.dim])
1476
        {
1477 1
            if (!el)
1478 0
                el = ale.basis;
1479
        }
1480
    }
1481

1482 1
    if (e1.op == TOK.arrayLiteral)
1483 1
        append(cast(ArrayLiteralExp)e1);
1484
    else
1485 1
        elems.push(e1);
1486

1487 1
    if (e2)
1488
    {
1489 1
        if (e2.op == TOK.arrayLiteral)
1490 1
            append(cast(ArrayLiteralExp)e2);
1491
        else
1492 0
            elems.push(e2);
1493
    }
1494

1495 1
    return elems;
1496
}
1497

1498
/* Also return TOK.cantExpression if this fails
1499
 */
1500
UnionExp Cat(Type type, Expression e1, Expression e2)
1501
{
1502 1
    UnionExp ue = void;
1503 1
    Expression e = CTFEExp.cantexp;
1504 1
    Loc loc = e1.loc;
1505 1
    Type t;
1506 1
    Type t1 = e1.type.toBasetype();
1507 1
    Type t2 = e2.type.toBasetype();
1508
    //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1509
    //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1510 1
    if (e1.op == TOK.null_ && (e2.op == TOK.int64 || e2.op == TOK.structLiteral))
1511
    {
1512 1
        e = e2;
1513 1
        t = t1;
1514 1
        goto L2;
1515
    }
1516 1
    else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_)
1517
    {
1518 1
        e = e1;
1519 1
        t = t2;
1520
    L2:
1521 1
        Type tn = e.type.toBasetype();
1522 1
        if (tn.ty.isSomeChar)
1523
        {
1524
            // Create a StringExp
1525 1
            if (t.nextOf())
1526 1
                t = t.nextOf().toBasetype();
1527 1
            const sz = cast(ubyte)t.size();
1528 1
            dinteger_t v = e.toInteger();
1529 1
            const len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
1530 1
            void* s = mem.xmalloc(len * sz);
1531 1
            if (t.ty == tn.ty)
1532 1
                Port.valcpy(s, v, sz);
1533
            else
1534 1
                utf_encode(sz, s, cast(dchar)v);
1535 1
            emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1536 1
            StringExp es = cast(StringExp)ue.exp();
1537 1
            es.type = type;
1538 1
            es.committed = 1;
1539
        }
1540
        else
1541
        {
1542
            // Create an ArrayLiteralExp
1543 1
            auto elements = new Expressions();
1544 1
            elements.push(e);
1545 1
            emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
1546
        }
1547 1
        assert(ue.exp().type);
1548 1
        return ue;
1549
    }
1550 1
    else if (e1.op == TOK.null_ && e2.op == TOK.null_)
1551
    {
1552 1
        if (type == e1.type)
1553
        {
1554
            // Handle null ~= null
1555 1
            if (t1.ty == Tarray && t2 == t1.nextOf())
1556
            {
1557 1
                emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2);
1558 1
                assert(ue.exp().type);
1559 1
                return ue;
1560
            }
1561
            else
1562
            {
1563 1
                emplaceExp!(UnionExp)(&ue, e1);
1564 1
                assert(ue.exp().type);
1565 1
                return ue;
1566
            }
1567
        }
1568 0
        if (type == e2.type)
1569
        {
1570 0
            emplaceExp!(UnionExp)(&ue, e2);
1571 0
            assert(ue.exp().type);
1572 0
            return ue;
1573
        }
1574 0
        emplaceExp!(NullExp)(&ue, e1.loc, type);
1575 0
        assert(ue.exp().type);
1576 0
        return ue;
1577
    }
1578 1
    else if (e1.op == TOK.string_ && e2.op == TOK.string_)
1579
    {
1580
        // Concatenate the strings
1581 1
        StringExp es1 = cast(StringExp)e1;
1582 1
        StringExp es2 = cast(StringExp)e2;
1583 1
        size_t len = es1.len + es2.len;
1584 1
        ubyte sz = es1.sz;
1585 1
        if (sz != es2.sz)
1586
        {
1587
            /* Can happen with:
1588
             *   auto s = "foo"d ~ "bar"c;
1589
             */
1590 0
            assert(global.errors);
1591 0
            cantExp(ue);
1592 0
            assert(ue.exp().type);
1593 0
            return ue;
1594
        }
1595 1
        void* s = mem.xmalloc(len * sz);
1596 1
        const data1 = es1.peekData();
1597 1
        const data2 = es2.peekData();
1598 1
        memcpy(cast(char*)s, data1.ptr, es1.len * sz);
1599 1
        memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
1600 1
        emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1601 1
        StringExp es = cast(StringExp)ue.exp();
1602 1
        es.committed = es1.committed | es2.committed;
1603 1
        es.type = type;
1604 1
        assert(ue.exp().type);
1605 1
        return ue;
1606
    }
1607 1
    else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
1608
    {
1609
        // [chars] ~ string --> [chars]
1610 1
        StringExp es = cast(StringExp)e2;
1611 1
        ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
1612 1
        size_t len = es.len + ea.elements.dim;
1613 1
        auto elems = new Expressions(len);
1614 1
        for (size_t i = 0; i < ea.elements.dim; ++i)
1615
        {
1616 1
            (*elems)[i] = ea[i];
1617
        }
1618 1
        emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1619 1
        ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
1620 1
        sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
1621 1
        assert(ue.exp().type);
1622 1
        return ue;
1623
    }
1624 1
    else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
1625
    {
1626
        // string ~ [chars] --> [chars]
1627 1
        StringExp es = cast(StringExp)e1;
1628 1
        ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
1629 1
        size_t len = es.len + ea.elements.dim;
1630 1
        auto elems = new Expressions(len);
1631 1
        for (size_t i = 0; i < ea.elements.dim; ++i)
1632
        {
1633 1
            (*elems)[es.len + i] = ea[i];
1634
        }
1635 1
        emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1636 1
        ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
1637 1
        sliceAssignArrayLiteralFromString(dest, es, 0);
1638 1
        assert(ue.exp().type);
1639 1
        return ue;
1640
    }
1641 1
    else if (e1.op == TOK.string_ && e2.op == TOK.int64)
1642
    {
1643
        // string ~ char --> string
1644 1
        StringExp es1 = cast(StringExp)e1;
1645 1
        StringExp es;
1646 1
        const sz = es1.sz;
1647 1
        dinteger_t v = e2.toInteger();
1648
        // Is it a concatenation of homogenous types?
1649
        // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1650 1
        bool homoConcat = (sz == t2.size());
1651 1
        const len = es1.len + (homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v));
1652 1
        void* s = mem.xmalloc(len * sz);
1653 1
        const data1 = es1.peekData();
1654 1
        memcpy(s, data1.ptr, data1.length);
1655 1
        if (homoConcat)
1656 1
            Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
1657
        else
1658 1
            utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
1659 1
        emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1660 1
        es = cast(StringExp)ue.exp();
1661 1
        es.committed = es1.committed;
1662 1
        es.type = type;
1663 1
        assert(ue.exp().type);
1664 1
        return ue;
1665
    }
1666 1
    else if (e1.op == TOK.int64 && e2.op == TOK.string_)
1667
    {
1668
        // [w|d]?char ~ string --> string
1669
        // We assume that we only ever prepend one char of the same type
1670
        // (wchar,dchar) as the string's characters.
1671 1
        StringExp es2 = cast(StringExp)e2;
1672 1
        const len = 1 + es2.len;
1673 1
        const sz = es2.sz;
1674 1
        dinteger_t v = e1.toInteger();
1675 1
        void* s = mem.xmalloc(len * sz);
1676 1
        Port.valcpy(cast(char*)s, v, sz);
1677 1
        const data2 = es2.peekData();
1678 1
        memcpy(cast(char*)s + sz, data2.ptr, data2.length);
1679 1
        emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1680 1
        StringExp es = cast(StringExp)ue.exp();
1681 1
        es.sz = sz;
1682 1
        es.committed = es2.committed;
1683 1
        es.type = type;
1684 1
        assert(ue.exp().type);
1685 1
        return ue;
1686
    }
1687 1
    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1688
    {
1689
        // Concatenate the arrays
1690 1
        auto elems = copyElements(e1, e2);
1691

1692 1
        emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
1693

1694 1
        e = ue.exp();
1695 1
        if (type.toBasetype().ty == Tsarray)
1696
        {
1697 0
            e.type = t1.nextOf().sarrayOf(elems.dim);
1698
        }
1699
        else
1700 1
            e.type = type;
1701 1
        assert(ue.exp().type);
1702 1
        return ue;
1703
    }
1704 1
    else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
1705
    {
1706 0
        e = e1;
1707 0
        goto L3;
1708
    }
1709 1
    else if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1710
    {
1711 0
        e = e2;
1712
    L3:
1713
        // Concatenate the array with null
1714 0
        auto elems = copyElements(e);
1715

1716 0
        emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems);
1717

1718 0
        e = ue.exp();
1719 0
        if (type.toBasetype().ty == Tsarray)
1720
        {
1721 0
            e.type = t1.nextOf().sarrayOf(elems.dim);
1722
        }
1723
        else
1724 0
            e.type = type;
1725 0
        assert(ue.exp().type);
1726 0
        return ue;
1727
    }
1728 1
    else if ((e1.op == TOK.arrayLiteral || e1.op == TOK.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
1729
    {
1730 1
        auto elems = (e1.op == TOK.arrayLiteral)
1731 1
                ? copyElements(e1) : new Expressions();
1732 1
        elems.push(e2);
1733

1734 1
        emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
1735

1736 1
        e = ue.exp();
1737 1
        if (type.toBasetype().ty == Tsarray)
1738
        {
1739 0
            e.type = e2.type.sarrayOf(elems.dim);
1740
        }
1741
        else
1742 1
            e.type = type;
1743 1
        assert(ue.exp().type);
1744 1
        return ue;
1745
    }
1746 1
    else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
1747
    {
1748 1
        auto elems = copyElements(e1, e2);
1749

1750 1
        emplaceExp!(ArrayLiteralExp)(&ue, e2.loc, cast(Type)null, elems);
1751

1752 1
        e = ue.exp();
1753 1
        if (type.toBasetype().ty == Tsarray)
1754
        {
1755 0
            e.type = e1.type.sarrayOf(elems.dim);
1756
        }
1757
        else
1758 1
            e.type = type;
1759 1
        assert(ue.exp().type);
1760 1
        return ue;
1761
    }
1762 1
    else if (e1.op == TOK.null_ && e2.op == TOK.string_)
1763
    {
1764 1
        t = e1.type;
1765 1
        e = e2;
1766 1
        goto L1;
1767
    }
1768 1
    else if (e1.op == TOK.string_ && e2.op == TOK.null_)
1769
    {
1770 1
        e = e1;
1771 1
        t = e2.type;
1772
    L1:
1773 1
        Type tb = t.toBasetype();
1774 1
        if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
1775
        {
1776 0
            auto expressions = new Expressions();
1777 0
            expressions.push(e);
1778 0
            emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
1779 0
            e = ue.exp();
1780
        }
1781
        else
1782
        {
1783 1
            emplaceExp!(UnionExp)(&ue, e);
1784 1
            e = ue.exp();
1785
        }
1786 1
        if (!e.type.equals(type))
1787
        {
1788 0
            StringExp se = cast(StringExp)e.copy();
1789 0
            e = se.castTo(null, type);
1790 0
            emplaceExp!(UnionExp)(&ue, e);
1791 0
            e = ue.exp();
1792
        }
1793
    }
1794
    else
1795 1
        cantExp(ue);
1796 1
    assert(ue.exp().type);
1797 1
    return ue;
1798
}
1799

1800
UnionExp Ptr(Type type, Expression e1)
1801
{
1802
    //printf("Ptr(e1 = %s)\n", e1.toChars());
1803 1
    UnionExp ue = void;
1804 1
    if (e1.op == TOK.add)
1805
    {
1806 1
        AddExp ae = cast(AddExp)e1;
1807 1
        if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
1808
        {
1809 0
            AddrExp ade = cast(AddrExp)ae.e1;
1810 0
            if (ade.e1.op == TOK.structLiteral)
1811
            {
1812 0
                StructLiteralExp se = cast(StructLiteralExp)ade.e1;
1813 0
                uint offset = cast(uint)ae.e2.toInteger();
1814 0
                Expression e = se.getField(type, offset);
1815 0
                if (e)
1816
                {
1817 0
                    emplaceExp!(UnionExp)(&ue, e);
1818 0
                    return ue;
1819
                }
1820
            }
1821
        }
1822
    }
1823 1
    cantExp(ue);
1824 1
    return ue;
1825
}

Read our documentation on viewing source code .

Loading