2 * Perform constant folding of arithmetic expressions.
4 * The routines in this module are called from `optimize.d`.
6 * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
8 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/constfold.d, _constfold.d)
12 * Documentation: https://dlang.org/phobos/dmd_constfold.html
13 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/constfold.d
18 import core
.stdc
.string
;
19 import core
.stdc
.stdio
;
20 import dmd
.arraytypes
;
23 import dmd
.declaration
;
26 import dmd
.expression
;
30 import dmd
.root
.complex
;
31 import dmd
.root
.ctfloat
;
35 import dmd
.sideeffect
;
39 private enum LOG
= false;
41 private Expression
expType(Type type
, Expression e
)
51 /************************************
53 * true if e is a constant
55 int isConst(Expression e
)
57 //printf("Expression::isConst(): %s\n", e.toChars());
66 case EXP
.symbolOffset
:
74 /**********************************
75 * Initialize a EXP.cantExpression Expression.
77 * ue = where to write it
79 void cantExp(out UnionExp ue
)
81 emplaceExp
!(CTFEExp
)(&ue
, EXP
.cantExpression
);
84 /* =============================== constFold() ============================== */
85 /* The constFold() functions were redundant with the optimize() ones,
86 * and so have been folded in with them.
88 /* ========================================================================== */
89 UnionExp
Neg(Type type
, Expression e1
)
95 emplaceExp
!(RealExp
)(&ue
, loc
, -e1
.toReal(), type
);
97 else if (e1
.type
.isimaginary())
99 emplaceExp
!(RealExp
)(&ue
, loc
, -e1
.toImaginary(), type
);
101 else if (e1
.type
.iscomplex())
103 emplaceExp
!(ComplexExp
)(&ue
, loc
, -e1
.toComplex(), type
);
107 emplaceExp
!(IntegerExp
)(&ue
, loc
, -e1
.toInteger(), type
);
112 UnionExp
Com(Type type
, Expression e1
)
116 emplaceExp
!(IntegerExp
)(&ue
, loc
, ~e1
.toInteger(), type
);
120 UnionExp
Not(Type type
, Expression e1
)
124 // BUG: Should be replaced with e1.toBool().get(), but this is apparently
125 // executed for some expressions that cannot be const-folded
126 // To be fixed in another PR
127 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toBool().hasValue(false) ?
1 : 0, type
);
131 UnionExp
Add(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
136 printf("Add(e1 = %s, e2 = %s)\n", e1
.toChars(), e2
.toChars());
140 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toReal() + e2
.toReal(), type
);
142 else if (type
.isimaginary())
144 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toImaginary() + e2
.toImaginary(), type
);
146 else if (type
.iscomplex())
148 // This rigamarole is necessary so that -0.0 doesn't get
149 // converted to +0.0 by doing an extraneous add with +0.0
150 auto c1
= complex_t(CTFloat
.zero
);
151 real_t r1
= CTFloat
.zero
;
152 real_t i1
= CTFloat
.zero
;
153 auto c2
= complex_t(CTFloat
.zero
);
154 real_t r2
= CTFloat
.zero
;
155 real_t i2
= CTFloat
.zero
;
156 auto v
= complex_t(CTFloat
.zero
);
158 if (e1
.type
.isreal())
163 else if (e1
.type
.isimaginary())
165 i1
= e1
.toImaginary();
173 if (e2
.type
.isreal())
177 else if (e2
.type
.isimaginary())
179 i2
= e2
.toImaginary();
190 v
= complex_t(r1
+ r2
);
193 v
= complex_t(r1
, i2
);
196 v
= complex_t(r1
+ creall(c2
), cimagl(c2
));
199 v
= complex_t(r2
, i1
);
202 v
= complex_t(CTFloat
.zero
, i1
+ i2
);
205 v
= complex_t(creall(c2
), i1
+ cimagl(c2
));
208 v
= complex_t(creall(c1
) + r2
, cimagl(c2
));
211 v
= complex_t(creall(c1
), cimagl(c1
) + i2
);
219 emplaceExp
!(ComplexExp
)(&ue
, loc
, v
, type
);
221 else if (SymOffExp soe
= e1
.isSymOffExp())
223 emplaceExp
!(SymOffExp
)(&ue
, loc
, soe
.var
, soe
.offset
+ e2
.toInteger());
224 ue
.exp().type
= type
;
226 else if (SymOffExp soe
= e2
.isSymOffExp())
228 emplaceExp
!(SymOffExp
)(&ue
, loc
, soe
.var
, soe
.offset
+ e1
.toInteger());
229 ue
.exp().type
= type
;
232 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() + e2
.toInteger(), type
);
236 UnionExp
Min(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
238 // Compute e1-e2 as e1+(-e2)
239 UnionExp
neg = Neg(e2
.type
, e2
);
240 UnionExp ue
= Add(loc
, type
, e1
, neg.exp());
244 UnionExp
Mul(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
247 if (type
.isfloating())
249 auto c
= complex_t(CTFloat
.zero
);
250 real_t r
= CTFloat
.zero
;
251 if (e1
.type
.isreal())
255 c
= complex_t(r
* creall(c
), r
* cimagl(c
));
257 else if (e1
.type
.isimaginary())
259 r
= e1
.toImaginary();
261 c
= complex_t(-r
* cimagl(c
), r
* creall(c
));
263 else if (e2
.type
.isreal())
267 c
= complex_t(r
* creall(c
), r
* cimagl(c
));
269 else if (e2
.type
.isimaginary())
271 r
= e2
.toImaginary();
273 c
= complex_t(-r
* cimagl(c
), r
* creall(c
));
276 c
= e1
.toComplex() * e2
.toComplex();
278 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
279 else if (type
.isimaginary())
280 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
281 else if (type
.iscomplex())
282 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
288 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() * e2
.toInteger(), type
);
293 UnionExp
Div(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
296 if (type
.isfloating())
298 auto c
= complex_t(CTFloat
.zero
);
299 if (e2
.type
.isreal())
301 if (e1
.type
.isreal())
303 emplaceExp
!(RealExp
)(&ue
, loc
, e1
.toReal() / e2
.toReal(), type
);
306 const r
= e2
.toReal();
308 c
= complex_t(creall(c
) / r
, cimagl(c
) / r
);
310 else if (e2
.type
.isimaginary())
312 const r
= e2
.toImaginary();
314 c
= complex_t(cimagl(c
) / r
, -creall(c
) / r
);
318 c
= e1
.toComplex() / e2
.toComplex();
322 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
323 else if (type
.isimaginary())
324 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
325 else if (type
.iscomplex())
326 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
339 e2
.error("divide by 0");
340 emplaceExp
!(ErrorExp
)(&ue
);
343 if (n2
== -1 && !type
.isunsigned())
345 // Check for int.min / -1
346 if (n1
== 0xFFFFFFFF80000000UL
&& type
.toBasetype().ty
!= Tint64
)
348 e2
.error("integer overflow: `int.min / -1`");
349 emplaceExp
!(ErrorExp
)(&ue
);
352 else if (n1
== 0x8000000000000000L
) // long.min / -1
354 e2
.error("integer overflow: `long.min / -1L`");
355 emplaceExp
!(ErrorExp
)(&ue
);
359 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
360 n
= (cast(dinteger_t
)n1
) / (cast(dinteger_t
)n2
);
363 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
368 UnionExp
Mod(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
371 if (type
.isfloating())
373 auto c
= complex_t(CTFloat
.zero
);
374 if (e2
.type
.isreal())
376 const r2
= e2
.toReal();
377 c
= complex_t(e1
.toReal() % r2
, e1
.toImaginary() % r2
);
379 else if (e2
.type
.isimaginary())
381 const i2
= e2
.toImaginary();
382 c
= complex_t(e1
.toReal() % i2
, e1
.toImaginary() % i2
);
387 emplaceExp
!(RealExp
)(&ue
, loc
, creall(c
), type
);
388 else if (type
.isimaginary())
389 emplaceExp
!(RealExp
)(&ue
, loc
, cimagl(c
), type
);
390 else if (type
.iscomplex())
391 emplaceExp
!(ComplexExp
)(&ue
, loc
, c
, type
);
404 e2
.error("divide by 0");
405 emplaceExp
!(ErrorExp
)(&ue
);
408 if (n2
== -1 && !type
.isunsigned())
410 // Check for int.min % -1
411 if (n1
== 0xFFFFFFFF80000000UL
&& type
.toBasetype().ty
!= Tint64
)
413 e2
.error("integer overflow: `int.min %% -1`");
414 emplaceExp
!(ErrorExp
)(&ue
);
417 else if (n1
== 0x8000000000000000L
) // long.min % -1
419 e2
.error("integer overflow: `long.min %% -1L`");
420 emplaceExp
!(ErrorExp
)(&ue
);
424 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
425 n
= (cast(dinteger_t
)n1
) % (cast(dinteger_t
)n2
);
428 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
433 UnionExp
Pow(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
437 // Handle integer power operations.
438 if (e2
.type
.isintegral())
440 dinteger_t n
= e2
.toInteger();
442 if (!e2
.type
.isunsigned() && cast(sinteger_t
)n
< 0)
444 if (e1
.type
.isintegral())
449 // Don't worry about overflow, from now on n is unsigned.
456 if (e1
.type
.iscomplex())
458 emplaceExp
!(ComplexExp
)(&ur
, loc
, e1
.toComplex(), e1
.type
);
459 emplaceExp
!(ComplexExp
)(&uv
, loc
, complex_t(CTFloat
.one
), e1
.type
);
461 else if (e1
.type
.isfloating())
463 emplaceExp
!(RealExp
)(&ur
, loc
, e1
.toReal(), e1
.type
);
464 emplaceExp
!(RealExp
)(&uv
, loc
, CTFloat
.one
, e1
.type
);
468 emplaceExp
!(IntegerExp
)(&ur
, loc
, e1
.toInteger(), e1
.type
);
469 emplaceExp
!(IntegerExp
)(&uv
, loc
, 1, e1
.type
);
471 Expression r
= ur
.exp();
472 Expression v
= uv
.exp();
478 uv
= Mul(loc
, v
.type
, v
, r
);
482 ur
= Mul(loc
, r
.type
, r
, r
);
488 emplaceExp
!(RealExp
)(&one
, loc
, CTFloat
.one
, v
.type
);
489 uv
= Div(loc
, v
.type
, one
.exp(), v
);
491 if (type
.iscomplex())
492 emplaceExp
!(ComplexExp
)(&ue
, loc
, v
.toComplex(), type
);
493 else if (type
.isintegral())
494 emplaceExp
!(IntegerExp
)(&ue
, loc
, v
.toInteger(), type
);
496 emplaceExp
!(RealExp
)(&ue
, loc
, v
.toReal(), type
);
498 else if (e2
.type
.isfloating())
500 // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
501 if (e1
.toReal() < CTFloat
.zero
)
503 emplaceExp
!(RealExp
)(&ue
, loc
, target
.RealProperties
.nan
, type
);
513 UnionExp
Shl(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
516 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() << e2
.toInteger(), type
);
520 UnionExp
Shr(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
523 dinteger_t value
= e1
.toInteger();
524 dinteger_t dcount
= e2
.toInteger();
525 assert(dcount
<= 0xFFFFFFFF);
526 uint count
= cast(uint)dcount
;
527 switch (e1
.type
.toBasetype().ty
)
530 value
= cast(byte)value
>> count
;
534 value
= cast(ubyte)value
>> count
;
537 value
= cast(short)value
>> count
;
541 value
= cast(ushort)value
>> count
;
544 value
= cast(int)value
>> count
;
548 value
= cast(uint)value
>> count
;
551 value
= cast(long)value
>> count
;
554 value
= cast(ulong)value
>> count
;
557 emplaceExp
!(ErrorExp
)(&ue
);
562 emplaceExp
!(IntegerExp
)(&ue
, loc
, value
, type
);
566 UnionExp
Ushr(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
569 dinteger_t value
= e1
.toInteger();
570 dinteger_t dcount
= e2
.toInteger();
571 assert(dcount
<= 0xFFFFFFFF);
572 uint count
= cast(uint)dcount
;
573 switch (e1
.type
.toBasetype().ty
)
578 // Possible only with >>>=. >>> always gets promoted to int.
579 value
= (value
& 0xFF) >>> count
;
584 // Possible only with >>>=. >>> always gets promoted to int.
585 value
= (value
& 0xFFFF) >>> count
;
590 value
= (value
& 0xFFFFFFFF) >>> count
;
594 value
= value
>>> count
;
597 emplaceExp
!(ErrorExp
)(&ue
);
602 emplaceExp
!(IntegerExp
)(&ue
, loc
, value
, type
);
606 UnionExp
And(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
609 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() & e2
.toInteger(), type
);
613 UnionExp
Or(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
616 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() | e2
.toInteger(), type
);
620 UnionExp
Xor(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
622 //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
624 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger() ^ e2
.toInteger(), type
);
628 /* Also returns EXP.cantExpression if cannot be computed.
630 UnionExp
Equal(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
634 real_t r1
= CTFloat
.zero
;
635 real_t r2
= CTFloat
.zero
;
636 //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
637 assert(op
== EXP
.equal || op
== EXP
.notEqual
);
638 if (e1
.op
== EXP
.null_
)
640 if (e2
.op
== EXP
.null_
)
642 else if (StringExp es2
= e2
.isStringExp())
644 cmp = (0 == es2
.len
);
646 else if (ArrayLiteralExp es2
= e2
.isArrayLiteralExp())
648 cmp = !es2
.elements ||
(0 == es2
.elements
.length
);
656 else if (e2
.op
== EXP
.null_
)
658 if (StringExp es1
= e1
.isStringExp())
660 cmp = (0 == es1
.len
);
662 else if (ArrayLiteralExp es1
= e1
.isArrayLiteralExp())
664 cmp = !es1
.elements ||
(0 == es1
.elements
.length
);
672 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
674 StringExp es1
= e1
.isStringExp();
675 StringExp es2
= e2
.isStringExp();
676 if (es1
.sz
!= es2
.sz
)
678 assert(global
.errors
);
682 const data1
= es1
.peekData();
683 const data2
= es2
.peekData();
684 if (es1
.len
== es2
.len
&& memcmp(data1
.ptr
, data2
.ptr
, es1
.sz
* es1
.len
) == 0)
689 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.arrayLiteral
)
691 ArrayLiteralExp es1
= e1
.isArrayLiteralExp();
692 ArrayLiteralExp es2
= e2
.isArrayLiteralExp();
693 if ((!es1
.elements ||
!es1
.elements
.length
) && (!es2
.elements ||
!es2
.elements
.length
))
694 cmp = 1; // both arrays are empty
695 else if (!es1
.elements ||
!es2
.elements
)
697 else if (es1
.elements
.length
!= es2
.elements
.length
)
701 for (size_t i
= 0; i
< es1
.elements
.length
; i
++)
705 ue
= Equal(EXP
.equal
, loc
, Type
.tint32
, ee1
, ee2
);
706 if (CTFEExp
.isCantExp(ue
.exp()))
708 cmp = cast(int)ue
.exp().toInteger();
714 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.string_
)
716 // Swap operands and use common code
717 Expression etmp
= e1
;
722 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.arrayLiteral
)
725 StringExp es1
= e1
.isStringExp();
726 ArrayLiteralExp es2
= e2
.isArrayLiteralExp();
727 size_t dim1
= es1
.len
;
728 size_t dim2
= es2
.elements ? es2
.elements
.length
: 0;
733 cmp = 1; // if dim1 winds up being 0
734 foreach (i
; 0 .. dim1
)
736 uinteger_t c
= es1
.getCodeUnit(i
);
738 if (ee2
.isConst() != 1)
743 cmp = (c
== ee2
.toInteger());
749 else if (e1
.op
== EXP
.structLiteral
&& e2
.op
== EXP
.structLiteral
)
751 StructLiteralExp es1
= e1
.isStructLiteralExp();
752 StructLiteralExp es2
= e2
.isStructLiteralExp();
753 if (es1
.sd
!= es2
.sd
)
755 else if ((!es1
.elements ||
!es1
.elements
.length
) && (!es2
.elements ||
!es2
.elements
.length
))
756 cmp = 1; // both arrays are empty
757 else if (!es1
.elements ||
!es2
.elements
)
759 else if (es1
.elements
.length
!= es2
.elements
.length
)
764 for (size_t i
= 0; i
< es1
.elements
.length
; i
++)
766 Expression ee1
= (*es1
.elements
)[i
];
767 Expression ee2
= (*es2
.elements
)[i
];
775 ue
= Equal(EXP
.equal
, loc
, Type
.tint32
, ee1
, ee2
);
776 if (ue
.exp().op
== EXP
.cantExpression
)
778 cmp = cast(int)ue
.exp().toInteger();
784 else if (e1
.isConst() != 1 || e2
.isConst() != 1)
789 else if (e1
.type
.isreal())
795 else if (e1
.type
.isimaginary())
797 r1
= e1
.toImaginary();
798 r2
= e2
.toImaginary();
800 if (CTFloat
.isNaN(r1
) || CTFloat
.isNaN(r2
)) // if unordered
809 else if (e1
.type
.iscomplex())
811 cmp = e1
.toComplex() == e2
.toComplex();
813 else if (e1
.type
.isintegral() || e1
.type
.toBasetype().ty
== Tpointer
)
815 cmp = (e1
.toInteger() == e2
.toInteger());
822 if (op
== EXP
.notEqual
)
824 emplaceExp
!(IntegerExp
)(&ue
, loc
, cmp, type
);
828 UnionExp
Identity(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
832 if (e1
.op
== EXP
.null_
)
834 cmp = (e2
.op
== EXP
.null_
);
836 else if (e2
.op
== EXP
.null_
)
840 else if (e1
.op
== EXP
.symbolOffset
&& e2
.op
== EXP
.symbolOffset
)
842 SymOffExp es1
= e1
.isSymOffExp();
843 SymOffExp es2
= e2
.isSymOffExp();
844 cmp = (es1
.var
== es2
.var
&& es1
.offset
== es2
.offset
);
848 if (e1
.type
.isfloating())
849 cmp = e1
.isIdentical(e2
);
852 ue
= Equal((op
== EXP
.identity
) ? EXP
.equal
: EXP
.notEqual
, loc
, type
, e1
, e2
);
856 if (op
== EXP
.notIdentity
)
858 emplaceExp
!(IntegerExp
)(&ue
, loc
, cmp, type
);
862 UnionExp
Cmp(EXP op
, const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
866 real_t r1
= CTFloat
.zero
;
867 real_t r2
= CTFloat
.zero
;
868 //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
869 if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
871 StringExp es1
= e1
.isStringExp();
872 StringExp es2
= e2
.isStringExp();
874 assert(sz
== es2
.sz
);
875 size_t len
= es1
.len
;
878 const data1
= es1
.peekData();
879 const data2
= es1
.peekData();
880 int rawCmp
= memcmp(data1
.ptr
, data2
.ptr
, sz
* len
);
882 rawCmp
= cast(int)(es1
.len
- es2
.len
);
883 n
= specificCmp(op
, rawCmp
);
885 else if (e1
.isConst() != 1 || e2
.isConst() != 1)
890 else if (e1
.type
.isreal())
896 else if (e1
.type
.isimaginary())
898 r1
= e1
.toImaginary();
899 r2
= e2
.toImaginary();
901 n
= realCmp(op
, r1
, r2
);
903 else if (e1
.type
.iscomplex())
913 if (e1
.type
.isunsigned() || e2
.type
.isunsigned())
914 n
= intUnsignedCmp(op
, n1
, n2
);
916 n
= intSignedCmp(op
, n1
, n2
);
918 emplaceExp
!(IntegerExp
)(&ue
, loc
, n
, type
);
922 /* Also returns EXP.cantExpression if cannot be computed.
923 * to: type to cast to
924 * type: type to paint the result
926 UnionExp
Cast(const ref Loc loc
, Type type
, Type to
, Expression e1
)
929 Type tb
= to
.toBasetype();
930 Type typeb
= type
.toBasetype();
931 //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
932 //printf("\te1.type = %s\n", e1.type.toChars());
933 if (e1
.type
.equals(type
) && type
.equals(to
))
935 emplaceExp
!(UnionExp
)(&ue
, e1
);
938 if (e1
.op
== EXP
.vector
&& (cast(TypeVector
)e1
.type
).basetype
.equals(type
) && type
.equals(to
))
940 Expression ex
= e1
.isVectorExp().e1
;
941 emplaceExp
!(UnionExp
)(&ue
, ex
);
944 if (e1
.type
.toBasetype
.equals(type
) && type
.equals(to
))
946 emplaceExp
!(UnionExp
)(&ue
, e1
);
947 ue
.exp().type
= type
;
950 if (e1
.type
.implicitConvTo(to
) >= MATCH
.constant || to
.implicitConvTo(e1
.type
) >= MATCH
.constant
)
954 // Allow covariant converions of delegates
955 // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
956 // then we wouldn't need this extra check.)
957 if (e1
.type
.toBasetype().ty
== Tdelegate
&& e1
.type
.implicitConvTo(to
) == MATCH
.convert
)
961 /* Allow casting from one string type to another
963 if (e1
.op
== EXP
.string_
)
965 if (tb
.ty
== Tarray
&& typeb
.ty
== Tarray
&& tb
.nextOf().size() == typeb
.nextOf().size())
970 if (e1
.op
== EXP
.arrayLiteral
&& typeb
== tb
)
973 Expression ex
= expType(to
, e1
);
974 emplaceExp
!(UnionExp
)(&ue
, ex
);
977 if (e1
.isConst() != 1)
981 else if (tb
.ty
== Tbool
)
983 const opt
= e1
.toBool();
990 emplaceExp
!(IntegerExp
)(&ue
, loc
, opt
.get(), type
);
992 else if (type
.isintegral())
994 if (e1
.type
.isfloating())
997 real_t r
= e1
.toReal();
1001 result
= cast(byte)cast(sinteger_t
)r
;
1005 result
= cast(ubyte)cast(dinteger_t
)r
;
1008 result
= cast(short)cast(sinteger_t
)r
;
1012 result
= cast(ushort)cast(dinteger_t
)r
;
1015 result
= cast(int)r
;
1019 result
= cast(uint)r
;
1022 result
= cast(long)r
;
1025 result
= cast(ulong)r
;
1030 emplaceExp
!(IntegerExp
)(&ue
, loc
, result
, type
);
1032 else if (type
.isunsigned())
1033 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toUInteger(), type
);
1035 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger(), type
);
1037 else if (tb
.isreal())
1039 real_t value
= e1
.toReal();
1040 emplaceExp
!(RealExp
)(&ue
, loc
, value
, type
);
1042 else if (tb
.isimaginary())
1044 real_t value
= e1
.toImaginary();
1045 emplaceExp
!(RealExp
)(&ue
, loc
, value
, type
);
1047 else if (tb
.iscomplex())
1049 complex_t value
= e1
.toComplex();
1050 emplaceExp
!(ComplexExp
)(&ue
, loc
, value
, type
);
1052 else if (tb
.isscalar())
1054 emplaceExp
!(IntegerExp
)(&ue
, loc
, e1
.toInteger(), type
);
1056 else if (tb
.ty
== Tvoid
)
1060 else if (tb
.ty
== Tstruct
&& e1
.op
== EXP
.int64
)
1063 StructDeclaration sd
= tb
.toDsymbol(null).isStructDeclaration();
1065 auto elements
= new Expressions();
1066 for (size_t i
= 0; i
< sd
.fields
.length
; i
++)
1068 VarDeclaration v
= sd
.fields
[i
];
1070 emplaceExp
!(IntegerExp
)(&zero
, 0);
1071 ue
= Cast(loc
, v
.type
, v
.type
, zero
.exp());
1072 if (ue
.exp().op
== EXP
.cantExpression
)
1074 elements
.push(ue
.exp().copy());
1076 emplaceExp
!(StructLiteralExp
)(&ue
, loc
, sd
, elements
);
1077 ue
.exp().type
= type
;
1081 if (type
!= Type
.terror
)
1083 // have to change to internal compiler error
1084 // all invalid casts should be handled already in Expression::castTo().
1085 error(loc
, "cannot cast `%s` to `%s`", e1
.type
.toChars(), type
.toChars());
1087 emplaceExp
!(ErrorExp
)(&ue
);
1092 UnionExp
ArrayLength(Type type
, Expression e1
)
1096 if (StringExp es1
= e1
.isStringExp())
1098 emplaceExp
!(IntegerExp
)(&ue
, loc
, es1
.len
, type
);
1100 else if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1102 size_t dim
= ale
.elements ? ale
.elements
.length
: 0;
1103 emplaceExp
!(IntegerExp
)(&ue
, loc
, dim
, type
);
1105 else if (AssocArrayLiteralExp ale
= e1
.isAssocArrayLiteralExp
)
1107 size_t dim
= ale
.keys
.length
;
1108 emplaceExp
!(IntegerExp
)(&ue
, loc
, dim
, type
);
1110 else if (e1
.type
.toBasetype().ty
== Tsarray
)
1112 Expression e
= (cast(TypeSArray
)e1
.type
.toBasetype()).dim
;
1113 emplaceExp
!(UnionExp
)(&ue
, e
);
1115 else if (e1
.isNullExp())
1117 emplaceExp
!(IntegerExp
)(&ue
, loc
, 0, type
);
1124 /* Also return EXP.cantExpression if this fails
1126 UnionExp
Index(Type type
, Expression e1
, Expression e2
, bool indexIsInBounds
)
1130 //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1132 if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.int64
)
1134 StringExp es1
= e1
.isStringExp();
1135 uinteger_t i
= e2
.toInteger();
1138 e1
.error("string index %llu is out of bounds `[0 .. %llu]`", i
, cast(ulong)es1
.len
);
1139 emplaceExp
!(ErrorExp
)(&ue
);
1143 emplaceExp
!(IntegerExp
)(&ue
, loc
, es1
.getCodeUnit(cast(size_t
) i
), type
);
1146 else if (e1
.type
.toBasetype().ty
== Tsarray
&& e2
.op
== EXP
.int64
)
1148 TypeSArray tsa
= cast(TypeSArray
)e1
.type
.toBasetype();
1149 uinteger_t length
= tsa
.dim
.toInteger();
1150 uinteger_t i
= e2
.toInteger();
1151 if (i
>= length
&& (e1
.op
== EXP
.arrayLiteral ||
!indexIsInBounds
))
1153 // C code only checks bounds if an ArrayLiteralExp
1154 e1
.error("array index %llu is out of bounds `%s[0 .. %llu]`", i
, e1
.toChars(), length
);
1155 emplaceExp
!(ErrorExp
)(&ue
);
1157 else if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1159 auto e
= ale
[cast(size_t
)i
];
1162 if (hasSideEffect(e
))
1165 emplaceExp
!(UnionExp
)(&ue
, e
);
1170 else if (e1
.type
.toBasetype().ty
== Tarray
&& e2
.op
== EXP
.int64
)
1172 uinteger_t i
= e2
.toInteger();
1173 if (ArrayLiteralExp ale
= e1
.isArrayLiteralExp())
1175 if (i
>= ale
.elements
.length
)
1177 e1
.error("array index %llu is out of bounds `%s[0 .. %llu]`", i
, e1
.toChars(), cast(ulong) ale
.elements
.length
);
1178 emplaceExp
!(ErrorExp
)(&ue
);
1182 auto e
= ale
[cast(size_t
)i
];
1185 if (hasSideEffect(e
))
1188 emplaceExp
!(UnionExp
)(&ue
, e
);
1194 else if (AssocArrayLiteralExp ae
= e1
.isAssocArrayLiteralExp())
1196 /* Search the keys backwards, in case there are duplicate keys
1198 for (size_t i
= ae
.keys
.length
; i
;)
1201 Expression ekey
= (*ae
.keys
)[i
];
1202 ue
= Equal(EXP
.equal
, loc
, Type
.tbool
, ekey
, e2
);
1203 if (CTFEExp
.isCantExp(ue
.exp()))
1205 if (ue
.exp().toBool().hasValue(true))
1207 Expression e
= (*ae
.values
)[i
];
1210 if (hasSideEffect(e
))
1213 emplaceExp
!(UnionExp
)(&ue
, e
);
1224 /* Also return EXP.cantExpression if this fails
1226 UnionExp
Slice(Type type
, Expression e1
, Expression lwr
, Expression upr
)
1232 printf("Slice()\n");
1235 printf("\te1 = %s\n", e1
.toChars());
1236 printf("\tlwr = %s\n", lwr
.toChars());
1237 printf("\tupr = %s\n", upr
.toChars());
1243 if (e1
.op
== EXP
.string_
)
1244 emplaceExp(&ue
, e1
);
1248 else if (e1
.op
== EXP
.string_
&& lwr
.op
== EXP
.int64
&& upr
.op
== EXP
.int64
)
1250 StringExp es1
= e1
.isStringExp();
1251 const uinteger_t ilwr
= lwr
.toInteger();
1252 const uinteger_t iupr
= upr
.toInteger();
1253 if (sliceBoundsCheck(0, es1
.len
, ilwr
, iupr
))
1254 cantExp(ue
); // https://issues.dlang.org/show_bug.cgi?id=18115
1257 const len
= cast(size_t
)(iupr
- ilwr
);
1259 void* s
= mem
.xmalloc(len
* sz
);
1260 const data1
= es1
.peekData();
1261 memcpy(s
, data1
.ptr
+ ilwr
* sz
, len
* sz
);
1262 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
, es1
.postfix
);
1263 StringExp es
= ue
.exp().isStringExp();
1264 es
.committed
= es1
.committed
;
1268 else if (e1
.op
== EXP
.arrayLiteral
&& lwr
.op
== EXP
.int64
&& upr
.op
== EXP
.int64
&& !hasSideEffect(e1
))
1270 ArrayLiteralExp es1
= e1
.isArrayLiteralExp();
1271 const uinteger_t ilwr
= lwr
.toInteger();
1272 const uinteger_t iupr
= upr
.toInteger();
1273 if (sliceBoundsCheck(0, es1
.elements
.length
, ilwr
, iupr
))
1277 auto elements
= new Expressions(cast(size_t
)(iupr
- ilwr
));
1278 memcpy(elements
.tdata(), es1
.elements
.tdata() + ilwr
, cast(size_t
)(iupr
- ilwr
) * ((*es1
.elements
)[0]).sizeof
);
1279 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elements
);
1287 /* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
1289 bool sliceBoundsCheck(uinteger_t lwr
, uinteger_t upr
, uinteger_t newlwr
, uinteger_t newupr
) pure
1292 return !(newlwr
<= newupr
&&
1297 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1298 * existingAE[firstIndex..firstIndex+newval.length] = newval.
1300 void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE
, const StringExp newval
, size_t firstIndex
)
1302 const len
= newval
.len
;
1303 Type elemType
= existingAE
.type
.nextOf();
1304 foreach (j
; 0 .. len
)
1306 const val
= newval
.getCodeUnit(j
);
1307 (*existingAE
.elements
)[j
+ firstIndex
] = new IntegerExp(newval
.loc
, val
, elemType
);
1311 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1312 * existingSE[firstIndex..firstIndex+newae.length] = newae.
1314 void sliceAssignStringFromArrayLiteral(StringExp existingSE
, ArrayLiteralExp newae
, size_t firstIndex
)
1316 assert(existingSE
.ownedByCtfe
!= OwnedBy
.code
);
1317 foreach (j
; 0 .. newae
.elements
.length
)
1319 existingSE
.setCodeUnit(firstIndex
+ j
, cast(dchar)newae
[j
].toInteger());
1323 /* Set a slice of string 'existingSE' from a string 'newstr'.
1324 * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1326 void sliceAssignStringFromString(StringExp existingSE
, const StringExp newstr
, size_t firstIndex
)
1328 assert(existingSE
.ownedByCtfe
!= OwnedBy
.code
);
1329 size_t sz
= existingSE
.sz
;
1330 assert(sz
== newstr
.sz
);
1331 auto data1
= existingSE
.borrowData();
1332 const data2
= newstr
.peekData();
1333 memcpy(data1
.ptr
+ firstIndex
* sz
, data2
.ptr
, data2
.length
);
1336 /* Compare a string slice with another string slice.
1337 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
1339 int sliceCmpStringWithString(const StringExp se1
, const StringExp se2
, size_t lo1
, size_t lo2
, size_t len
)
1342 assert(sz
== se2
.sz
);
1343 const data1
= se1
.peekData();
1344 const data2
= se2
.peekData();
1345 return memcmp(data1
.ptr
+ sz
* lo1
, data2
.ptr
+ sz
* lo2
, sz
* len
);
1348 /* Compare a string slice with an array literal slice
1349 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
1351 int sliceCmpStringWithArray(const StringExp se1
, ArrayLiteralExp ae2
, size_t lo1
, size_t lo2
, size_t len
)
1353 foreach (j
; 0 .. len
)
1355 const val2
= cast(dchar)ae2
[j
+ lo2
].toInteger();
1356 const val1
= se1
.getCodeUnit(j
+ lo1
);
1357 const int c
= val1
- val2
;
1364 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1366 * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
1367 * Otherwise, `e1` itself will be pushed into the new `Expressions`.
1368 * e2 = If it's not `null`, it will be pushed/appended to the new
1369 * `Expressions` by the same way with `e1`.
1371 * Newly allocated `Expressions`. Note that it points to the original
1372 * `Expression` values in e1 and e2.
1374 private Expressions
* copyElements(Expression e1
, Expression e2
= null)
1376 auto elems
= new Expressions();
1378 void append(ArrayLiteralExp ale
)
1382 auto d
= elems
.length
;
1383 elems
.append(ale
.elements
);
1384 foreach (ref el
; (*elems
)[d
.. elems
.length
])
1391 if (auto ale
= e1
.isArrayLiteralExp())
1398 if (auto ale
= e2
.isArrayLiteralExp())
1407 /* Also return EXP.cantExpression if this fails
1409 UnionExp
Cat(const ref Loc loc
, Type type
, Expression e1
, Expression e2
)
1412 Expression e
= CTFEExp
.cantexp
;
1414 Type t1
= e1
.type
.toBasetype();
1415 Type t2
= e2
.type
.toBasetype();
1416 //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1417 //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1419 /* e is the non-null operand, t is the type of the null operand
1421 UnionExp
catNull(Expression e
, Type t
)
1423 Type tn
= e
.type
.toBasetype();
1424 if (tn
.ty
.isSomeChar
)
1426 // Create a StringExp
1428 t
= t
.nextOf().toBasetype();
1429 const sz
= cast(ubyte)t
.size();
1430 dinteger_t v
= e
.toInteger();
1431 const len
= (t
.ty
== tn
.ty
) ?
1 : utf_codeLength(sz
, cast(dchar)v
);
1432 void* s
= mem
.xmalloc(len
* sz
);
1434 Port
.valcpy(s
, v
, sz
);
1436 utf_encode(sz
, s
, cast(dchar)v
);
1437 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1438 StringExp es
= ue
.exp().isStringExp();
1444 // Create an ArrayLiteralExp
1445 auto elements
= new Expressions();
1447 emplaceExp
!(ArrayLiteralExp
)(&ue
, e
.loc
, type
, elements
);
1449 assert(ue
.exp().type
);
1453 if (e1
.op
== EXP
.null_
&& (e2
.op
== EXP
.int64 || e2
.op
== EXP
.structLiteral
))
1455 return catNull(e2
, t1
);
1457 else if ((e1
.op
== EXP
.int64 || e1
.op
== EXP
.structLiteral
) && e2
.op
== EXP
.null_
)
1459 return catNull(e1
, t2
);
1461 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.null_
)
1463 if (type
== e1
.type
)
1465 // Handle null ~= null
1466 if (t1
.ty
== Tarray
&& t2
== t1
.nextOf())
1468 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, e2
);
1469 assert(ue
.exp().type
);
1474 emplaceExp
!(UnionExp
)(&ue
, e1
);
1475 assert(ue
.exp().type
);
1479 if (type
== e2
.type
)
1481 emplaceExp
!(UnionExp
)(&ue
, e2
);
1482 assert(ue
.exp().type
);
1485 emplaceExp
!(NullExp
)(&ue
, e1
.loc
, type
);
1486 assert(ue
.exp().type
);
1489 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.string_
)
1491 // Concatenate the strings
1492 StringExp es1
= e1
.isStringExp();
1493 StringExp es2
= e2
.isStringExp();
1494 size_t len
= es1
.len
+ es2
.len
;
1499 * auto s = "foo"d ~ "bar"c;
1501 assert(global
.errors
);
1503 assert(ue
.exp().type
);
1506 void* s
= mem
.xmalloc(len
* sz
);
1507 const data1
= es1
.peekData();
1508 const data2
= es2
.peekData();
1509 memcpy(cast(char*)s
, data1
.ptr
, es1
.len
* sz
);
1510 memcpy(cast(char*)s
+ es1
.len
* sz
, data2
.ptr
, es2
.len
* sz
);
1511 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1512 StringExp es
= ue
.exp().isStringExp();
1513 es
.committed
= es1
.committed | es2
.committed
;
1515 assert(ue
.exp().type
);
1518 else if (e2
.op
== EXP
.string_
&& e1
.op
== EXP
.arrayLiteral
&& t1
.nextOf().isintegral())
1520 // [chars] ~ string --> [chars]
1521 StringExp es
= e2
.isStringExp();
1522 ArrayLiteralExp ea
= e1
.isArrayLiteralExp();
1523 size_t len
= es
.len
+ ea
.elements
.length
;
1524 auto elems
= new Expressions(len
);
1525 for (size_t i
= 0; i
< ea
.elements
.length
; ++i
)
1527 (*elems
)[i
] = ea
[i
];
1529 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elems
);
1530 ArrayLiteralExp dest
= ue
.exp().isArrayLiteralExp();
1531 sliceAssignArrayLiteralFromString(dest
, es
, ea
.elements
.length
);
1532 assert(ue
.exp().type
);
1535 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.arrayLiteral
&& t2
.nextOf().isintegral())
1537 // string ~ [chars] --> [chars]
1538 StringExp es
= e1
.isStringExp();
1539 ArrayLiteralExp ea
= e2
.isArrayLiteralExp();
1540 size_t len
= es
.len
+ ea
.elements
.length
;
1541 auto elems
= new Expressions(len
);
1542 for (size_t i
= 0; i
< ea
.elements
.length
; ++i
)
1544 (*elems
)[es
.len
+ i
] = ea
[i
];
1546 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, type
, elems
);
1547 ArrayLiteralExp dest
= ue
.exp().isArrayLiteralExp();
1548 sliceAssignArrayLiteralFromString(dest
, es
, 0);
1549 assert(ue
.exp().type
);
1552 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.int64
)
1554 // string ~ char --> string
1555 StringExp es1
= e1
.isStringExp();
1558 dinteger_t v
= e2
.toInteger();
1559 // Is it a concatenation of homogenous types?
1560 // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1561 bool homoConcat
= (sz
== t2
.size());
1562 const len
= es1
.len
+ (homoConcat ?
1 : utf_codeLength(sz
, cast(dchar)v
));
1563 void* s
= mem
.xmalloc(len
* sz
);
1564 const data1
= es1
.peekData();
1565 memcpy(s
, data1
.ptr
, data1
.length
);
1567 Port
.valcpy(cast(char*)s
+ (sz
* es1
.len
), v
, sz
);
1569 utf_encode(sz
, cast(char*)s
+ (sz
* es1
.len
), cast(dchar)v
);
1570 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1571 es
= ue
.exp().isStringExp();
1572 es
.committed
= es1
.committed
;
1574 assert(ue
.exp().type
);
1577 else if (e1
.op
== EXP
.int64
&& e2
.op
== EXP
.string_
)
1579 // [w|d]?char ~ string --> string
1580 // We assume that we only ever prepend one char of the same type
1581 // (wchar,dchar) as the string's characters.
1582 StringExp es2
= e2
.isStringExp();
1583 const len
= 1 + es2
.len
;
1585 dinteger_t v
= e1
.toInteger();
1586 void* s
= mem
.xmalloc(len
* sz
);
1587 Port
.valcpy(cast(char*)s
, v
, sz
);
1588 const data2
= es2
.peekData();
1589 memcpy(cast(char*)s
+ sz
, data2
.ptr
, data2
.length
);
1590 emplaceExp
!(StringExp
)(&ue
, loc
, s
[0 .. len
* sz
], len
, sz
);
1591 StringExp es
= ue
.exp().isStringExp();
1593 es
.committed
= es2
.committed
;
1595 assert(ue
.exp().type
);
1598 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.arrayLiteral
&& t1
.nextOf().equals(t2
.nextOf()))
1600 // Concatenate the arrays
1601 auto elems
= copyElements(e1
, e2
);
1603 emplaceExp
!(ArrayLiteralExp
)(&ue
, e1
.loc
, cast(Type
)null, elems
);
1606 if (type
.toBasetype().ty
== Tsarray
)
1608 e
.type
= t1
.nextOf().sarrayOf(elems
.length
);
1612 assert(ue
.exp().type
);
1615 else if (e1
.op
== EXP
.arrayLiteral
&& e2
.op
== EXP
.null_
&& t1
.nextOf().equals(t2
.nextOf()))
1620 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.arrayLiteral
&& t1
.nextOf().equals(t2
.nextOf()))
1624 // Concatenate the array with null
1625 auto elems
= copyElements(e
);
1627 emplaceExp
!(ArrayLiteralExp
)(&ue
, e
.loc
, cast(Type
)null, elems
);
1630 if (type
.toBasetype().ty
== Tsarray
)
1632 e
.type
= t1
.nextOf().sarrayOf(elems
.length
);
1636 assert(ue
.exp().type
);
1639 else if ((e1
.op
== EXP
.arrayLiteral || e1
.op
== EXP
.null_
) && e1
.type
.toBasetype().nextOf() && e1
.type
.toBasetype().nextOf().equals(e2
.type
))
1641 auto elems
= (e1
.op
== EXP
.arrayLiteral
)
1642 ?
copyElements(e1
) : new Expressions();
1645 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, cast(Type
)null, elems
);
1648 if (type
.toBasetype().ty
== Tsarray
)
1650 e
.type
= e2
.type
.sarrayOf(elems
.length
);
1654 assert(ue
.exp().type
);
1657 else if (e2
.op
== EXP
.arrayLiteral
&& e2
.type
.toBasetype().nextOf().equals(e1
.type
))
1659 auto elems
= copyElements(e1
, e2
);
1661 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, cast(Type
)null, elems
);
1664 if (type
.toBasetype().ty
== Tsarray
)
1666 e
.type
= e1
.type
.sarrayOf(elems
.length
);
1670 assert(ue
.exp().type
);
1673 else if (e1
.op
== EXP
.null_
&& e2
.op
== EXP
.string_
)
1679 else if (e1
.op
== EXP
.string_
&& e2
.op
== EXP
.null_
)
1684 Type tb
= t
.toBasetype();
1685 if (tb
.ty
== Tarray
&& tb
.nextOf().equivalent(e
.type
))
1687 auto expressions
= new Expressions();
1688 expressions
.push(e
);
1689 emplaceExp
!(ArrayLiteralExp
)(&ue
, loc
, t
, expressions
);
1694 emplaceExp
!(UnionExp
)(&ue
, e
);
1697 if (!e
.type
.equals(type
))
1699 StringExp se
= e
.copy().isStringExp();
1700 e
= se
.castTo(null, type
);
1701 emplaceExp
!(UnionExp
)(&ue
, e
);
1707 assert(ue
.exp().type
);
1711 UnionExp
Ptr(Type type
, Expression e1
)
1713 //printf("Ptr(e1 = %s)\n", e1.toChars());
1715 if (AddExp ae
= e1
.isAddExp())
1717 if (AddrExp ade
= ae
.e1
.isAddrExp())
1719 if (ae
.e2
.op
== EXP
.int64
)
1720 if (StructLiteralExp se
= ade
.e1
.isStructLiteralExp())
1722 uint offset
= cast(uint)ae
.e2
.toInteger();
1723 Expression e
= se
.getField(type
, offset
);
1726 emplaceExp
!(UnionExp
)(&ue
, e
);