]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/ctfeexpr.c
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/ctfeexpr.c
11 #include "root/dsystem.h" // mem{cpy|set}()
12 #include "root/rmem.h"
15 #include "expression.h"
16 #include "declaration.h"
17 #include "aggregate.h"
24 int RealEquals(real_t x1
, real_t x2
);
26 /************** ClassReferenceExp ********************************************/
28 ClassReferenceExp::ClassReferenceExp(Loc loc
, StructLiteralExp
*lit
, Type
*type
)
29 : Expression(loc
, TOKclassreference
, sizeof(ClassReferenceExp
))
31 assert(lit
&& lit
->sd
&& lit
->sd
->isClassDeclaration());
36 ClassDeclaration
*ClassReferenceExp::originalClass()
38 return value
->sd
->isClassDeclaration();
41 // Return index of the field, or -1 if not found
42 int ClassReferenceExp::getFieldIndex(Type
*fieldtype
, unsigned fieldoffset
)
44 ClassDeclaration
*cd
= originalClass();
45 unsigned fieldsSoFar
= 0;
46 for (size_t j
= 0; j
< value
->elements
->length
; j
++)
48 while (j
- fieldsSoFar
>= cd
->fields
.length
)
50 fieldsSoFar
+= cd
->fields
.length
;
53 VarDeclaration
*v2
= cd
->fields
[j
- fieldsSoFar
];
54 if (fieldoffset
== v2
->offset
&&
55 fieldtype
->size() == v2
->type
->size())
57 return (int)(value
->elements
->length
- fieldsSoFar
- cd
->fields
.length
+ (j
-fieldsSoFar
));
63 // Return index of the field, or -1 if not found
64 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
65 int ClassReferenceExp::findFieldIndexByName(VarDeclaration
*v
)
67 ClassDeclaration
*cd
= originalClass();
68 size_t fieldsSoFar
= 0;
69 for (size_t j
= 0; j
< value
->elements
->length
; j
++)
71 while (j
- fieldsSoFar
>= cd
->fields
.length
)
73 fieldsSoFar
+= cd
->fields
.length
;
76 VarDeclaration
*v2
= cd
->fields
[j
- fieldsSoFar
];
79 return (int)(value
->elements
->length
- fieldsSoFar
- cd
->fields
.length
+ (j
-fieldsSoFar
));
85 /************** VoidInitExp ********************************************/
87 VoidInitExp::VoidInitExp(VarDeclaration
*var
, Type
*)
88 : Expression(var
->loc
, TOKvoid
, sizeof(VoidInitExp
))
91 this->type
= var
->type
;
94 const char *VoidInitExp::toChars()
99 // Return index of the field, or -1 if not found
100 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
101 int findFieldIndexByName(StructDeclaration
*sd
, VarDeclaration
*v
)
103 for (size_t i
= 0; i
< sd
->fields
.length
; ++i
)
105 if (sd
->fields
[i
] == v
)
111 /************** ThrownExceptionExp ********************************************/
113 ThrownExceptionExp::ThrownExceptionExp(Loc loc
, ClassReferenceExp
*victim
) : Expression(loc
, TOKthrownexception
, sizeof(ThrownExceptionExp
))
115 this->thrown
= victim
;
116 this->type
= victim
->type
;
119 const char *ThrownExceptionExp::toChars()
121 return "CTFE ThrownException";
124 // Generate an error message when this exception is not caught
125 void ThrownExceptionExp::generateUncaughtError()
128 Expression
*e
= resolveSlice((*thrown
->value
->elements
)[0], &ue
);
129 StringExp
*se
= e
->toStringExp();
130 thrown
->error("uncaught CTFE exception %s(%s)", thrown
->type
->toChars(), se
? se
->toChars() : e
->toChars());
132 /* Also give the line where the throw statement was. We won't have it
133 * in the case where the ThrowStatement is generated internally
134 * (eg, in ScopeStatement)
136 if (loc
.filename
&& !loc
.equals(thrown
->loc
))
137 errorSupplemental(loc
, "thrown from here");
140 // True if 'e' is CTFEExp::cantexp, or an exception
141 bool exceptionOrCantInterpret(Expression
*e
)
143 return e
&& (e
->op
== TOKcantexp
|| e
->op
== TOKthrownexception
);
146 /********************** CTFEExp ******************************************/
148 CTFEExp
*CTFEExp::cantexp
;
149 CTFEExp
*CTFEExp::voidexp
;
150 CTFEExp
*CTFEExp::breakexp
;
151 CTFEExp
*CTFEExp::continueexp
;
152 CTFEExp
*CTFEExp::gotoexp
;
154 CTFEExp::CTFEExp(TOK tok
)
155 : Expression(Loc(), tok
, sizeof(CTFEExp
))
160 const char *CTFEExp::toChars()
164 case TOKcantexp
: return "<cant>";
165 case TOKvoidexp
: return "<void>";
166 case TOKbreak
: return "<break>";
167 case TOKcontinue
: return "<continue>";
168 case TOKgoto
: return "<goto>";
169 default: assert(0); return NULL
;
173 Expression
*UnionExp::copy()
175 Expression
*e
= exp();
176 //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op));
177 assert(e
->size
<= sizeof(u
));
178 if (e
->op
== TOKcantexp
) return CTFEExp::cantexp
;
179 if (e
->op
== TOKvoidexp
) return CTFEExp::voidexp
;
180 if (e
->op
== TOKbreak
) return CTFEExp::breakexp
;
181 if (e
->op
== TOKcontinue
) return CTFEExp::continueexp
;
182 if (e
->op
== TOKgoto
) return CTFEExp::gotoexp
;
186 /************** Aggregate literals (AA/string/array/struct) ******************/
188 // Given expr, which evaluates to an array/AA/string literal,
189 // return true if it needs to be copied
190 bool needToCopyLiteral(Expression
*expr
)
196 case TOKarrayliteral
:
197 return ((ArrayLiteralExp
*)expr
)->ownedByCtfe
== OWNEDcode
;
198 case TOKassocarrayliteral
:
199 return ((AssocArrayLiteralExp
*)expr
)->ownedByCtfe
== OWNEDcode
;
200 case TOKstructliteral
:
201 return ((StructLiteralExp
*)expr
)->ownedByCtfe
== OWNEDcode
;
212 expr
= ((UnaExp
*)expr
)->e1
;
215 return needToCopyLiteral(((BinExp
*)expr
)->e1
) ||
216 needToCopyLiteral(((BinExp
*)expr
)->e2
);
218 expr
= ((BinExp
*)expr
)->e2
;
226 Expressions
*copyLiteralArray(Expressions
*oldelems
, Expression
*basis
= NULL
)
230 CtfeStatus::numArrayAllocs
++;
231 Expressions
*newelems
= new Expressions();
232 newelems
->setDim(oldelems
->length
);
233 for (size_t i
= 0; i
< oldelems
->length
; i
++)
235 Expression
*el
= (*oldelems
)[i
];
238 (*newelems
)[i
] = copyLiteral(el
).copy();
243 // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
244 // This value will be used for in-place modification.
245 UnionExp
copyLiteral(Expression
*e
)
248 if (e
->op
== TOKstring
) // syntaxCopy doesn't make a copy for StringExp!
250 StringExp
*se
= (StringExp
*)e
;
251 utf8_t
*s
= (utf8_t
*)mem
.xcalloc(se
->len
+ 1, se
->sz
);
252 memcpy(s
, se
->string
, se
->len
* se
->sz
);
253 new(&ue
) StringExp(se
->loc
, s
, se
->len
);
254 StringExp
*se2
= (StringExp
*)ue
.exp();
255 se2
->committed
= se
->committed
;
256 se2
->postfix
= se
->postfix
;
257 se2
->type
= se
->type
;
259 se2
->ownedByCtfe
= OWNEDctfe
;
262 if (e
->op
== TOKarrayliteral
)
264 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)e
;
265 Expressions
*elements
= copyLiteralArray(ale
->elements
, ale
->basis
);
267 new(&ue
) ArrayLiteralExp(e
->loc
, e
->type
, elements
);
269 ArrayLiteralExp
*r
= (ArrayLiteralExp
*)ue
.exp();
270 r
->ownedByCtfe
= OWNEDctfe
;
273 if (e
->op
== TOKassocarrayliteral
)
275 AssocArrayLiteralExp
*aae
= (AssocArrayLiteralExp
*)e
;
276 new(&ue
) AssocArrayLiteralExp(e
->loc
, copyLiteralArray(aae
->keys
), copyLiteralArray(aae
->values
));
277 AssocArrayLiteralExp
*r
= (AssocArrayLiteralExp
*)ue
.exp();
279 r
->ownedByCtfe
= OWNEDctfe
;
282 if (e
->op
== TOKstructliteral
)
284 /* syntaxCopy doesn't work for struct literals, because of a nasty special
285 * case: block assignment is permitted inside struct literals, eg,
286 * an int[4] array can be initialized with a single int.
288 StructLiteralExp
*sle
= (StructLiteralExp
*)e
;
289 Expressions
*oldelems
= sle
->elements
;
290 Expressions
* newelems
= new Expressions();
291 newelems
->setDim(oldelems
->length
);
292 for (size_t i
= 0; i
< newelems
->length
; i
++)
294 // We need the struct definition to detect block assignment
295 VarDeclaration
*v
= sle
->sd
->fields
[i
];
296 Expression
*m
= (*oldelems
)[i
];
298 // If it is a void assignment, use the default initializer
300 m
= voidInitLiteral(v
->type
, v
).copy();
302 if (v
->type
->ty
== Tarray
|| v
->type
->ty
== Taarray
)
304 // Don't have to copy array references
308 // Buzilla 15681: Copy the source element always.
309 m
= copyLiteral(m
).copy();
311 // Block assignment from inside struct literals
312 if (v
->type
->ty
!= m
->type
->ty
&& v
->type
->ty
== Tsarray
)
314 TypeSArray
*tsa
= (TypeSArray
*)v
->type
;
315 size_t len
= (size_t)tsa
->dim
->toInteger();
317 m
= createBlockDuplicatedArrayLiteral(&uex
, e
->loc
, v
->type
, m
, len
);
324 new(&ue
) StructLiteralExp(e
->loc
, sle
->sd
, newelems
, sle
->stype
);
325 StructLiteralExp
*r
= (StructLiteralExp
*)ue
.exp();
327 r
->ownedByCtfe
= OWNEDctfe
;
328 r
->origin
= ((StructLiteralExp
*)e
)->origin
;
331 if (e
->op
== TOKfunction
|| e
->op
== TOKdelegate
||
332 e
->op
== TOKsymoff
|| e
->op
== TOKnull
||
333 e
->op
== TOKvar
|| e
->op
== TOKdotvar
||
334 e
->op
== TOKint64
|| e
->op
== TOKfloat64
||
335 e
->op
== TOKchar
|| e
->op
== TOKcomplex80
||
336 e
->op
== TOKvoid
|| e
->op
== TOKvector
||
339 // Simple value types
340 // Keep e1 for DelegateExp and DotVarExp
341 new(&ue
) UnionExp(e
);
342 Expression
*r
= ue
.exp();
346 if (e
->op
== TOKslice
)
348 SliceExp
*se
= (SliceExp
*)e
;
349 if (se
->type
->toBasetype()->ty
== Tsarray
)
351 // same with resolveSlice()
352 if (se
->e1
->op
== TOKnull
)
354 new(&ue
) NullExp(se
->loc
, se
->type
);
357 ue
= Slice(se
->type
, se
->e1
, se
->lwr
, se
->upr
);
358 assert(ue
.exp()->op
== TOKarrayliteral
);
359 ArrayLiteralExp
*r
= (ArrayLiteralExp
*)ue
.exp();
360 r
->elements
= copyLiteralArray(r
->elements
);
361 r
->ownedByCtfe
= OWNEDctfe
;
366 // Array slices only do a shallow copy
367 new(&ue
) SliceExp(e
->loc
, se
->e1
, se
->lwr
, se
->upr
);
368 Expression
*r
= ue
.exp();
373 if (isPointer(e
->type
))
375 // For pointers, we only do a shallow copy.
376 if (e
->op
== TOKaddress
)
377 new(&ue
) AddrExp(e
->loc
, ((AddrExp
*)e
)->e1
);
378 else if (e
->op
== TOKindex
)
379 new(&ue
) IndexExp(e
->loc
, ((IndexExp
*)e
)->e1
, ((IndexExp
*)e
)->e2
);
380 else if (e
->op
== TOKdotvar
)
382 new(&ue
) DotVarExp(e
->loc
, ((DotVarExp
*)e
)->e1
,
383 ((DotVarExp
*)e
)->var
, ((DotVarExp
*)e
)->hasOverloads
);
387 Expression
*r
= ue
.exp();
391 if (e
->op
== TOKclassreference
)
393 new(&ue
) ClassReferenceExp(e
->loc
, ((ClassReferenceExp
*)e
)->value
, e
->type
);
396 if (e
->op
== TOKerror
)
398 new(&ue
) UnionExp(e
);
401 e
->error("CTFE internal error: literal %s", e
->toChars());
406 /* Deal with type painting.
407 * Type painting is a major nuisance: we can't just set
408 * e->type = type, because that would change the original literal.
409 * But, we can't simply copy the literal either, because that would change
410 * the values of any pointers.
412 Expression
*paintTypeOntoLiteral(Type
*type
, Expression
*lit
)
414 if (lit
->type
->equals(type
))
416 return paintTypeOntoLiteralCopy(type
, lit
).copy();
419 Expression
*paintTypeOntoLiteral(UnionExp
*pue
, Type
*type
, Expression
*lit
)
421 if (lit
->type
->equals(type
))
423 *pue
= paintTypeOntoLiteralCopy(type
, lit
);
427 UnionExp
paintTypeOntoLiteralCopy(Type
*type
, Expression
*lit
)
431 if (lit
->type
->equals(type
))
433 new(&ue
) UnionExp(lit
);
437 // If it is a cast to inout, retain the original type of the referenced part.
438 if (type
->hasWild() && type
->hasPointers())
440 new(&ue
) UnionExp(lit
);
441 ue
.exp()->type
= type
;
445 if (lit
->op
== TOKslice
)
447 SliceExp
*se
= (SliceExp
*)lit
;
448 new(&ue
) SliceExp(lit
->loc
, se
->e1
, se
->lwr
, se
->upr
);
450 else if (lit
->op
== TOKindex
)
452 IndexExp
*ie
= (IndexExp
*)lit
;
453 new(&ue
) IndexExp(lit
->loc
, ie
->e1
, ie
->e2
);
455 else if (lit
->op
== TOKarrayliteral
)
457 new(&ue
) SliceExp(lit
->loc
, lit
,
458 new IntegerExp(Loc(), 0, Type::tsize_t
), ArrayLength(Type::tsize_t
, lit
).copy());
460 else if (lit
->op
== TOKstring
)
462 // For strings, we need to introduce another level of indirection
463 new(&ue
) SliceExp(lit
->loc
, lit
,
464 new IntegerExp(Loc(), 0, Type::tsize_t
), ArrayLength(Type::tsize_t
, lit
).copy());
466 else if (lit
->op
== TOKassocarrayliteral
)
468 AssocArrayLiteralExp
*aae
= (AssocArrayLiteralExp
*)lit
;
469 // TODO: we should be creating a reference to this AAExp, not
470 // just a ref to the keys and values.
471 OwnedBy wasOwned
= aae
->ownedByCtfe
;
472 new(&ue
) AssocArrayLiteralExp(lit
->loc
, aae
->keys
, aae
->values
);
473 aae
= (AssocArrayLiteralExp
*)ue
.exp();
474 aae
->ownedByCtfe
= wasOwned
;
478 // Can't type paint from struct to struct*; this needs another
479 // level of indirection
480 if (lit
->op
== TOKstructliteral
&& isPointer(type
))
481 lit
->error("CTFE internal error: painting %s", type
->toChars());
482 ue
= copyLiteral(lit
);
484 ue
.exp()->type
= type
;
488 /*************************************
489 * If e is a SliceExp, constant fold it.
491 * e = expression to resolve
492 * pue = if not null, store resulting expression here
494 * resulting expression
496 Expression
*resolveSlice(Expression
*e
, UnionExp
*pue
)
498 if (e
->op
!= TOKslice
)
500 SliceExp
*se
= (SliceExp
*)e
;
501 if (se
->e1
->op
== TOKnull
)
505 *pue
= Slice(e
->type
, se
->e1
, se
->lwr
, se
->upr
);
509 return Slice(e
->type
, se
->e1
, se
->lwr
, se
->upr
).copy();
512 /* Determine the array length, without interpreting it.
513 * e must be an array literal, or a slice
514 * It's very wasteful to resolve the slice when we only
517 uinteger_t
resolveArrayLength(Expression
*e
)
519 if (e
->op
== TOKvector
)
520 return ((VectorExp
*)e
)->dim
;
522 if (e
->op
== TOKnull
)
524 if (e
->op
== TOKslice
)
526 uinteger_t ilo
= ((SliceExp
*)e
)->lwr
->toInteger();
527 uinteger_t iup
= ((SliceExp
*)e
)->upr
->toInteger();
530 if (e
->op
== TOKstring
)
532 return ((StringExp
*)e
)->len
;
534 if (e
->op
== TOKarrayliteral
)
536 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)e
;
537 return ale
->elements
? ale
->elements
->length
: 0;
539 if (e
->op
== TOKassocarrayliteral
)
541 AssocArrayLiteralExp
*ale
= (AssocArrayLiteralExp
*)e
;
542 return ale
->keys
->length
;
548 /******************************
550 * Create an array literal consisting of 'elem' duplicated 'dim' times.
552 * pue = where to store result
553 * loc = source location where the interpretation occurs
554 * type = target type of the result
555 * elem = the source of array element, it will be owned by the result
556 * dim = element number of the result
558 * Constructed ArrayLiteralExp
560 ArrayLiteralExp
*createBlockDuplicatedArrayLiteral(UnionExp
*pue
, Loc loc
, Type
*type
,
561 Expression
*elem
, size_t dim
)
563 if (type
->ty
== Tsarray
&& type
->nextOf()->ty
== Tsarray
&& elem
->type
->ty
!= Tsarray
)
565 // If it is a multidimensional array literal, do it recursively
566 TypeSArray
*tsa
= (TypeSArray
*)type
->nextOf();
567 size_t len
= (size_t)tsa
->dim
->toInteger();
569 elem
= createBlockDuplicatedArrayLiteral(&ue
, loc
, type
->nextOf(), elem
, len
);
570 if (elem
== ue
.exp())
575 Type
*tb
= elem
->type
->toBasetype();
576 const bool mustCopy
= tb
->ty
== Tstruct
|| tb
->ty
== Tsarray
;
578 Expressions
*elements
= new Expressions();
579 elements
->setDim(dim
);
580 for (size_t i
= 0; i
< dim
; i
++)
582 (*elements
)[i
] = mustCopy
? copyLiteral(elem
).copy() : elem
;
584 new(pue
) ArrayLiteralExp(loc
, type
, elements
);
585 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)pue
->exp();
586 ale
->ownedByCtfe
= OWNEDctfe
;
590 /******************************
592 * Create a string literal consisting of 'value' duplicated 'dim' times.
594 StringExp
*createBlockDuplicatedStringLiteral(UnionExp
*pue
, Loc loc
, Type
*type
,
595 unsigned value
, size_t dim
, unsigned char sz
)
597 utf8_t
*s
= (utf8_t
*)mem
.xcalloc(dim
+ 1, sz
);
598 for (size_t elemi
= 0; elemi
< dim
; ++elemi
)
602 case 1: s
[elemi
] = (utf8_t
)value
; break;
603 case 2: ((unsigned short *)s
)[elemi
] = (unsigned short)value
; break;
604 case 4: ((unsigned *)s
)[elemi
] = value
; break;
608 new(pue
) StringExp(loc
, s
, dim
);
609 StringExp
*se
= (StringExp
*)pue
->exp();
612 se
->committed
= true;
613 se
->ownedByCtfe
= OWNEDctfe
;
617 // Return true if t is an AA
618 bool isAssocArray(Type
*t
)
621 if (t
->ty
== Taarray
)
626 // Given a template AA type, extract the corresponding built-in AA type
627 TypeAArray
*toBuiltinAAType(Type
*t
)
630 if (t
->ty
== Taarray
)
631 return (TypeAArray
*)t
;
636 /************** TypeInfo operations ************************************/
638 // Return true if type is TypeInfo_Class
639 bool isTypeInfo_Class(Type
*type
)
641 return type
->ty
== Tclass
&&
642 (Type::dtypeinfo
== ((TypeClass
*)type
)->sym
||
643 Type::dtypeinfo
->isBaseOf(((TypeClass
*)type
)->sym
, NULL
));
646 /************** Pointer operations ************************************/
648 // Return true if t is a pointer (not a function pointer)
649 bool isPointer(Type
*t
)
651 Type
* tb
= t
->toBasetype();
652 return tb
->ty
== Tpointer
&& tb
->nextOf()->ty
!= Tfunction
;
655 // For CTFE only. Returns true if 'e' is true or a non-null pointer.
656 bool isTrueBool(Expression
*e
)
658 return e
->isBool(true) ||
659 ((e
->type
->ty
== Tpointer
|| e
->type
->ty
== Tclass
) && e
->op
!= TOKnull
);
662 /* Is it safe to convert from srcPointee* to destPointee* ?
663 * srcPointee is the genuine type (never void).
664 * destPointee may be void.
666 bool isSafePointerCast(Type
*srcPointee
, Type
*destPointee
)
668 // It's safe to cast S** to D** if it's OK to cast S* to D*
669 while (srcPointee
->ty
== Tpointer
&& destPointee
->ty
== Tpointer
)
671 srcPointee
= srcPointee
->nextOf();
672 destPointee
= destPointee
->nextOf();
675 // It's OK if both are the same (modulo const)
676 if (srcPointee
->constConv(destPointee
))
679 // It's OK if function pointers differ only in safe/pure/nothrow
680 if (srcPointee
->ty
== Tfunction
&& destPointee
->ty
== Tfunction
)
681 return srcPointee
->covariant(destPointee
) == 1;
683 // it's OK to cast to void*
684 if (destPointee
->ty
== Tvoid
)
687 // It's OK to cast from V[K] to void*
688 if (srcPointee
->ty
== Taarray
&& destPointee
== Type::tvoidptr
)
691 // It's OK if they are the same size (static array of) integers, eg:
693 // int[5][] --> uint[5][]
694 if (srcPointee
->ty
== Tsarray
&& destPointee
->ty
== Tsarray
)
696 if (srcPointee
->size() != destPointee
->size())
698 srcPointee
= srcPointee
->baseElemOf();
699 destPointee
= destPointee
->baseElemOf();
701 return srcPointee
->isintegral() &&
702 destPointee
->isintegral() &&
703 srcPointee
->size() == destPointee
->size();
706 Expression
*getAggregateFromPointer(Expression
*e
, dinteger_t
*ofs
)
709 if (e
->op
== TOKaddress
)
710 e
= ((AddrExp
*)e
)->e1
;
711 if (e
->op
== TOKsymoff
)
712 *ofs
= ((SymOffExp
*)e
)->offset
;
713 if (e
->op
== TOKdotvar
)
715 Expression
*ex
= ((DotVarExp
*)e
)->e1
;
716 VarDeclaration
*v
= ((DotVarExp
*)e
)->var
->isVarDeclaration();
718 StructLiteralExp
*se
= ex
->op
== TOKclassreference
? ((ClassReferenceExp
*)ex
)->value
: (StructLiteralExp
*)ex
;
719 // We can't use getField, because it makes a copy
721 if (ex
->op
== TOKclassreference
)
722 i
= ((ClassReferenceExp
*)ex
)->getFieldIndex(e
->type
, v
->offset
);
724 i
= se
->getFieldIndex(e
->type
, v
->offset
);
725 e
= (*se
->elements
)[i
];
727 if (e
->op
== TOKindex
)
729 IndexExp
*ie
= (IndexExp
*)e
;
730 // Note that each AA element is part of its own memory block
731 if ((ie
->e1
->type
->ty
== Tarray
||
732 ie
->e1
->type
->ty
== Tsarray
||
733 ie
->e1
->op
== TOKstring
||
734 ie
->e1
->op
== TOKarrayliteral
) &&
735 ie
->e2
->op
== TOKint64
)
737 *ofs
= ie
->e2
->toInteger();
741 if (e
->op
== TOKslice
&& e
->type
->toBasetype()->ty
== Tsarray
)
743 SliceExp
*se
= (SliceExp
*)e
;
744 if ((se
->e1
->type
->ty
== Tarray
||
745 se
->e1
->type
->ty
== Tsarray
||
746 se
->e1
->op
== TOKstring
||
747 se
->e1
->op
== TOKarrayliteral
) &&
748 se
->lwr
->op
== TOKint64
)
750 *ofs
= se
->lwr
->toInteger();
757 /** Return true if agg1 and agg2 are pointers to the same memory block
759 bool pointToSameMemoryBlock(Expression
*agg1
, Expression
*agg2
)
764 // For integers cast to pointers, we regard them as non-comparable
765 // unless they are identical. (This may be overly strict).
766 if (agg1
->op
== TOKint64
&& agg2
->op
== TOKint64
&&
767 agg1
->toInteger() == agg2
->toInteger())
772 // Note that type painting can occur with VarExp, so we
773 // must compare the variables being pointed to.
774 if (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
775 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
)
779 if (agg1
->op
== TOKsymoff
&& agg2
->op
== TOKsymoff
&&
780 ((SymOffExp
*)agg1
)->var
== ((SymOffExp
*)agg2
)->var
)
788 // return e1 - e2 as an integer, or error if not possible
789 UnionExp
pointerDifference(Loc loc
, Type
*type
, Expression
*e1
, Expression
*e2
)
792 dinteger_t ofs1
, ofs2
;
793 Expression
*agg1
= getAggregateFromPointer(e1
, &ofs1
);
794 Expression
*agg2
= getAggregateFromPointer(e2
, &ofs2
);
797 Type
*pointee
= ((TypePointer
*)agg1
->type
)->next
;
798 dinteger_t sz
= pointee
->size();
799 new(&ue
) IntegerExp(loc
, (ofs1
- ofs2
) * sz
, type
);
801 else if (agg1
->op
== TOKstring
&& agg2
->op
== TOKstring
)
803 if (((StringExp
*)agg1
)->string
== ((StringExp
*)agg2
)->string
)
805 Type
*pointee
= ((TypePointer
*)agg1
->type
)->next
;
806 dinteger_t sz
= pointee
->size();
807 new(&ue
) IntegerExp(loc
, (ofs1
- ofs2
) * sz
, type
);
810 else if (agg1
->op
== TOKsymoff
&& agg2
->op
== TOKsymoff
&&
811 ((SymOffExp
*)agg1
)->var
== ((SymOffExp
*)agg2
)->var
)
813 new(&ue
) IntegerExp(loc
, ofs1
- ofs2
, type
);
817 error(loc
, "%s - %s cannot be interpreted at compile time: cannot subtract "
818 "pointers to two different memory blocks",
819 e1
->toChars(), e2
->toChars());
820 new(&ue
) CTFEExp(TOKcantexp
);
825 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
826 // and op is TOKadd or TOKmin
827 UnionExp
pointerArithmetic(Loc loc
, TOK op
, Type
*type
,
828 Expression
*eptr
, Expression
*e2
)
832 if (eptr
->type
->nextOf()->ty
== Tvoid
)
834 error(loc
, "cannot perform arithmetic on void* pointers at compile time");
836 new(&ue
) CTFEExp(TOKcantexp
);
841 if (eptr
->op
== TOKaddress
)
842 eptr
= ((AddrExp
*)eptr
)->e1
;
843 Expression
*agg1
= getAggregateFromPointer(eptr
, &ofs1
);
844 if (agg1
->op
== TOKsymoff
)
846 if (((SymOffExp
*)agg1
)->var
->type
->ty
!= Tsarray
)
848 error(loc
, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
852 else if (agg1
->op
!= TOKstring
&& agg1
->op
!= TOKarrayliteral
)
854 error(loc
, "cannot perform pointer arithmetic on non-arrays at compile time");
857 dinteger_t ofs2
= e2
->toInteger();
859 Type
*pointee
= ((TypeNext
*)agg1
->type
->toBasetype())->next
;
860 dinteger_t sz
= pointee
->size();
864 if (agg1
->op
== TOKsymoff
)
867 len
= ((TypeSArray
*)((SymOffExp
*)agg1
)->var
->type
)->dim
->toInteger();
871 Expression
*dollar
= ArrayLength(Type::tsize_t
, agg1
).copy();
872 assert(!CTFEExp::isCantExp(dollar
));
874 len
= dollar
->toInteger();
876 if (op
== TOKadd
|| op
== TOKaddass
|| op
== TOKplusplus
)
878 else if (op
== TOKmin
|| op
== TOKminass
|| op
== TOKminusminus
)
882 error(loc
, "CTFE internal error: bad pointer operation");
886 if (indx
< 0 || len
< (dinteger_t
)indx
)
888 error(loc
, "cannot assign pointer to index %lld inside memory block [0..%lld]", (ulonglong
)indx
, (ulonglong
)len
);
892 if (agg1
->op
== TOKsymoff
)
894 new(&ue
) SymOffExp(loc
, ((SymOffExp
*)agg1
)->var
, indx
* sz
);
895 SymOffExp
*se
= (SymOffExp
*)ue
.exp();
900 if (agg1
->op
!= TOKarrayliteral
&& agg1
->op
!= TOKstring
)
902 error(loc
, "CTFE internal error: pointer arithmetic %s", agg1
->toChars());
906 if (eptr
->type
->toBasetype()->ty
== Tsarray
)
908 dinteger_t dim
= ((TypeSArray
*)eptr
->type
->toBasetype())->dim
->toInteger();
910 // Create a CTFE pointer &agg1[indx .. indx+dim]
911 SliceExp
*se
= new SliceExp(loc
, agg1
,
912 new IntegerExp(loc
, indx
, Type::tsize_t
),
913 new IntegerExp(loc
, indx
+ dim
, Type::tsize_t
));
914 se
->type
= type
->toBasetype()->nextOf();
915 new(&ue
) AddrExp(loc
, se
);
916 ue
.exp()->type
= type
;
920 // Create a CTFE pointer &agg1[indx]
921 IntegerExp
*ofs
= new IntegerExp(loc
, indx
, Type::tsize_t
);
922 Expression
*ie
= new IndexExp(loc
, agg1
, ofs
);
923 ie
->type
= type
->toBasetype()->nextOf(); // Bugzilla 13992
924 new(&ue
) AddrExp(loc
, ie
);
925 ue
.exp()->type
= type
;
929 // Return 1 if true, 0 if false
930 // -1 if comparison is illegal because they point to non-comparable memory blocks
931 int comparePointers(TOK op
, Expression
*agg1
, dinteger_t ofs1
, Expression
*agg2
, dinteger_t ofs2
)
933 if (pointToSameMemoryBlock(agg1
, agg2
))
938 case TOKlt
: n
= (ofs1
< ofs2
); break;
939 case TOKle
: n
= (ofs1
<= ofs2
); break;
940 case TOKgt
: n
= (ofs1
> ofs2
); break;
941 case TOKge
: n
= (ofs1
>= ofs2
); break;
943 case TOKequal
: n
= (ofs1
== ofs2
); break;
945 case TOKnotequal
: n
= (ofs1
!= ofs2
); break;
951 bool null1
= (agg1
->op
== TOKnull
);
952 bool null2
= (agg2
->op
== TOKnull
);
959 case TOKlt
: cmp
= null1
&& !null2
; break;
960 case TOKgt
: cmp
= !null1
&& null2
; break;
961 case TOKle
: cmp
= null1
; break;
962 case TOKge
: cmp
= null2
; break;
965 case TOKnotidentity
: // 'cmp' gets inverted below
967 cmp
= (null1
== null2
);
979 case TOKnotidentity
: // 'cmp' gets inverted below
984 return -1; // memory blocks are different
987 if (op
== TOKnotidentity
|| op
== TOKnotequal
)
992 // True if conversion from type 'from' to 'to' involves a reinterpret_cast
993 // floating point -> integer or integer -> floating point
994 bool isFloatIntPaint(Type
*to
, Type
*from
)
996 return from
->size() == to
->size() &&
997 ((from
->isintegral() && to
->isfloating()) ||
998 (from
->isfloating() && to
->isintegral()));
1001 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
1002 Expression
*paintFloatInt(UnionExp
*pue
, Expression
*fromVal
, Type
*to
)
1004 if (exceptionOrCantInterpret(fromVal
))
1007 assert(to
->size() == 4 || to
->size() == 8);
1008 return Compiler::paintAsType(pue
, fromVal
, to
);
1011 /******** Constant folding, with support for CTFE ***************************/
1013 /// Return true if non-pointer expression e can be compared
1014 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
1015 bool isCtfeComparable(Expression
*e
)
1017 if (e
->op
== TOKslice
)
1018 e
= ((SliceExp
*)e
)->e1
;
1020 if (e
->isConst() != 1)
1022 if (e
->op
== TOKnull
||
1023 e
->op
== TOKstring
||
1024 e
->op
== TOKfunction
||
1025 e
->op
== TOKdelegate
||
1026 e
->op
== TOKarrayliteral
||
1027 e
->op
== TOKstructliteral
||
1028 e
->op
== TOKassocarrayliteral
||
1029 e
->op
== TOKclassreference
)
1033 // Bugzilla 14123: TypeInfo object is comparable in CTFE
1034 if (e
->op
== TOKtypeid
)
1042 /// Map TOK comparison ops
1043 template <typename N
>
1044 static bool numCmp(TOK op
, N n1
, N n2
)
1063 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1064 int specificCmp(TOK op
, int rawCmp
)
1066 return numCmp
<int>(op
, rawCmp
, 0);
1069 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1070 int intUnsignedCmp(TOK op
, dinteger_t n1
, dinteger_t n2
)
1072 return numCmp
<dinteger_t
>(op
, n1
, n2
);
1075 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1076 int intSignedCmp(TOK op
, sinteger_t n1
, sinteger_t n2
)
1078 return numCmp
<sinteger_t
>(op
, n1
, n2
);
1081 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1082 int realCmp(TOK op
, real_t r1
, real_t r2
)
1084 // Don't rely on compiler, handle NAN arguments separately
1085 if (CTFloat::isNaN(r1
) || CTFloat::isNaN(r2
)) // if unordered
1102 return numCmp
<real_t
>(op
, r1
, r2
);
1106 int ctfeRawCmp(Loc loc
, Expression
*e1
, Expression
*e2
);
1108 /* Conceptually the same as memcmp(e1, e2).
1109 * e1 and e2 may be strings, arrayliterals, or slices.
1110 * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1111 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1113 int ctfeCmpArrays(Loc loc
, Expression
*e1
, Expression
*e2
, uinteger_t len
)
1115 // Resolve slices, if necessary
1120 if (x
->op
== TOKslice
)
1122 lo1
= ((SliceExp
*)x
)->lwr
->toInteger();
1123 x
= ((SliceExp
*)x
)->e1
;
1125 StringExp
*se1
= (x
->op
== TOKstring
) ? (StringExp
*)x
: NULL
;
1126 ArrayLiteralExp
*ae1
= (x
->op
== TOKarrayliteral
) ? (ArrayLiteralExp
*)x
: NULL
;
1129 if (x
->op
== TOKslice
)
1131 lo2
= ((SliceExp
*)x
)->lwr
->toInteger();
1132 x
= ((SliceExp
*)x
)->e1
;
1134 StringExp
*se2
= (x
->op
== TOKstring
) ? (StringExp
*)x
: NULL
;
1135 ArrayLiteralExp
*ae2
= (x
->op
== TOKarrayliteral
) ? (ArrayLiteralExp
*)x
: NULL
;
1137 // Now both must be either TOKarrayliteral or TOKstring
1139 return sliceCmpStringWithString(se1
, se2
, (size_t)lo1
, (size_t)lo2
, (size_t)len
);
1141 return sliceCmpStringWithArray(se1
, ae2
, (size_t)lo1
, (size_t)lo2
, (size_t)len
);
1143 return -sliceCmpStringWithArray(se2
, ae1
, (size_t)lo2
, (size_t)lo1
, (size_t)len
);
1145 assert (ae1
&& ae2
);
1146 // Comparing two array literals. This case is potentially recursive.
1147 // If they aren't strings, we just need an equality check rather than
1149 bool needCmp
= ae1
->type
->nextOf()->isintegral();
1150 for (size_t i
= 0; i
< (size_t)len
; i
++)
1152 Expression
*ee1
= (*ae1
->elements
)[(size_t)(lo1
+ i
)];
1153 Expression
*ee2
= (*ae2
->elements
)[(size_t)(lo2
+ i
)];
1156 sinteger_t c
= ee1
->toInteger() - ee2
->toInteger();
1164 if (ctfeRawCmp(loc
, ee1
, ee2
))
1171 /* Given a delegate expression e, return .funcptr.
1172 * If e is NullExp, return NULL.
1174 FuncDeclaration
*funcptrOf(Expression
*e
)
1176 assert(e
->type
->ty
== Tdelegate
);
1178 if (e
->op
== TOKdelegate
)
1179 return ((DelegateExp
*)e
)->func
;
1180 if (e
->op
== TOKfunction
)
1181 return ((FuncExp
*)e
)->fd
;
1182 assert(e
->op
== TOKnull
);
1186 bool isArray(Expression
*e
)
1188 return e
->op
== TOKarrayliteral
|| e
->op
== TOKstring
||
1189 e
->op
== TOKslice
|| e
->op
== TOKnull
;
1192 /* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1193 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1195 int ctfeRawCmp(Loc loc
, Expression
*e1
, Expression
*e2
)
1197 if (e1
->op
== TOKclassreference
|| e2
->op
== TOKclassreference
)
1199 if (e1
->op
== TOKclassreference
&& e2
->op
== TOKclassreference
&&
1200 ((ClassReferenceExp
*)e1
)->value
== ((ClassReferenceExp
*)e2
)->value
)
1204 if (e1
->op
== TOKtypeid
&& e2
->op
== TOKtypeid
)
1206 // printf("e1: %s\n", e1->toChars());
1207 // printf("e2: %s\n", e2->toChars());
1208 Type
*t1
= isType(((TypeidExp
*)e1
)->obj
);
1209 Type
*t2
= isType(((TypeidExp
*)e2
)->obj
);
1215 // null == null, regardless of type
1217 if (e1
->op
== TOKnull
&& e2
->op
== TOKnull
)
1220 if (e1
->type
->ty
== Tpointer
&& e2
->type
->ty
== Tpointer
)
1222 // Can only be an equality test.
1224 dinteger_t ofs1
, ofs2
;
1225 Expression
*agg1
= getAggregateFromPointer(e1
, &ofs1
);
1226 Expression
*agg2
= getAggregateFromPointer(e2
, &ofs2
);
1227 if ((agg1
== agg2
) || (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
1228 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
))
1235 if (e1
->type
->ty
== Tdelegate
&& e2
->type
->ty
== Tdelegate
)
1237 // If .funcptr isn't the same, they are not equal
1239 if (funcptrOf(e1
) != funcptrOf(e2
))
1242 // If both are delegate literals, assume they have the
1243 // same closure pointer. TODO: We don't support closures yet!
1244 if (e1
->op
== TOKfunction
&& e2
->op
== TOKfunction
)
1246 assert(e1
->op
== TOKdelegate
&& e2
->op
== TOKdelegate
);
1248 // Same .funcptr. Do they have the same .ptr?
1249 Expression
* ptr1
= ((DelegateExp
*)e1
)->e1
;
1250 Expression
* ptr2
= ((DelegateExp
*)e2
)->e1
;
1252 dinteger_t ofs1
, ofs2
;
1253 Expression
*agg1
= getAggregateFromPointer(ptr1
, &ofs1
);
1254 Expression
*agg2
= getAggregateFromPointer(ptr2
, &ofs2
);
1255 // If they are TOKvar, it means they are FuncDeclarations
1256 if ((agg1
== agg2
&& ofs1
== ofs2
) ||
1257 (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
1258 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
))
1264 if (isArray(e1
) && isArray(e2
))
1266 uinteger_t len1
= resolveArrayLength(e1
);
1267 uinteger_t len2
= resolveArrayLength(e2
);
1268 // workaround for dmc optimizer bug calculating wrong len for
1269 // uinteger_t len = (len1 < len2 ? len1 : len2);
1270 // if (len == 0) ...
1271 if (len1
> 0 && len2
> 0)
1273 uinteger_t len
= (len1
< len2
? len1
: len2
);
1274 int res
= ctfeCmpArrays(loc
, e1
, e2
, len
);
1278 return (int)(len1
- len2
);
1280 if (e1
->type
->isintegral())
1282 return e1
->toInteger() != e2
->toInteger();
1286 if (e1
->type
->isreal())
1292 else if (e1
->type
->isimaginary())
1294 r1
= e1
->toImaginary();
1295 r2
= e2
->toImaginary();
1297 if (CTFloat::isNaN(r1
) || CTFloat::isNaN(r2
)) // if unordered
1306 else if (e1
->type
->iscomplex())
1308 return e1
->toComplex() != e2
->toComplex();
1311 if (e1
->op
== TOKstructliteral
&& e2
->op
== TOKstructliteral
)
1313 StructLiteralExp
*es1
= (StructLiteralExp
*)e1
;
1314 StructLiteralExp
*es2
= (StructLiteralExp
*)e2
;
1315 // For structs, we only need to return 0 or 1 (< and > aren't legal).
1317 if (es1
->sd
!= es2
->sd
)
1319 else if ((!es1
->elements
|| !es1
->elements
->length
) &&
1320 (!es2
->elements
|| !es2
->elements
->length
))
1321 return 0; // both arrays are empty
1322 else if (!es1
->elements
|| !es2
->elements
)
1324 else if (es1
->elements
->length
!= es2
->elements
->length
)
1328 for (size_t i
= 0; i
< es1
->elements
->length
; i
++)
1330 Expression
*ee1
= (*es1
->elements
)[i
];
1331 Expression
*ee2
= (*es2
->elements
)[i
];
1337 int cmp
= ctfeRawCmp(loc
, ee1
, ee2
);
1341 return 0; // All elements are equal
1344 if (e1
->op
== TOKassocarrayliteral
&& e2
->op
== TOKassocarrayliteral
)
1346 AssocArrayLiteralExp
*es1
= (AssocArrayLiteralExp
*)e1
;
1347 AssocArrayLiteralExp
*es2
= (AssocArrayLiteralExp
*)e2
;
1349 size_t dim
= es1
->keys
->length
;
1350 if (es2
->keys
->length
!= dim
)
1353 bool *used
= (bool *)mem
.xmalloc(sizeof(bool) * dim
);
1354 memset(used
, 0, sizeof(bool) * dim
);
1356 for (size_t i
= 0; i
< dim
; ++i
)
1358 Expression
*k1
= (*es1
->keys
)[i
];
1359 Expression
*v1
= (*es1
->values
)[i
];
1360 Expression
*v2
= NULL
;
1361 for (size_t j
= 0; j
< dim
; ++j
)
1365 Expression
*k2
= (*es2
->keys
)[j
];
1367 if (ctfeRawCmp(loc
, k1
, k2
))
1370 v2
= (*es2
->values
)[j
];
1373 if (!v2
|| ctfeRawCmp(loc
, v1
, v2
))
1382 error(loc
, "CTFE internal error: bad compare of `%s` and `%s`", e1
->toChars(), e2
->toChars());
1387 /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
1388 int ctfeEqual(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1390 int cmp
= !ctfeRawCmp(loc
, e1
, e2
);
1391 if (op
== TOKnotequal
)
1396 /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
1397 int ctfeIdentity(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1399 //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
1400 // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
1402 if (e1
->op
== TOKnull
)
1404 cmp
= (e2
->op
== TOKnull
);
1406 else if (e2
->op
== TOKnull
)
1410 else if (e1
->op
== TOKsymoff
&& e2
->op
== TOKsymoff
)
1412 SymOffExp
*es1
= (SymOffExp
*)e1
;
1413 SymOffExp
*es2
= (SymOffExp
*)e2
;
1414 cmp
= (es1
->var
== es2
->var
&& es1
->offset
== es2
->offset
);
1416 else if (e1
->type
->isreal())
1417 cmp
= RealEquals(e1
->toReal(), e2
->toReal());
1418 else if (e1
->type
->isimaginary())
1419 cmp
= RealEquals(e1
->toImaginary(), e2
->toImaginary());
1420 else if (e1
->type
->iscomplex())
1422 complex_t v1
= e1
->toComplex();
1423 complex_t v2
= e2
->toComplex();
1424 cmp
= RealEquals(creall(v1
), creall(v2
)) &&
1425 RealEquals(cimagl(v1
), cimagl(v1
));
1428 cmp
= !ctfeRawCmp(loc
, e1
, e2
);
1430 if (op
== TOKnotidentity
|| op
== TOKnotequal
)
1435 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
1436 int ctfeCmp(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1438 Type
*t1
= e1
->type
->toBasetype();
1439 Type
*t2
= e2
->type
->toBasetype();
1441 if (t1
->isString() && t2
->isString())
1442 return specificCmp(op
, ctfeRawCmp(loc
, e1
, e2
));
1443 else if (t1
->isreal())
1444 return realCmp(op
, e1
->toReal(), e2
->toReal());
1445 else if (t1
->isimaginary())
1446 return realCmp(op
, e1
->toImaginary(), e2
->toImaginary());
1447 else if (t1
->isunsigned() || t2
->isunsigned())
1448 return intUnsignedCmp(op
, e1
->toInteger(), e2
->toInteger());
1450 return intSignedCmp(op
, e1
->toInteger(), e2
->toInteger());
1453 UnionExp
ctfeCat(Loc loc
, Type
*type
, Expression
*e1
, Expression
*e2
)
1455 Type
*t1
= e1
->type
->toBasetype();
1456 Type
*t2
= e2
->type
->toBasetype();
1458 if (e2
->op
== TOKstring
&& e1
->op
== TOKarrayliteral
&&
1459 t1
->nextOf()->isintegral())
1461 // [chars] ~ string => string (only valid for CTFE)
1462 StringExp
*es1
= (StringExp
*)e2
;
1463 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e1
;
1464 size_t len
= es1
->len
+ es2
->elements
->length
;
1465 unsigned char sz
= es1
->sz
;
1467 void *s
= mem
.xmalloc((len
+ 1) * sz
);
1468 memcpy((char *)s
+ sz
* es2
->elements
->length
, es1
->string
, es1
->len
* sz
);
1469 for (size_t i
= 0; i
< es2
->elements
->length
; i
++)
1471 Expression
*es2e
= (*es2
->elements
)[i
];
1472 if (es2e
->op
!= TOKint64
)
1474 new(&ue
) CTFEExp(TOKcantexp
);
1477 dinteger_t v
= es2e
->toInteger();
1478 Port::valcpy((utf8_t
*)s
+ i
* sz
, v
, sz
);
1481 // Add terminating 0
1482 memset((utf8_t
*)s
+ len
* sz
, 0, sz
);
1484 new(&ue
) StringExp(loc
, s
, len
);
1485 StringExp
*es
= (StringExp
*)ue
.exp();
1491 if (e1
->op
== TOKstring
&& e2
->op
== TOKarrayliteral
&&
1492 t2
->nextOf()->isintegral())
1494 // string ~ [chars] => string (only valid for CTFE)
1495 // Concatenate the strings
1496 StringExp
*es1
= (StringExp
*)e1
;
1497 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e2
;
1498 size_t len
= es1
->len
+ es2
->elements
->length
;
1499 unsigned char sz
= es1
->sz
;
1501 void *s
= mem
.xmalloc((len
+ 1) * sz
);
1502 memcpy(s
, es1
->string
, es1
->len
* sz
);
1503 for (size_t i
= 0; i
< es2
->elements
->length
; i
++)
1505 Expression
*es2e
= (*es2
->elements
)[i
];
1506 if (es2e
->op
!= TOKint64
)
1508 new(&ue
) CTFEExp(TOKcantexp
);
1511 dinteger_t v
= es2e
->toInteger();
1512 Port::valcpy((utf8_t
*)s
+ (es1
->len
+ i
) * sz
, v
, sz
);
1515 // Add terminating 0
1516 memset((utf8_t
*)s
+ len
* sz
, 0, sz
);
1518 new(&ue
) StringExp(loc
, s
, len
);
1519 StringExp
*es
= (StringExp
*)ue
.exp();
1521 es
->committed
= 0; //es1->committed;
1525 if (e1
->op
== TOKarrayliteral
&& e2
->op
== TOKarrayliteral
&&
1526 t1
->nextOf()->equals(t2
->nextOf()))
1528 // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
1529 ArrayLiteralExp
*es1
= (ArrayLiteralExp
*)e1
;
1530 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e2
;
1532 new(&ue
) ArrayLiteralExp(es1
->loc
, type
, copyLiteralArray(es1
->elements
));
1533 es1
= (ArrayLiteralExp
*)ue
.exp();
1534 es1
->elements
->insert(es1
->elements
->length
, copyLiteralArray(es2
->elements
));
1537 if (e1
->op
== TOKarrayliteral
&& e2
->op
== TOKnull
&&
1538 t1
->nextOf()->equals(t2
->nextOf()))
1540 // [ e1 ] ~ null ----> [ e1 ].dup
1541 ue
= paintTypeOntoLiteralCopy(type
, copyLiteral(e1
).copy());
1544 if (e1
->op
== TOKnull
&& e2
->op
== TOKarrayliteral
&&
1545 t1
->nextOf()->equals(t2
->nextOf()))
1547 // null ~ [ e2 ] ----> [ e2 ].dup
1548 ue
= paintTypeOntoLiteralCopy(type
, copyLiteral(e2
).copy());
1551 ue
= Cat(type
, e1
, e2
);
1555 /* Given an AA literal 'ae', and a key 'e2':
1556 * Return ae[e2] if present, or NULL if not found.
1558 Expression
*findKeyInAA(Loc loc
, AssocArrayLiteralExp
*ae
, Expression
*e2
)
1560 /* Search the keys backwards, in case there are duplicate keys
1562 for (size_t i
= ae
->keys
->length
; i
;)
1565 Expression
*ekey
= (*ae
->keys
)[i
];
1566 int eq
= ctfeEqual(loc
, TOKequal
, ekey
, e2
);
1569 return (*ae
->values
)[i
];
1575 /* Same as for constfold.Index, except that it only works for static arrays,
1576 * dynamic arrays, and strings. We know that e1 is an
1577 * interpreted CTFE expression, so it cannot have side-effects.
1579 Expression
*ctfeIndex(Loc loc
, Type
*type
, Expression
*e1
, uinteger_t indx
)
1581 //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
1583 if (e1
->op
== TOKstring
)
1585 StringExp
*es1
= (StringExp
*)e1
;
1586 if (indx
>= es1
->len
)
1588 error(loc
, "string index %llu is out of bounds [0 .. %llu]", (ulonglong
)indx
, (ulonglong
)es1
->len
);
1589 return CTFEExp::cantexp
;
1591 return new IntegerExp(loc
, es1
->charAt(indx
), type
);
1593 assert(e1
->op
== TOKarrayliteral
);
1595 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)e1
;
1596 if (indx
>= ale
->elements
->length
)
1598 error(loc
, "array index %llu is out of bounds %s[0 .. %llu]", (ulonglong
)indx
, e1
->toChars(), (ulonglong
)ale
->elements
->length
);
1599 return CTFEExp::cantexp
;
1601 Expression
*e
= (*ale
->elements
)[(size_t)indx
];
1602 return paintTypeOntoLiteral(type
, e
);
1606 Expression
*ctfeCast(UnionExp
*pue
, Loc loc
, Type
*type
, Type
*to
, Expression
*e
)
1608 if (e
->op
== TOKnull
)
1609 return paintTypeOntoLiteral(pue
, to
, e
);
1611 if (e
->op
== TOKclassreference
)
1613 // Disallow reinterpreting class casts. Do this by ensuring that
1614 // the original class can implicitly convert to the target class
1615 ClassDeclaration
*originalClass
= ((ClassReferenceExp
*)e
)->originalClass();
1616 if (originalClass
->type
->implicitConvTo(to
->mutableOf()))
1617 return paintTypeOntoLiteral(pue
, to
, e
);
1620 new(pue
) NullExp(loc
, to
);
1625 // Allow TypeInfo type painting
1626 if (isTypeInfo_Class(e
->type
) && e
->type
->implicitConvTo(to
))
1627 return paintTypeOntoLiteral(pue
, to
, e
);
1629 // Allow casting away const for struct literals
1630 if (e
->op
== TOKstructliteral
&&
1631 e
->type
->toBasetype()->castMod(0) == to
->toBasetype()->castMod(0))
1632 return paintTypeOntoLiteral(pue
, to
, e
);
1635 if (e
->type
->equals(type
) && type
->equals(to
))
1637 // necessary not to change e's address for pointer comparisons
1640 else if (to
->toBasetype()->ty
== Tarray
&&
1641 type
->toBasetype()->ty
== Tarray
&&
1642 to
->toBasetype()->nextOf()->size() == type
->toBasetype()->nextOf()->size())
1644 // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
1645 return paintTypeOntoLiteral(pue
, to
, e
);
1649 *pue
= Cast(loc
, type
, to
, e
);
1653 if (CTFEExp::isCantExp(r
))
1654 error(loc
, "cannot cast %s to %s at compile time", e
->toChars(), to
->toChars());
1656 if (e
->op
== TOKarrayliteral
)
1657 ((ArrayLiteralExp
*)e
)->ownedByCtfe
= OWNEDctfe
;
1659 if (e
->op
== TOKstring
)
1660 ((StringExp
*)e
)->ownedByCtfe
= OWNEDctfe
;
1665 /******** Assignment helper functions ***************************/
1667 /* Set dest = src, where both dest and src are container value literals
1668 * (ie, struct literals, or static arrays (can be an array literal or a string))
1669 * Assignment is recursively in-place.
1670 * Purpose: any reference to a member of 'dest' will remain valid after the
1673 void assignInPlace(Expression
*dest
, Expression
*src
)
1675 assert(dest
->op
== TOKstructliteral
||
1676 dest
->op
== TOKarrayliteral
||
1677 dest
->op
== TOKstring
);
1678 Expressions
*oldelems
;
1679 Expressions
*newelems
;
1680 if (dest
->op
== TOKstructliteral
)
1682 assert(dest
->op
== src
->op
);
1683 oldelems
= ((StructLiteralExp
*)dest
)->elements
;
1684 newelems
= ((StructLiteralExp
*)src
)->elements
;
1685 if (((StructLiteralExp
*)dest
)->sd
->isNested() && oldelems
->length
== newelems
->length
- 1)
1686 oldelems
->push(NULL
);
1688 else if (dest
->op
== TOKarrayliteral
&& src
->op
==TOKarrayliteral
)
1690 oldelems
= ((ArrayLiteralExp
*)dest
)->elements
;
1691 newelems
= ((ArrayLiteralExp
*)src
)->elements
;
1693 else if (dest
->op
== TOKstring
&& src
->op
== TOKstring
)
1695 sliceAssignStringFromString((StringExp
*)dest
, (StringExp
*)src
, 0);
1698 else if (dest
->op
== TOKarrayliteral
&& src
->op
== TOKstring
)
1700 sliceAssignArrayLiteralFromString((ArrayLiteralExp
*)dest
, (StringExp
*)src
, 0);
1703 else if (src
->op
== TOKarrayliteral
&& dest
->op
== TOKstring
)
1705 sliceAssignStringFromArrayLiteral((StringExp
*)dest
, (ArrayLiteralExp
*)src
, 0);
1711 assert(oldelems
->length
== newelems
->length
);
1713 for (size_t i
= 0; i
< oldelems
->length
; ++i
)
1715 Expression
*e
= (*newelems
)[i
];
1716 Expression
*o
= (*oldelems
)[i
];
1717 if (e
->op
== TOKstructliteral
)
1719 assert(o
->op
== e
->op
);
1720 assignInPlace(o
, e
);
1722 else if (e
->type
->ty
== Tsarray
&& e
->op
!= TOKvoid
&&
1723 o
->type
->ty
== Tsarray
)
1725 assignInPlace(o
, e
);
1729 (*oldelems
)[i
] = (*newelems
)[i
];
1734 // Duplicate the elements array, then set field 'indexToChange' = newelem.
1735 Expressions
*changeOneElement(Expressions
*oldelems
, size_t indexToChange
, Expression
*newelem
)
1737 Expressions
*expsx
= new Expressions();
1738 ++CtfeStatus::numArrayAllocs
;
1739 expsx
->setDim(oldelems
->length
);
1740 for (size_t j
= 0; j
< expsx
->length
; j
++)
1742 if (j
== indexToChange
)
1743 (*expsx
)[j
] = newelem
;
1745 (*expsx
)[j
] = (*oldelems
)[j
];
1750 // Given an AA literal aae, set aae[index] = newval and return newval.
1751 Expression
*assignAssocArrayElement(Loc loc
, AssocArrayLiteralExp
*aae
,
1752 Expression
*index
, Expression
*newval
)
1754 /* Create new associative array literal reflecting updated key/value
1756 Expressions
*keysx
= aae
->keys
;
1757 Expressions
*valuesx
= aae
->values
;
1759 for (size_t j
= valuesx
->length
; j
; )
1762 Expression
*ekey
= (*aae
->keys
)[j
];
1763 int eq
= ctfeEqual(loc
, TOKequal
, ekey
, index
);
1766 (*valuesx
)[j
] = newval
;
1772 // Append index/newval to keysx[]/valuesx[]
1773 valuesx
->push(newval
);
1779 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
1780 /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
1781 /// all new elements will be set to the default initializer for the element type.
1782 UnionExp
changeArrayLiteralLength(Loc loc
, TypeArray
*arrayType
,
1783 Expression
*oldval
, size_t oldlen
, size_t newlen
)
1786 Type
*elemType
= arrayType
->next
;
1788 Expression
*defaultElem
= elemType
->defaultInitLiteral(loc
);
1789 Expressions
*elements
= new Expressions();
1790 elements
->setDim(newlen
);
1794 if (oldval
->op
== TOKslice
)
1796 indxlo
= (size_t)((SliceExp
*)oldval
)->lwr
->toInteger();
1797 oldval
= ((SliceExp
*)oldval
)->e1
;
1799 size_t copylen
= oldlen
< newlen
? oldlen
: newlen
;
1800 if (oldval
->op
== TOKstring
)
1802 StringExp
*oldse
= (StringExp
*)oldval
;
1803 void *s
= mem
.xcalloc(newlen
+ 1, oldse
->sz
);
1804 memcpy(s
, oldse
->string
, copylen
* oldse
->sz
);
1805 unsigned defaultValue
= (unsigned)(defaultElem
->toInteger());
1806 for (size_t elemi
= copylen
; elemi
< newlen
; ++elemi
)
1810 case 1: (( utf8_t
*)s
)[(size_t)(indxlo
+ elemi
)] = ( utf8_t
)defaultValue
; break;
1811 case 2: ((utf16_t
*)s
)[(size_t)(indxlo
+ elemi
)] = (utf16_t
)defaultValue
; break;
1812 case 4: ((utf32_t
*)s
)[(size_t)(indxlo
+ elemi
)] = (utf32_t
)defaultValue
; break;
1816 new(&ue
) StringExp(loc
, s
, newlen
);
1817 StringExp
*se
= (StringExp
*)ue
.exp();
1818 se
->type
= arrayType
;
1820 se
->committed
= oldse
->committed
;
1821 se
->ownedByCtfe
= OWNEDctfe
;
1827 assert(oldval
->op
== TOKarrayliteral
);
1828 ArrayLiteralExp
*ae
= (ArrayLiteralExp
*)oldval
;
1829 for (size_t i
= 0; i
< copylen
; i
++)
1830 (*elements
)[i
] = (*ae
->elements
)[indxlo
+ i
];
1832 if (elemType
->ty
== Tstruct
|| elemType
->ty
== Tsarray
)
1834 /* If it is an aggregate literal representing a value type,
1835 * we need to create a unique copy for each element
1837 for (size_t i
= copylen
; i
< newlen
; i
++)
1838 (*elements
)[i
] = copyLiteral(defaultElem
).copy();
1842 for (size_t i
= copylen
; i
< newlen
; i
++)
1843 (*elements
)[i
] = defaultElem
;
1845 new(&ue
) ArrayLiteralExp(loc
, arrayType
, elements
);
1846 ArrayLiteralExp
*aae
= (ArrayLiteralExp
*)ue
.exp();
1847 aae
->ownedByCtfe
= OWNEDctfe
;
1852 /*************************** CTFE Sanity Checks ***************************/
1854 bool isCtfeValueValid(Expression
*newval
)
1856 Type
*tb
= newval
->type
->toBasetype();
1858 if (newval
->op
== TOKint64
||
1859 newval
->op
== TOKfloat64
||
1860 newval
->op
== TOKchar
||
1861 newval
->op
== TOKcomplex80
)
1863 return tb
->isscalar();
1865 if (newval
->op
== TOKnull
)
1867 return tb
->ty
== Tnull
||
1868 tb
->ty
== Tpointer
||
1870 tb
->ty
== Taarray
||
1872 tb
->ty
== Tdelegate
;
1875 if (newval
->op
== TOKstring
)
1876 return true; // CTFE would directly use the StringExp in AST.
1877 if (newval
->op
== TOKarrayliteral
)
1878 return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
1879 if (newval
->op
== TOKassocarrayliteral
)
1880 return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
1881 if (newval
->op
== TOKstructliteral
)
1882 return true; //((StructLiteralExp *)newval)->ownedByCtfe;
1883 if (newval
->op
== TOKclassreference
)
1886 if (newval
->op
== TOKvector
)
1887 return true; // vector literal
1889 if (newval
->op
== TOKfunction
)
1890 return true; // function literal or delegate literal
1891 if (newval
->op
== TOKdelegate
)
1893 // &struct.func or &clasinst.func
1895 Expression
*ethis
= ((DelegateExp
*)newval
)->e1
;
1896 return (ethis
->op
== TOKstructliteral
||
1897 ethis
->op
== TOKclassreference
||
1898 (ethis
->op
== TOKvar
&& ((VarExp
*)ethis
)->var
== ((DelegateExp
*)newval
)->func
));
1900 if (newval
->op
== TOKsymoff
)
1902 // function pointer, or pointer to static variable
1903 Declaration
*d
= ((SymOffExp
*)newval
)->var
;
1904 return d
->isFuncDeclaration() || d
->isDataseg();
1906 if (newval
->op
== TOKtypeid
)
1911 if (newval
->op
== TOKaddress
)
1913 // e1 should be a CTFE reference
1914 Expression
*e1
= ((AddrExp
*)newval
)->e1
;
1915 return tb
->ty
== Tpointer
&&
1916 (((e1
->op
== TOKstructliteral
|| e1
->op
== TOKarrayliteral
) && isCtfeValueValid(e1
)) ||
1917 (e1
->op
== TOKvar
) ||
1918 (e1
->op
== TOKdotvar
&& isCtfeReferenceValid(e1
)) ||
1919 (e1
->op
== TOKindex
&& isCtfeReferenceValid(e1
)) ||
1920 (e1
->op
== TOKslice
&& e1
->type
->toBasetype()->ty
== Tsarray
));
1922 if (newval
->op
== TOKslice
)
1924 // e1 should be an array aggregate
1925 SliceExp
*se
= (SliceExp
*)newval
;
1926 assert(se
->lwr
&& se
->lwr
->op
== TOKint64
);
1927 assert(se
->upr
&& se
->upr
->op
== TOKint64
);
1928 return (tb
->ty
== Tarray
||
1929 tb
->ty
== Tsarray
) &&
1930 (se
->e1
->op
== TOKstring
||
1931 se
->e1
->op
== TOKarrayliteral
);
1934 if (newval
->op
== TOKvoid
)
1935 return true; // uninitialized value
1937 newval
->error("CTFE internal error: illegal CTFE value %s", newval
->toChars());
1941 bool isCtfeReferenceValid(Expression
*newval
)
1943 if (newval
->op
== TOKthis
)
1945 if (newval
->op
== TOKvar
)
1947 VarDeclaration
*v
= ((VarExp
*)newval
)->var
->isVarDeclaration();
1949 // Must not be a reference to a reference
1952 if (newval
->op
== TOKindex
)
1954 Expression
*eagg
= ((IndexExp
*)newval
)->e1
;
1955 return eagg
->op
== TOKstring
||
1956 eagg
->op
== TOKarrayliteral
||
1957 eagg
->op
== TOKassocarrayliteral
;
1959 if (newval
->op
== TOKdotvar
)
1961 Expression
*eagg
= ((DotVarExp
*)newval
)->e1
;
1962 return (eagg
->op
== TOKstructliteral
|| eagg
->op
== TOKclassreference
) &&
1963 isCtfeValueValid(eagg
);
1966 // Internally a ref variable may directly point a stack memory.
1967 // e.g. ref int v = 1;
1968 return isCtfeValueValid(newval
);
1971 // Used for debugging only
1972 void showCtfeExpr(Expression
*e
, int level
)
1974 for (int i
= level
; i
> 0; --i
) printf(" ");
1975 Expressions
*elements
= NULL
;
1976 // We need the struct definition to detect block assignment
1977 StructDeclaration
*sd
= NULL
;
1978 ClassDeclaration
*cd
= NULL
;
1979 if (e
->op
== TOKstructliteral
)
1981 elements
= ((StructLiteralExp
*)e
)->elements
;
1982 sd
= ((StructLiteralExp
*)e
)->sd
;
1983 printf("STRUCT type = %s %p:\n", e
->type
->toChars(),
1986 else if (e
->op
== TOKclassreference
)
1988 elements
= ((ClassReferenceExp
*)e
)->value
->elements
;
1989 cd
= ((ClassReferenceExp
*)e
)->originalClass();
1990 printf("CLASS type = %s %p:\n", e
->type
->toChars(),
1991 ((ClassReferenceExp
*)e
)->value
);
1993 else if (e
->op
== TOKarrayliteral
)
1995 elements
= ((ArrayLiteralExp
*)e
)->elements
;
1996 printf("ARRAY LITERAL type=%s %p:\n", e
->type
->toChars(),
1999 else if (e
->op
== TOKassocarrayliteral
)
2001 printf("AA LITERAL type=%s %p:\n", e
->type
->toChars(),
2004 else if (e
->op
== TOKstring
)
2006 printf("STRING %s %p\n", e
->toChars(),
2007 ((StringExp
*)e
)->string
);
2009 else if (e
->op
== TOKslice
)
2011 printf("SLICE %p: %s\n", e
, e
->toChars());
2012 showCtfeExpr(((SliceExp
*)e
)->e1
, level
+ 1);
2014 else if (e
->op
== TOKvar
)
2016 printf("VAR %p %s\n", e
, e
->toChars());
2017 VarDeclaration
*v
= ((VarExp
*)e
)->var
->isVarDeclaration();
2018 if (v
&& getValue(v
))
2019 showCtfeExpr(getValue(v
), level
+ 1);
2021 else if (e
->op
== TOKaddress
)
2023 // This is potentially recursive. We mustn't try to print the thing we're pointing to.
2024 printf("POINTER %p to %p: %s\n", e
, ((AddrExp
*)e
)->e1
, e
->toChars());
2027 printf("VALUE %p: %s\n", e
, e
->toChars());
2031 size_t fieldsSoFar
= 0;
2032 for (size_t i
= 0; i
< elements
->length
; i
++)
2034 Expression
*z
= NULL
;
2035 VarDeclaration
*v
= NULL
;
2038 printf("...(total %d elements)\n", (int)elements
->length
);
2048 while (i
- fieldsSoFar
>= cd
->fields
.length
)
2050 fieldsSoFar
+= cd
->fields
.length
;
2052 for (int j
= level
; j
> 0; --j
) printf(" ");
2053 printf(" BASE CLASS: %s\n", cd
->toChars());
2055 v
= cd
->fields
[i
- fieldsSoFar
];
2056 assert((elements
->length
+ i
) >= (fieldsSoFar
+ cd
->fields
.length
));
2057 size_t indx
= (elements
->length
- fieldsSoFar
)- cd
->fields
.length
+ i
;
2058 assert(indx
< elements
->length
);
2059 z
= (*elements
)[indx
];
2063 for (int j
= level
; j
> 0; --j
) printf(" ");
2070 // If it is a void assignment, use the default initializer
2071 if ((v
->type
->ty
!= z
->type
->ty
) && v
->type
->ty
== Tsarray
)
2073 for (int j
= level
; --j
; ) printf(" ");
2074 printf(" field: block initalized static array\n");
2078 showCtfeExpr(z
, level
+ 1);
2083 /*************************** Void initialization ***************************/
2085 UnionExp
voidInitLiteral(Type
*t
, VarDeclaration
*var
)
2088 if (t
->ty
== Tsarray
)
2090 TypeSArray
*tsa
= (TypeSArray
*)t
;
2091 Expression
*elem
= voidInitLiteral(tsa
->next
, var
).copy();
2093 // For aggregate value types (structs, static arrays) we must
2094 // create an a separate copy for each element.
2095 bool mustCopy
= (elem
->op
== TOKarrayliteral
|| elem
->op
== TOKstructliteral
);
2097 Expressions
*elements
= new Expressions();
2098 size_t d
= (size_t)tsa
->dim
->toInteger();
2099 elements
->setDim(d
);
2100 for (size_t i
= 0; i
< d
; i
++)
2102 if (mustCopy
&& i
> 0)
2103 elem
= copyLiteral(elem
).copy();
2104 (*elements
)[i
] = elem
;
2106 new(&ue
) ArrayLiteralExp(var
->loc
, tsa
, elements
);
2107 ArrayLiteralExp
*ae
= (ArrayLiteralExp
*)ue
.exp();
2108 ae
->ownedByCtfe
= OWNEDctfe
;
2110 else if (t
->ty
== Tstruct
)
2112 TypeStruct
*ts
= (TypeStruct
*)t
;
2113 Expressions
*exps
= new Expressions();
2114 exps
->setDim(ts
->sym
->fields
.length
);
2115 for (size_t i
= 0; i
< ts
->sym
->fields
.length
; i
++)
2117 (*exps
)[i
] = voidInitLiteral(ts
->sym
->fields
[i
]->type
, ts
->sym
->fields
[i
]).copy();
2119 new(&ue
) StructLiteralExp(var
->loc
, ts
->sym
, exps
);
2120 StructLiteralExp
*se
= (StructLiteralExp
*)ue
.exp();
2122 se
->ownedByCtfe
= OWNEDctfe
;
2125 new(&ue
) VoidInitExp(var
, t
);