2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 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
->dim
; j
++)
48 while (j
- fieldsSoFar
>= cd
->fields
.dim
)
50 fieldsSoFar
+= cd
->fields
.dim
;
53 VarDeclaration
*v2
= cd
->fields
[j
- fieldsSoFar
];
54 if (fieldoffset
== v2
->offset
&&
55 fieldtype
->size() == v2
->type
->size())
57 return (int)(value
->elements
->dim
- fieldsSoFar
- cd
->fields
.dim
+ (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
->dim
; j
++)
71 while (j
- fieldsSoFar
>= cd
->fields
.dim
)
73 fieldsSoFar
+= cd
->fields
.dim
;
76 VarDeclaration
*v2
= cd
->fields
[j
- fieldsSoFar
];
79 return (int)(value
->elements
->dim
- fieldsSoFar
- cd
->fields
.dim
+ (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
.dim
; ++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
->dim
);
233 for (size_t i
= 0; i
< oldelems
->dim
; 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
, elements
);
269 ArrayLiteralExp
*r
= (ArrayLiteralExp
*)ue
.exp();
271 r
->ownedByCtfe
= OWNEDctfe
;
274 if (e
->op
== TOKassocarrayliteral
)
276 AssocArrayLiteralExp
*aae
= (AssocArrayLiteralExp
*)e
;
277 new(&ue
) AssocArrayLiteralExp(e
->loc
, copyLiteralArray(aae
->keys
), copyLiteralArray(aae
->values
));
278 AssocArrayLiteralExp
*r
= (AssocArrayLiteralExp
*)ue
.exp();
280 r
->ownedByCtfe
= OWNEDctfe
;
283 if (e
->op
== TOKstructliteral
)
285 /* syntaxCopy doesn't work for struct literals, because of a nasty special
286 * case: block assignment is permitted inside struct literals, eg,
287 * an int[4] array can be initialized with a single int.
289 StructLiteralExp
*sle
= (StructLiteralExp
*)e
;
290 Expressions
*oldelems
= sle
->elements
;
291 Expressions
* newelems
= new Expressions();
292 newelems
->setDim(oldelems
->dim
);
293 for (size_t i
= 0; i
< newelems
->dim
; i
++)
295 // We need the struct definition to detect block assignment
296 VarDeclaration
*v
= sle
->sd
->fields
[i
];
297 Expression
*m
= (*oldelems
)[i
];
299 // If it is a void assignment, use the default initializer
301 m
= voidInitLiteral(v
->type
, v
).copy();
303 if (v
->type
->ty
== Tarray
|| v
->type
->ty
== Taarray
)
305 // Don't have to copy array references
309 // Buzilla 15681: Copy the source element always.
310 m
= copyLiteral(m
).copy();
312 // Block assignment from inside struct literals
313 if (v
->type
->ty
!= m
->type
->ty
&& v
->type
->ty
== Tsarray
)
315 TypeSArray
*tsa
= (TypeSArray
*)v
->type
;
316 size_t len
= (size_t)tsa
->dim
->toInteger();
317 m
= createBlockDuplicatedArrayLiteral(e
->loc
, v
->type
, m
, len
);
322 new(&ue
) StructLiteralExp(e
->loc
, sle
->sd
, newelems
, sle
->stype
);
323 StructLiteralExp
*r
= (StructLiteralExp
*)ue
.exp();
325 r
->ownedByCtfe
= OWNEDctfe
;
326 r
->origin
= ((StructLiteralExp
*)e
)->origin
;
329 if (e
->op
== TOKfunction
|| e
->op
== TOKdelegate
||
330 e
->op
== TOKsymoff
|| e
->op
== TOKnull
||
331 e
->op
== TOKvar
|| e
->op
== TOKdotvar
||
332 e
->op
== TOKint64
|| e
->op
== TOKfloat64
||
333 e
->op
== TOKchar
|| e
->op
== TOKcomplex80
||
334 e
->op
== TOKvoid
|| e
->op
== TOKvector
||
337 // Simple value types
338 // Keep e1 for DelegateExp and DotVarExp
339 new(&ue
) UnionExp(e
);
340 Expression
*r
= ue
.exp();
344 if (e
->op
== TOKslice
)
346 SliceExp
*se
= (SliceExp
*)e
;
347 if (se
->type
->toBasetype()->ty
== Tsarray
)
349 // same with resolveSlice()
350 if (se
->e1
->op
== TOKnull
)
352 new(&ue
) NullExp(se
->loc
, se
->type
);
355 ue
= Slice(se
->type
, se
->e1
, se
->lwr
, se
->upr
);
356 assert(ue
.exp()->op
== TOKarrayliteral
);
357 ArrayLiteralExp
*r
= (ArrayLiteralExp
*)ue
.exp();
358 r
->elements
= copyLiteralArray(r
->elements
);
359 r
->ownedByCtfe
= OWNEDctfe
;
364 // Array slices only do a shallow copy
365 new(&ue
) SliceExp(e
->loc
, se
->e1
, se
->lwr
, se
->upr
);
366 Expression
*r
= ue
.exp();
371 if (isPointer(e
->type
))
373 // For pointers, we only do a shallow copy.
374 if (e
->op
== TOKaddress
)
375 new(&ue
) AddrExp(e
->loc
, ((AddrExp
*)e
)->e1
);
376 else if (e
->op
== TOKindex
)
377 new(&ue
) IndexExp(e
->loc
, ((IndexExp
*)e
)->e1
, ((IndexExp
*)e
)->e2
);
378 else if (e
->op
== TOKdotvar
)
380 new(&ue
) DotVarExp(e
->loc
, ((DotVarExp
*)e
)->e1
,
381 ((DotVarExp
*)e
)->var
, ((DotVarExp
*)e
)->hasOverloads
);
385 Expression
*r
= ue
.exp();
389 if (e
->op
== TOKclassreference
)
391 new(&ue
) ClassReferenceExp(e
->loc
, ((ClassReferenceExp
*)e
)->value
, e
->type
);
394 if (e
->op
== TOKerror
)
396 new(&ue
) UnionExp(e
);
399 e
->error("CTFE internal error: literal %s", e
->toChars());
404 /* Deal with type painting.
405 * Type painting is a major nuisance: we can't just set
406 * e->type = type, because that would change the original literal.
407 * But, we can't simply copy the literal either, because that would change
408 * the values of any pointers.
410 Expression
*paintTypeOntoLiteral(Type
*type
, Expression
*lit
)
412 if (lit
->type
->equals(type
))
414 return paintTypeOntoLiteralCopy(type
, lit
).copy();
417 UnionExp
paintTypeOntoLiteralCopy(Type
*type
, Expression
*lit
)
421 if (lit
->type
->equals(type
))
423 new(&ue
) UnionExp(lit
);
427 // If it is a cast to inout, retain the original type of the referenced part.
428 if (type
->hasWild() && type
->hasPointers())
430 new(&ue
) UnionExp(lit
);
431 ue
.exp()->type
= type
;
435 if (lit
->op
== TOKslice
)
437 SliceExp
*se
= (SliceExp
*)lit
;
438 new(&ue
) SliceExp(lit
->loc
, se
->e1
, se
->lwr
, se
->upr
);
440 else if (lit
->op
== TOKindex
)
442 IndexExp
*ie
= (IndexExp
*)lit
;
443 new(&ue
) IndexExp(lit
->loc
, ie
->e1
, ie
->e2
);
445 else if (lit
->op
== TOKarrayliteral
)
447 new(&ue
) SliceExp(lit
->loc
, lit
,
448 new IntegerExp(Loc(), 0, Type::tsize_t
), ArrayLength(Type::tsize_t
, lit
).copy());
450 else if (lit
->op
== TOKstring
)
452 // For strings, we need to introduce another level of indirection
453 new(&ue
) SliceExp(lit
->loc
, lit
,
454 new IntegerExp(Loc(), 0, Type::tsize_t
), ArrayLength(Type::tsize_t
, lit
).copy());
456 else if (lit
->op
== TOKassocarrayliteral
)
458 AssocArrayLiteralExp
*aae
= (AssocArrayLiteralExp
*)lit
;
459 // TODO: we should be creating a reference to this AAExp, not
460 // just a ref to the keys and values.
461 OwnedBy wasOwned
= aae
->ownedByCtfe
;
462 new(&ue
) AssocArrayLiteralExp(lit
->loc
, aae
->keys
, aae
->values
);
463 aae
= (AssocArrayLiteralExp
*)ue
.exp();
464 aae
->ownedByCtfe
= wasOwned
;
468 // Can't type paint from struct to struct*; this needs another
469 // level of indirection
470 if (lit
->op
== TOKstructliteral
&& isPointer(type
))
471 lit
->error("CTFE internal error: painting %s", type
->toChars());
472 ue
= copyLiteral(lit
);
474 ue
.exp()->type
= type
;
478 /*************************************
479 * If e is a SliceExp, constant fold it.
481 * e = expression to resolve
482 * pue = if not null, store resulting expression here
484 * resulting expression
486 Expression
*resolveSlice(Expression
*e
, UnionExp
*pue
)
488 if (e
->op
!= TOKslice
)
490 SliceExp
*se
= (SliceExp
*)e
;
491 if (se
->e1
->op
== TOKnull
)
495 *pue
= Slice(e
->type
, se
->e1
, se
->lwr
, se
->upr
);
499 return Slice(e
->type
, se
->e1
, se
->lwr
, se
->upr
).copy();
502 /* Determine the array length, without interpreting it.
503 * e must be an array literal, or a slice
504 * It's very wasteful to resolve the slice when we only
507 uinteger_t
resolveArrayLength(Expression
*e
)
509 if (e
->op
== TOKvector
)
510 e
= ((VectorExp
*)e
)->e1
;
512 if (e
->op
== TOKnull
)
514 if (e
->op
== TOKslice
)
516 uinteger_t ilo
= ((SliceExp
*)e
)->lwr
->toInteger();
517 uinteger_t iup
= ((SliceExp
*)e
)->upr
->toInteger();
520 if (e
->op
== TOKstring
)
522 return ((StringExp
*)e
)->len
;
524 if (e
->op
== TOKarrayliteral
)
526 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)e
;
527 return ale
->elements
? ale
->elements
->dim
: 0;
529 if (e
->op
== TOKassocarrayliteral
)
531 AssocArrayLiteralExp
*ale
= (AssocArrayLiteralExp
*)e
;
532 return ale
->keys
->dim
;
538 /******************************
540 * Create an array literal consisting of 'elem' duplicated 'dim' times.
542 * loc = source location where the interpretation occurs
543 * type = target type of the result
544 * elem = the source of array element, it will be owned by the result
545 * dim = element number of the result
547 * Constructed ArrayLiteralExp
549 ArrayLiteralExp
*createBlockDuplicatedArrayLiteral(Loc loc
, Type
*type
,
550 Expression
*elem
, size_t dim
)
552 if (type
->ty
== Tsarray
&& type
->nextOf()->ty
== Tsarray
&& elem
->type
->ty
!= Tsarray
)
554 // If it is a multidimensional array literal, do it recursively
555 TypeSArray
*tsa
= (TypeSArray
*)type
->nextOf();
556 size_t len
= (size_t)tsa
->dim
->toInteger();
557 elem
= createBlockDuplicatedArrayLiteral(loc
, type
->nextOf(), elem
, len
);
561 Type
*tb
= elem
->type
->toBasetype();
562 const bool mustCopy
= tb
->ty
== Tstruct
|| tb
->ty
== Tsarray
;
564 Expressions
*elements
= new Expressions();
565 elements
->setDim(dim
);
566 for (size_t i
= 0; i
< dim
; i
++)
568 (*elements
)[i
] = mustCopy
? copyLiteral(elem
).copy() : elem
;
570 ArrayLiteralExp
*ale
= new ArrayLiteralExp(loc
, elements
);
572 ale
->ownedByCtfe
= OWNEDctfe
;
576 /******************************
578 * Create a string literal consisting of 'value' duplicated 'dim' times.
580 StringExp
*createBlockDuplicatedStringLiteral(Loc loc
, Type
*type
,
581 unsigned value
, size_t dim
, unsigned char sz
)
583 utf8_t
*s
= (utf8_t
*)mem
.xcalloc(dim
+ 1, sz
);
584 for (size_t elemi
= 0; elemi
< dim
; ++elemi
)
588 case 1: s
[elemi
] = (utf8_t
)value
; break;
589 case 2: ((unsigned short *)s
)[elemi
] = (unsigned short)value
; break;
590 case 4: ((unsigned *)s
)[elemi
] = value
; break;
594 StringExp
*se
= new StringExp(loc
, s
, dim
);
597 se
->committed
= true;
598 se
->ownedByCtfe
= OWNEDctfe
;
602 // Return true if t is an AA
603 bool isAssocArray(Type
*t
)
606 if (t
->ty
== Taarray
)
611 // Given a template AA type, extract the corresponding built-in AA type
612 TypeAArray
*toBuiltinAAType(Type
*t
)
615 if (t
->ty
== Taarray
)
616 return (TypeAArray
*)t
;
621 /************** TypeInfo operations ************************************/
623 // Return true if type is TypeInfo_Class
624 bool isTypeInfo_Class(Type
*type
)
626 return type
->ty
== Tclass
&&
627 (Type::dtypeinfo
== ((TypeClass
*)type
)->sym
||
628 Type::dtypeinfo
->isBaseOf(((TypeClass
*)type
)->sym
, NULL
));
631 /************** Pointer operations ************************************/
633 // Return true if t is a pointer (not a function pointer)
634 bool isPointer(Type
*t
)
636 Type
* tb
= t
->toBasetype();
637 return tb
->ty
== Tpointer
&& tb
->nextOf()->ty
!= Tfunction
;
640 // For CTFE only. Returns true if 'e' is true or a non-null pointer.
641 bool isTrueBool(Expression
*e
)
643 return e
->isBool(true) ||
644 ((e
->type
->ty
== Tpointer
|| e
->type
->ty
== Tclass
) && e
->op
!= TOKnull
);
647 /* Is it safe to convert from srcPointee* to destPointee* ?
648 * srcPointee is the genuine type (never void).
649 * destPointee may be void.
651 bool isSafePointerCast(Type
*srcPointee
, Type
*destPointee
)
653 // It's safe to cast S** to D** if it's OK to cast S* to D*
654 while (srcPointee
->ty
== Tpointer
&& destPointee
->ty
== Tpointer
)
656 srcPointee
= srcPointee
->nextOf();
657 destPointee
= destPointee
->nextOf();
660 // It's OK if both are the same (modulo const)
661 if (srcPointee
->constConv(destPointee
))
664 // It's OK if function pointers differ only in safe/pure/nothrow
665 if (srcPointee
->ty
== Tfunction
&& destPointee
->ty
== Tfunction
)
666 return srcPointee
->covariant(destPointee
) == 1;
668 // it's OK to cast to void*
669 if (destPointee
->ty
== Tvoid
)
672 // It's OK to cast from V[K] to void*
673 if (srcPointee
->ty
== Taarray
&& destPointee
== Type::tvoidptr
)
676 // It's OK if they are the same size (static array of) integers, eg:
678 // int[5][] --> uint[5][]
679 if (srcPointee
->ty
== Tsarray
&& destPointee
->ty
== Tsarray
)
681 if (srcPointee
->size() != destPointee
->size())
683 srcPointee
= srcPointee
->baseElemOf();
684 destPointee
= destPointee
->baseElemOf();
686 return srcPointee
->isintegral() &&
687 destPointee
->isintegral() &&
688 srcPointee
->size() == destPointee
->size();
691 Expression
*getAggregateFromPointer(Expression
*e
, dinteger_t
*ofs
)
694 if (e
->op
== TOKaddress
)
695 e
= ((AddrExp
*)e
)->e1
;
696 if (e
->op
== TOKsymoff
)
697 *ofs
= ((SymOffExp
*)e
)->offset
;
698 if (e
->op
== TOKdotvar
)
700 Expression
*ex
= ((DotVarExp
*)e
)->e1
;
701 VarDeclaration
*v
= ((DotVarExp
*)e
)->var
->isVarDeclaration();
703 StructLiteralExp
*se
= ex
->op
== TOKclassreference
? ((ClassReferenceExp
*)ex
)->value
: (StructLiteralExp
*)ex
;
704 // We can't use getField, because it makes a copy
706 if (ex
->op
== TOKclassreference
)
707 i
= ((ClassReferenceExp
*)ex
)->getFieldIndex(e
->type
, v
->offset
);
709 i
= se
->getFieldIndex(e
->type
, v
->offset
);
710 e
= (*se
->elements
)[i
];
712 if (e
->op
== TOKindex
)
714 IndexExp
*ie
= (IndexExp
*)e
;
715 // Note that each AA element is part of its own memory block
716 if ((ie
->e1
->type
->ty
== Tarray
||
717 ie
->e1
->type
->ty
== Tsarray
||
718 ie
->e1
->op
== TOKstring
||
719 ie
->e1
->op
== TOKarrayliteral
) &&
720 ie
->e2
->op
== TOKint64
)
722 *ofs
= ie
->e2
->toInteger();
726 if (e
->op
== TOKslice
&& e
->type
->toBasetype()->ty
== Tsarray
)
728 SliceExp
*se
= (SliceExp
*)e
;
729 if ((se
->e1
->type
->ty
== Tarray
||
730 se
->e1
->type
->ty
== Tsarray
||
731 se
->e1
->op
== TOKstring
||
732 se
->e1
->op
== TOKarrayliteral
) &&
733 se
->lwr
->op
== TOKint64
)
735 *ofs
= se
->lwr
->toInteger();
742 /** Return true if agg1 and agg2 are pointers to the same memory block
744 bool pointToSameMemoryBlock(Expression
*agg1
, Expression
*agg2
)
749 // For integers cast to pointers, we regard them as non-comparable
750 // unless they are identical. (This may be overly strict).
751 if (agg1
->op
== TOKint64
&& agg2
->op
== TOKint64
&&
752 agg1
->toInteger() == agg2
->toInteger())
757 // Note that type painting can occur with VarExp, so we
758 // must compare the variables being pointed to.
759 if (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
760 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
)
764 if (agg1
->op
== TOKsymoff
&& agg2
->op
== TOKsymoff
&&
765 ((SymOffExp
*)agg1
)->var
== ((SymOffExp
*)agg2
)->var
)
773 // return e1 - e2 as an integer, or error if not possible
774 UnionExp
pointerDifference(Loc loc
, Type
*type
, Expression
*e1
, Expression
*e2
)
777 dinteger_t ofs1
, ofs2
;
778 Expression
*agg1
= getAggregateFromPointer(e1
, &ofs1
);
779 Expression
*agg2
= getAggregateFromPointer(e2
, &ofs2
);
782 Type
*pointee
= ((TypePointer
*)agg1
->type
)->next
;
783 dinteger_t sz
= pointee
->size();
784 new(&ue
) IntegerExp(loc
, (ofs1
- ofs2
) * sz
, type
);
786 else if (agg1
->op
== TOKstring
&& agg2
->op
== TOKstring
)
788 if (((StringExp
*)agg1
)->string
== ((StringExp
*)agg2
)->string
)
790 Type
*pointee
= ((TypePointer
*)agg1
->type
)->next
;
791 dinteger_t sz
= pointee
->size();
792 new(&ue
) IntegerExp(loc
, (ofs1
- ofs2
) * sz
, type
);
795 else if (agg1
->op
== TOKsymoff
&& agg2
->op
== TOKsymoff
&&
796 ((SymOffExp
*)agg1
)->var
== ((SymOffExp
*)agg2
)->var
)
798 new(&ue
) IntegerExp(loc
, ofs1
- ofs2
, type
);
802 error(loc
, "%s - %s cannot be interpreted at compile time: cannot subtract "
803 "pointers to two different memory blocks",
804 e1
->toChars(), e2
->toChars());
805 new(&ue
) CTFEExp(TOKcantexp
);
810 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
811 // and op is TOKadd or TOKmin
812 UnionExp
pointerArithmetic(Loc loc
, TOK op
, Type
*type
,
813 Expression
*eptr
, Expression
*e2
)
817 if (eptr
->type
->nextOf()->ty
== Tvoid
)
819 error(loc
, "cannot perform arithmetic on void* pointers at compile time");
821 new(&ue
) CTFEExp(TOKcantexp
);
826 if (eptr
->op
== TOKaddress
)
827 eptr
= ((AddrExp
*)eptr
)->e1
;
828 Expression
*agg1
= getAggregateFromPointer(eptr
, &ofs1
);
829 if (agg1
->op
== TOKsymoff
)
831 if (((SymOffExp
*)agg1
)->var
->type
->ty
!= Tsarray
)
833 error(loc
, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
837 else if (agg1
->op
!= TOKstring
&& agg1
->op
!= TOKarrayliteral
)
839 error(loc
, "cannot perform pointer arithmetic on non-arrays at compile time");
842 dinteger_t ofs2
= e2
->toInteger();
844 Type
*pointee
= ((TypeNext
*)agg1
->type
->toBasetype())->next
;
845 dinteger_t sz
= pointee
->size();
849 if (agg1
->op
== TOKsymoff
)
852 len
= ((TypeSArray
*)((SymOffExp
*)agg1
)->var
->type
)->dim
->toInteger();
856 Expression
*dollar
= ArrayLength(Type::tsize_t
, agg1
).copy();
857 assert(!CTFEExp::isCantExp(dollar
));
859 len
= dollar
->toInteger();
861 if (op
== TOKadd
|| op
== TOKaddass
|| op
== TOKplusplus
)
863 else if (op
== TOKmin
|| op
== TOKminass
|| op
== TOKminusminus
)
867 error(loc
, "CTFE internal error: bad pointer operation");
871 if (indx
< 0 || len
< (dinteger_t
)indx
)
873 error(loc
, "cannot assign pointer to index %lld inside memory block [0..%lld]", (ulonglong
)indx
, (ulonglong
)len
);
877 if (agg1
->op
== TOKsymoff
)
879 new(&ue
) SymOffExp(loc
, ((SymOffExp
*)agg1
)->var
, indx
* sz
);
880 SymOffExp
*se
= (SymOffExp
*)ue
.exp();
885 if (agg1
->op
!= TOKarrayliteral
&& agg1
->op
!= TOKstring
)
887 error(loc
, "CTFE internal error: pointer arithmetic %s", agg1
->toChars());
891 if (eptr
->type
->toBasetype()->ty
== Tsarray
)
893 dinteger_t dim
= ((TypeSArray
*)eptr
->type
->toBasetype())->dim
->toInteger();
895 // Create a CTFE pointer &agg1[indx .. indx+dim]
896 SliceExp
*se
= new SliceExp(loc
, agg1
,
897 new IntegerExp(loc
, indx
, Type::tsize_t
),
898 new IntegerExp(loc
, indx
+ dim
, Type::tsize_t
));
899 se
->type
= type
->toBasetype()->nextOf();
900 new(&ue
) AddrExp(loc
, se
);
901 ue
.exp()->type
= type
;
905 // Create a CTFE pointer &agg1[indx]
906 IntegerExp
*ofs
= new IntegerExp(loc
, indx
, Type::tsize_t
);
907 Expression
*ie
= new IndexExp(loc
, agg1
, ofs
);
908 ie
->type
= type
->toBasetype()->nextOf(); // Bugzilla 13992
909 new(&ue
) AddrExp(loc
, ie
);
910 ue
.exp()->type
= type
;
914 // Return 1 if true, 0 if false
915 // -1 if comparison is illegal because they point to non-comparable memory blocks
916 int comparePointers(TOK op
, Expression
*agg1
, dinteger_t ofs1
, Expression
*agg2
, dinteger_t ofs2
)
918 if (pointToSameMemoryBlock(agg1
, agg2
))
923 case TOKlt
: n
= (ofs1
< ofs2
); break;
924 case TOKle
: n
= (ofs1
<= ofs2
); break;
925 case TOKgt
: n
= (ofs1
> ofs2
); break;
926 case TOKge
: n
= (ofs1
>= ofs2
); break;
928 case TOKequal
: n
= (ofs1
== ofs2
); break;
930 case TOKnotequal
: n
= (ofs1
!= ofs2
); break;
936 bool null1
= (agg1
->op
== TOKnull
);
937 bool null2
= (agg2
->op
== TOKnull
);
944 case TOKlt
: cmp
= null1
&& !null2
; break;
945 case TOKgt
: cmp
= !null1
&& null2
; break;
946 case TOKle
: cmp
= null1
; break;
947 case TOKge
: cmp
= null2
; break;
950 case TOKnotidentity
: // 'cmp' gets inverted below
952 cmp
= (null1
== null2
);
964 case TOKnotidentity
: // 'cmp' gets inverted below
969 return -1; // memory blocks are different
972 if (op
== TOKnotidentity
|| op
== TOKnotequal
)
977 // True if conversion from type 'from' to 'to' involves a reinterpret_cast
978 // floating point -> integer or integer -> floating point
979 bool isFloatIntPaint(Type
*to
, Type
*from
)
981 return from
->size() == to
->size() &&
982 ((from
->isintegral() && to
->isfloating()) ||
983 (from
->isfloating() && to
->isintegral()));
986 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
987 Expression
*paintFloatInt(Expression
*fromVal
, Type
*to
)
989 if (exceptionOrCantInterpret(fromVal
))
992 assert(to
->size() == 4 || to
->size() == 8);
993 return Compiler::paintAsType(fromVal
, to
);
996 /******** Constant folding, with support for CTFE ***************************/
998 /// Return true if non-pointer expression e can be compared
999 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
1000 bool isCtfeComparable(Expression
*e
)
1002 if (e
->op
== TOKslice
)
1003 e
= ((SliceExp
*)e
)->e1
;
1005 if (e
->isConst() != 1)
1007 if (e
->op
== TOKnull
||
1008 e
->op
== TOKstring
||
1009 e
->op
== TOKfunction
||
1010 e
->op
== TOKdelegate
||
1011 e
->op
== TOKarrayliteral
||
1012 e
->op
== TOKstructliteral
||
1013 e
->op
== TOKassocarrayliteral
||
1014 e
->op
== TOKclassreference
)
1018 // Bugzilla 14123: TypeInfo object is comparable in CTFE
1019 if (e
->op
== TOKtypeid
)
1027 /// Map TOK comparison ops
1028 template <typename N
>
1029 static bool numCmp(TOK op
, N n1
, N n2
)
1047 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1048 int specificCmp(TOK op
, int rawCmp
)
1050 return numCmp
<int>(op
, rawCmp
, 0);
1053 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1054 int intUnsignedCmp(TOK op
, dinteger_t n1
, dinteger_t n2
)
1056 return numCmp
<dinteger_t
>(op
, n1
, n2
);
1059 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1060 int intSignedCmp(TOK op
, sinteger_t n1
, sinteger_t n2
)
1062 return numCmp
<sinteger_t
>(op
, n1
, n2
);
1065 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1066 int realCmp(TOK op
, real_t r1
, real_t r2
)
1068 // Don't rely on compiler, handle NAN arguments separately
1069 if (CTFloat::isNaN(r1
) || CTFloat::isNaN(r2
)) // if unordered
1085 return numCmp
<real_t
>(op
, r1
, r2
);
1089 int ctfeRawCmp(Loc loc
, Expression
*e1
, Expression
*e2
);
1091 /* Conceptually the same as memcmp(e1, e2).
1092 * e1 and e2 may be strings, arrayliterals, or slices.
1093 * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1094 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1096 int ctfeCmpArrays(Loc loc
, Expression
*e1
, Expression
*e2
, uinteger_t len
)
1098 // Resolve slices, if necessary
1103 if (x
->op
== TOKslice
)
1105 lo1
= ((SliceExp
*)x
)->lwr
->toInteger();
1106 x
= ((SliceExp
*)x
)->e1
;
1108 StringExp
*se1
= (x
->op
== TOKstring
) ? (StringExp
*)x
: NULL
;
1109 ArrayLiteralExp
*ae1
= (x
->op
== TOKarrayliteral
) ? (ArrayLiteralExp
*)x
: NULL
;
1112 if (x
->op
== TOKslice
)
1114 lo2
= ((SliceExp
*)x
)->lwr
->toInteger();
1115 x
= ((SliceExp
*)x
)->e1
;
1117 StringExp
*se2
= (x
->op
== TOKstring
) ? (StringExp
*)x
: NULL
;
1118 ArrayLiteralExp
*ae2
= (x
->op
== TOKarrayliteral
) ? (ArrayLiteralExp
*)x
: NULL
;
1120 // Now both must be either TOKarrayliteral or TOKstring
1122 return sliceCmpStringWithString(se1
, se2
, (size_t)lo1
, (size_t)lo2
, (size_t)len
);
1124 return sliceCmpStringWithArray(se1
, ae2
, (size_t)lo1
, (size_t)lo2
, (size_t)len
);
1126 return -sliceCmpStringWithArray(se2
, ae1
, (size_t)lo2
, (size_t)lo1
, (size_t)len
);
1128 assert (ae1
&& ae2
);
1129 // Comparing two array literals. This case is potentially recursive.
1130 // If they aren't strings, we just need an equality check rather than
1132 bool needCmp
= ae1
->type
->nextOf()->isintegral();
1133 for (size_t i
= 0; i
< (size_t)len
; i
++)
1135 Expression
*ee1
= (*ae1
->elements
)[(size_t)(lo1
+ i
)];
1136 Expression
*ee2
= (*ae2
->elements
)[(size_t)(lo2
+ i
)];
1139 sinteger_t c
= ee1
->toInteger() - ee2
->toInteger();
1147 if (ctfeRawCmp(loc
, ee1
, ee2
))
1154 /* Given a delegate expression e, return .funcptr.
1155 * If e is NullExp, return NULL.
1157 FuncDeclaration
*funcptrOf(Expression
*e
)
1159 assert(e
->type
->ty
== Tdelegate
);
1161 if (e
->op
== TOKdelegate
)
1162 return ((DelegateExp
*)e
)->func
;
1163 if (e
->op
== TOKfunction
)
1164 return ((FuncExp
*)e
)->fd
;
1165 assert(e
->op
== TOKnull
);
1169 bool isArray(Expression
*e
)
1171 return e
->op
== TOKarrayliteral
|| e
->op
== TOKstring
||
1172 e
->op
== TOKslice
|| e
->op
== TOKnull
;
1175 /* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1176 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1178 int ctfeRawCmp(Loc loc
, Expression
*e1
, Expression
*e2
)
1180 if (e1
->op
== TOKclassreference
|| e2
->op
== TOKclassreference
)
1182 if (e1
->op
== TOKclassreference
&& e2
->op
== TOKclassreference
&&
1183 ((ClassReferenceExp
*)e1
)->value
== ((ClassReferenceExp
*)e2
)->value
)
1187 if (e1
->op
== TOKtypeid
&& e2
->op
== TOKtypeid
)
1189 // printf("e1: %s\n", e1->toChars());
1190 // printf("e2: %s\n", e2->toChars());
1191 Type
*t1
= isType(((TypeidExp
*)e1
)->obj
);
1192 Type
*t2
= isType(((TypeidExp
*)e2
)->obj
);
1198 // null == null, regardless of type
1200 if (e1
->op
== TOKnull
&& e2
->op
== TOKnull
)
1203 if (e1
->type
->ty
== Tpointer
&& e2
->type
->ty
== Tpointer
)
1205 // Can only be an equality test.
1207 dinteger_t ofs1
, ofs2
;
1208 Expression
*agg1
= getAggregateFromPointer(e1
, &ofs1
);
1209 Expression
*agg2
= getAggregateFromPointer(e2
, &ofs2
);
1210 if ((agg1
== agg2
) || (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
1211 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
))
1218 if (e1
->type
->ty
== Tdelegate
&& e2
->type
->ty
== Tdelegate
)
1220 // If .funcptr isn't the same, they are not equal
1222 if (funcptrOf(e1
) != funcptrOf(e2
))
1225 // If both are delegate literals, assume they have the
1226 // same closure pointer. TODO: We don't support closures yet!
1227 if (e1
->op
== TOKfunction
&& e2
->op
== TOKfunction
)
1229 assert(e1
->op
== TOKdelegate
&& e2
->op
== TOKdelegate
);
1231 // Same .funcptr. Do they have the same .ptr?
1232 Expression
* ptr1
= ((DelegateExp
*)e1
)->e1
;
1233 Expression
* ptr2
= ((DelegateExp
*)e2
)->e1
;
1235 dinteger_t ofs1
, ofs2
;
1236 Expression
*agg1
= getAggregateFromPointer(ptr1
, &ofs1
);
1237 Expression
*agg2
= getAggregateFromPointer(ptr2
, &ofs2
);
1238 // If they are TOKvar, it means they are FuncDeclarations
1239 if ((agg1
== agg2
&& ofs1
== ofs2
) ||
1240 (agg1
->op
== TOKvar
&& agg2
->op
== TOKvar
&&
1241 ((VarExp
*)agg1
)->var
== ((VarExp
*)agg2
)->var
))
1247 if (isArray(e1
) && isArray(e2
))
1249 uinteger_t len1
= resolveArrayLength(e1
);
1250 uinteger_t len2
= resolveArrayLength(e2
);
1251 // workaround for dmc optimizer bug calculating wrong len for
1252 // uinteger_t len = (len1 < len2 ? len1 : len2);
1253 // if (len == 0) ...
1254 if (len1
> 0 && len2
> 0)
1256 uinteger_t len
= (len1
< len2
? len1
: len2
);
1257 int res
= ctfeCmpArrays(loc
, e1
, e2
, len
);
1261 return (int)(len1
- len2
);
1263 if (e1
->type
->isintegral())
1265 return e1
->toInteger() != e2
->toInteger();
1269 if (e1
->type
->isreal())
1275 else if (e1
->type
->isimaginary())
1277 r1
= e1
->toImaginary();
1278 r2
= e2
->toImaginary();
1280 if (CTFloat::isNaN(r1
) || CTFloat::isNaN(r2
)) // if unordered
1289 else if (e1
->type
->iscomplex())
1291 return e1
->toComplex() != e2
->toComplex();
1294 if (e1
->op
== TOKstructliteral
&& e2
->op
== TOKstructliteral
)
1296 StructLiteralExp
*es1
= (StructLiteralExp
*)e1
;
1297 StructLiteralExp
*es2
= (StructLiteralExp
*)e2
;
1298 // For structs, we only need to return 0 or 1 (< and > aren't legal).
1300 if (es1
->sd
!= es2
->sd
)
1302 else if ((!es1
->elements
|| !es1
->elements
->dim
) &&
1303 (!es2
->elements
|| !es2
->elements
->dim
))
1304 return 0; // both arrays are empty
1305 else if (!es1
->elements
|| !es2
->elements
)
1307 else if (es1
->elements
->dim
!= es2
->elements
->dim
)
1311 for (size_t i
= 0; i
< es1
->elements
->dim
; i
++)
1313 Expression
*ee1
= (*es1
->elements
)[i
];
1314 Expression
*ee2
= (*es2
->elements
)[i
];
1320 int cmp
= ctfeRawCmp(loc
, ee1
, ee2
);
1324 return 0; // All elements are equal
1327 if (e1
->op
== TOKassocarrayliteral
&& e2
->op
== TOKassocarrayliteral
)
1329 AssocArrayLiteralExp
*es1
= (AssocArrayLiteralExp
*)e1
;
1330 AssocArrayLiteralExp
*es2
= (AssocArrayLiteralExp
*)e2
;
1332 size_t dim
= es1
->keys
->dim
;
1333 if (es2
->keys
->dim
!= dim
)
1336 bool *used
= (bool *)mem
.xmalloc(sizeof(bool) * dim
);
1337 memset(used
, 0, sizeof(bool) * dim
);
1339 for (size_t i
= 0; i
< dim
; ++i
)
1341 Expression
*k1
= (*es1
->keys
)[i
];
1342 Expression
*v1
= (*es1
->values
)[i
];
1343 Expression
*v2
= NULL
;
1344 for (size_t j
= 0; j
< dim
; ++j
)
1348 Expression
*k2
= (*es2
->keys
)[j
];
1350 if (ctfeRawCmp(loc
, k1
, k2
))
1353 v2
= (*es2
->values
)[j
];
1356 if (!v2
|| ctfeRawCmp(loc
, v1
, v2
))
1365 error(loc
, "CTFE internal error: bad compare of `%s` and `%s`", e1
->toChars(), e2
->toChars());
1370 /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
1371 int ctfeEqual(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1373 int cmp
= !ctfeRawCmp(loc
, e1
, e2
);
1374 if (op
== TOKnotequal
)
1379 /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
1380 int ctfeIdentity(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1382 //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
1383 // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars());
1385 if (e1
->op
== TOKnull
)
1387 cmp
= (e2
->op
== TOKnull
);
1389 else if (e2
->op
== TOKnull
)
1393 else if (e1
->op
== TOKsymoff
&& e2
->op
== TOKsymoff
)
1395 SymOffExp
*es1
= (SymOffExp
*)e1
;
1396 SymOffExp
*es2
= (SymOffExp
*)e2
;
1397 cmp
= (es1
->var
== es2
->var
&& es1
->offset
== es2
->offset
);
1399 else if (e1
->type
->isreal())
1400 cmp
= RealEquals(e1
->toReal(), e2
->toReal());
1401 else if (e1
->type
->isimaginary())
1402 cmp
= RealEquals(e1
->toImaginary(), e2
->toImaginary());
1403 else if (e1
->type
->iscomplex())
1405 complex_t v1
= e1
->toComplex();
1406 complex_t v2
= e2
->toComplex();
1407 cmp
= RealEquals(creall(v1
), creall(v2
)) &&
1408 RealEquals(cimagl(v1
), cimagl(v1
));
1411 cmp
= !ctfeRawCmp(loc
, e1
, e2
);
1413 if (op
== TOKnotidentity
|| op
== TOKnotequal
)
1418 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
1419 int ctfeCmp(Loc loc
, TOK op
, Expression
*e1
, Expression
*e2
)
1421 Type
*t1
= e1
->type
->toBasetype();
1422 Type
*t2
= e2
->type
->toBasetype();
1424 if (t1
->isString() && t2
->isString())
1425 return specificCmp(op
, ctfeRawCmp(loc
, e1
, e2
));
1426 else if (t1
->isreal())
1427 return realCmp(op
, e1
->toReal(), e2
->toReal());
1428 else if (t1
->isimaginary())
1429 return realCmp(op
, e1
->toImaginary(), e2
->toImaginary());
1430 else if (t1
->isunsigned() || t2
->isunsigned())
1431 return intUnsignedCmp(op
, e1
->toInteger(), e2
->toInteger());
1433 return intSignedCmp(op
, e1
->toInteger(), e2
->toInteger());
1436 UnionExp
ctfeCat(Loc loc
, Type
*type
, Expression
*e1
, Expression
*e2
)
1438 Type
*t1
= e1
->type
->toBasetype();
1439 Type
*t2
= e2
->type
->toBasetype();
1441 if (e2
->op
== TOKstring
&& e1
->op
== TOKarrayliteral
&&
1442 t1
->nextOf()->isintegral())
1444 // [chars] ~ string => string (only valid for CTFE)
1445 StringExp
*es1
= (StringExp
*)e2
;
1446 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e1
;
1447 size_t len
= es1
->len
+ es2
->elements
->dim
;
1448 unsigned char sz
= es1
->sz
;
1450 void *s
= mem
.xmalloc((len
+ 1) * sz
);
1451 memcpy((char *)s
+ sz
* es2
->elements
->dim
, es1
->string
, es1
->len
* sz
);
1452 for (size_t i
= 0; i
< es2
->elements
->dim
; i
++)
1454 Expression
*es2e
= (*es2
->elements
)[i
];
1455 if (es2e
->op
!= TOKint64
)
1457 new(&ue
) CTFEExp(TOKcantexp
);
1460 dinteger_t v
= es2e
->toInteger();
1461 Port::valcpy((utf8_t
*)s
+ i
* sz
, v
, sz
);
1464 // Add terminating 0
1465 memset((utf8_t
*)s
+ len
* sz
, 0, sz
);
1467 new(&ue
) StringExp(loc
, s
, len
);
1468 StringExp
*es
= (StringExp
*)ue
.exp();
1474 if (e1
->op
== TOKstring
&& e2
->op
== TOKarrayliteral
&&
1475 t2
->nextOf()->isintegral())
1477 // string ~ [chars] => string (only valid for CTFE)
1478 // Concatenate the strings
1479 StringExp
*es1
= (StringExp
*)e1
;
1480 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e2
;
1481 size_t len
= es1
->len
+ es2
->elements
->dim
;
1482 unsigned char sz
= es1
->sz
;
1484 void *s
= mem
.xmalloc((len
+ 1) * sz
);
1485 memcpy(s
, es1
->string
, es1
->len
* sz
);
1486 for (size_t i
= 0; i
< es2
->elements
->dim
; i
++)
1488 Expression
*es2e
= (*es2
->elements
)[i
];
1489 if (es2e
->op
!= TOKint64
)
1491 new(&ue
) CTFEExp(TOKcantexp
);
1494 dinteger_t v
= es2e
->toInteger();
1495 Port::valcpy((utf8_t
*)s
+ (es1
->len
+ i
) * sz
, v
, sz
);
1498 // Add terminating 0
1499 memset((utf8_t
*)s
+ len
* sz
, 0, sz
);
1501 new(&ue
) StringExp(loc
, s
, len
);
1502 StringExp
*es
= (StringExp
*)ue
.exp();
1504 es
->committed
= 0; //es1->committed;
1508 if (e1
->op
== TOKarrayliteral
&& e2
->op
== TOKarrayliteral
&&
1509 t1
->nextOf()->equals(t2
->nextOf()))
1511 // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
1512 ArrayLiteralExp
*es1
= (ArrayLiteralExp
*)e1
;
1513 ArrayLiteralExp
*es2
= (ArrayLiteralExp
*)e2
;
1515 new(&ue
) ArrayLiteralExp(es1
->loc
, copyLiteralArray(es1
->elements
));
1516 es1
= (ArrayLiteralExp
*)ue
.exp();
1517 es1
->elements
->insert(es1
->elements
->dim
, copyLiteralArray(es2
->elements
));
1521 if (e1
->op
== TOKarrayliteral
&& e2
->op
== TOKnull
&&
1522 t1
->nextOf()->equals(t2
->nextOf()))
1524 // [ e1 ] ~ null ----> [ e1 ].dup
1525 ue
= paintTypeOntoLiteralCopy(type
, copyLiteral(e1
).copy());
1528 if (e1
->op
== TOKnull
&& e2
->op
== TOKarrayliteral
&&
1529 t1
->nextOf()->equals(t2
->nextOf()))
1531 // null ~ [ e2 ] ----> [ e2 ].dup
1532 ue
= paintTypeOntoLiteralCopy(type
, copyLiteral(e2
).copy());
1535 ue
= Cat(type
, e1
, e2
);
1539 /* Given an AA literal 'ae', and a key 'e2':
1540 * Return ae[e2] if present, or NULL if not found.
1542 Expression
*findKeyInAA(Loc loc
, AssocArrayLiteralExp
*ae
, Expression
*e2
)
1544 /* Search the keys backwards, in case there are duplicate keys
1546 for (size_t i
= ae
->keys
->dim
; i
;)
1549 Expression
*ekey
= (*ae
->keys
)[i
];
1550 int eq
= ctfeEqual(loc
, TOKequal
, ekey
, e2
);
1553 return (*ae
->values
)[i
];
1559 /* Same as for constfold.Index, except that it only works for static arrays,
1560 * dynamic arrays, and strings. We know that e1 is an
1561 * interpreted CTFE expression, so it cannot have side-effects.
1563 Expression
*ctfeIndex(Loc loc
, Type
*type
, Expression
*e1
, uinteger_t indx
)
1565 //printf("ctfeIndex(e1 = %s)\n", e1->toChars());
1567 if (e1
->op
== TOKstring
)
1569 StringExp
*es1
= (StringExp
*)e1
;
1570 if (indx
>= es1
->len
)
1572 error(loc
, "string index %llu is out of bounds [0 .. %llu]", (ulonglong
)indx
, (ulonglong
)es1
->len
);
1573 return CTFEExp::cantexp
;
1575 return new IntegerExp(loc
, es1
->charAt(indx
), type
);
1577 assert(e1
->op
== TOKarrayliteral
);
1579 ArrayLiteralExp
*ale
= (ArrayLiteralExp
*)e1
;
1580 if (indx
>= ale
->elements
->dim
)
1582 error(loc
, "array index %llu is out of bounds %s[0 .. %llu]", (ulonglong
)indx
, e1
->toChars(), (ulonglong
)ale
->elements
->dim
);
1583 return CTFEExp::cantexp
;
1585 Expression
*e
= (*ale
->elements
)[(size_t)indx
];
1586 return paintTypeOntoLiteral(type
, e
);
1590 Expression
*ctfeCast(Loc loc
, Type
*type
, Type
*to
, Expression
*e
)
1592 if (e
->op
== TOKnull
)
1593 return paintTypeOntoLiteral(to
, e
);
1594 if (e
->op
== TOKclassreference
)
1596 // Disallow reinterpreting class casts. Do this by ensuring that
1597 // the original class can implicitly convert to the target class
1598 ClassDeclaration
*originalClass
= ((ClassReferenceExp
*)e
)->originalClass();
1599 if (originalClass
->type
->implicitConvTo(to
->mutableOf()))
1600 return paintTypeOntoLiteral(to
, e
);
1602 return new NullExp(loc
, to
);
1604 // Allow TypeInfo type painting
1605 if (isTypeInfo_Class(e
->type
) && e
->type
->implicitConvTo(to
))
1606 return paintTypeOntoLiteral(to
, e
);
1607 // Allow casting away const for struct literals
1608 if (e
->op
== TOKstructliteral
&&
1609 e
->type
->toBasetype()->castMod(0) == to
->toBasetype()->castMod(0))
1611 return paintTypeOntoLiteral(to
, e
);
1615 if (e
->type
->equals(type
) && type
->equals(to
))
1617 // necessary not to change e's address for pointer comparisons
1620 else if (to
->toBasetype()->ty
== Tarray
&& type
->toBasetype()->ty
== Tarray
&&
1621 to
->toBasetype()->nextOf()->size() == type
->toBasetype()->nextOf()->size())
1623 // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[]
1624 return paintTypeOntoLiteral(to
, e
);
1628 r
= Cast(loc
, type
, to
, e
).copy();
1630 if (CTFEExp::isCantExp(r
))
1631 error(loc
, "cannot cast %s to %s at compile time", e
->toChars(), to
->toChars());
1632 if (e
->op
== TOKarrayliteral
)
1633 ((ArrayLiteralExp
*)e
)->ownedByCtfe
= OWNEDctfe
;
1634 if (e
->op
== TOKstring
)
1635 ((StringExp
*)e
)->ownedByCtfe
= OWNEDctfe
;
1639 /******** Assignment helper functions ***************************/
1641 /* Set dest = src, where both dest and src are container value literals
1642 * (ie, struct literals, or static arrays (can be an array literal or a string))
1643 * Assignment is recursively in-place.
1644 * Purpose: any reference to a member of 'dest' will remain valid after the
1647 void assignInPlace(Expression
*dest
, Expression
*src
)
1649 assert(dest
->op
== TOKstructliteral
||
1650 dest
->op
== TOKarrayliteral
||
1651 dest
->op
== TOKstring
);
1652 Expressions
*oldelems
;
1653 Expressions
*newelems
;
1654 if (dest
->op
== TOKstructliteral
)
1656 assert(dest
->op
== src
->op
);
1657 oldelems
= ((StructLiteralExp
*)dest
)->elements
;
1658 newelems
= ((StructLiteralExp
*)src
)->elements
;
1659 if (((StructLiteralExp
*)dest
)->sd
->isNested() && oldelems
->dim
== newelems
->dim
- 1)
1660 oldelems
->push(NULL
);
1662 else if (dest
->op
== TOKarrayliteral
&& src
->op
==TOKarrayliteral
)
1664 oldelems
= ((ArrayLiteralExp
*)dest
)->elements
;
1665 newelems
= ((ArrayLiteralExp
*)src
)->elements
;
1667 else if (dest
->op
== TOKstring
&& src
->op
== TOKstring
)
1669 sliceAssignStringFromString((StringExp
*)dest
, (StringExp
*)src
, 0);
1672 else if (dest
->op
== TOKarrayliteral
&& src
->op
== TOKstring
)
1674 sliceAssignArrayLiteralFromString((ArrayLiteralExp
*)dest
, (StringExp
*)src
, 0);
1677 else if (src
->op
== TOKarrayliteral
&& dest
->op
== TOKstring
)
1679 sliceAssignStringFromArrayLiteral((StringExp
*)dest
, (ArrayLiteralExp
*)src
, 0);
1685 assert(oldelems
->dim
== newelems
->dim
);
1687 for (size_t i
= 0; i
< oldelems
->dim
; ++i
)
1689 Expression
*e
= (*newelems
)[i
];
1690 Expression
*o
= (*oldelems
)[i
];
1691 if (e
->op
== TOKstructliteral
)
1693 assert(o
->op
== e
->op
);
1694 assignInPlace(o
, e
);
1696 else if (e
->type
->ty
== Tsarray
&& e
->op
!= TOKvoid
&&
1697 o
->type
->ty
== Tsarray
)
1699 assignInPlace(o
, e
);
1703 (*oldelems
)[i
] = (*newelems
)[i
];
1708 // Duplicate the elements array, then set field 'indexToChange' = newelem.
1709 Expressions
*changeOneElement(Expressions
*oldelems
, size_t indexToChange
, Expression
*newelem
)
1711 Expressions
*expsx
= new Expressions();
1712 ++CtfeStatus::numArrayAllocs
;
1713 expsx
->setDim(oldelems
->dim
);
1714 for (size_t j
= 0; j
< expsx
->dim
; j
++)
1716 if (j
== indexToChange
)
1717 (*expsx
)[j
] = newelem
;
1719 (*expsx
)[j
] = (*oldelems
)[j
];
1724 // Given an AA literal aae, set aae[index] = newval and return newval.
1725 Expression
*assignAssocArrayElement(Loc loc
, AssocArrayLiteralExp
*aae
,
1726 Expression
*index
, Expression
*newval
)
1728 /* Create new associative array literal reflecting updated key/value
1730 Expressions
*keysx
= aae
->keys
;
1731 Expressions
*valuesx
= aae
->values
;
1733 for (size_t j
= valuesx
->dim
; j
; )
1736 Expression
*ekey
= (*aae
->keys
)[j
];
1737 int eq
= ctfeEqual(loc
, TOKequal
, ekey
, index
);
1740 (*valuesx
)[j
] = newval
;
1746 // Append index/newval to keysx[]/valuesx[]
1747 valuesx
->push(newval
);
1753 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
1754 /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
1755 /// all new elements will be set to the default initializer for the element type.
1756 UnionExp
changeArrayLiteralLength(Loc loc
, TypeArray
*arrayType
,
1757 Expression
*oldval
, size_t oldlen
, size_t newlen
)
1760 Type
*elemType
= arrayType
->next
;
1762 Expression
*defaultElem
= elemType
->defaultInitLiteral(loc
);
1763 Expressions
*elements
= new Expressions();
1764 elements
->setDim(newlen
);
1768 if (oldval
->op
== TOKslice
)
1770 indxlo
= (size_t)((SliceExp
*)oldval
)->lwr
->toInteger();
1771 oldval
= ((SliceExp
*)oldval
)->e1
;
1773 size_t copylen
= oldlen
< newlen
? oldlen
: newlen
;
1774 if (oldval
->op
== TOKstring
)
1776 StringExp
*oldse
= (StringExp
*)oldval
;
1777 void *s
= mem
.xcalloc(newlen
+ 1, oldse
->sz
);
1778 memcpy(s
, oldse
->string
, copylen
* oldse
->sz
);
1779 unsigned defaultValue
= (unsigned)(defaultElem
->toInteger());
1780 for (size_t elemi
= copylen
; elemi
< newlen
; ++elemi
)
1784 case 1: (( utf8_t
*)s
)[(size_t)(indxlo
+ elemi
)] = ( utf8_t
)defaultValue
; break;
1785 case 2: ((utf16_t
*)s
)[(size_t)(indxlo
+ elemi
)] = (utf16_t
)defaultValue
; break;
1786 case 4: ((utf32_t
*)s
)[(size_t)(indxlo
+ elemi
)] = (utf32_t
)defaultValue
; break;
1790 new(&ue
) StringExp(loc
, s
, newlen
);
1791 StringExp
*se
= (StringExp
*)ue
.exp();
1792 se
->type
= arrayType
;
1794 se
->committed
= oldse
->committed
;
1795 se
->ownedByCtfe
= OWNEDctfe
;
1801 assert(oldval
->op
== TOKarrayliteral
);
1802 ArrayLiteralExp
*ae
= (ArrayLiteralExp
*)oldval
;
1803 for (size_t i
= 0; i
< copylen
; i
++)
1804 (*elements
)[i
] = (*ae
->elements
)[indxlo
+ i
];
1806 if (elemType
->ty
== Tstruct
|| elemType
->ty
== Tsarray
)
1808 /* If it is an aggregate literal representing a value type,
1809 * we need to create a unique copy for each element
1811 for (size_t i
= copylen
; i
< newlen
; i
++)
1812 (*elements
)[i
] = copyLiteral(defaultElem
).copy();
1816 for (size_t i
= copylen
; i
< newlen
; i
++)
1817 (*elements
)[i
] = defaultElem
;
1819 new(&ue
) ArrayLiteralExp(loc
, elements
);
1820 ArrayLiteralExp
*aae
= (ArrayLiteralExp
*)ue
.exp();
1821 aae
->type
= arrayType
;
1822 aae
->ownedByCtfe
= OWNEDctfe
;
1827 /*************************** CTFE Sanity Checks ***************************/
1829 bool isCtfeValueValid(Expression
*newval
)
1831 Type
*tb
= newval
->type
->toBasetype();
1833 if (newval
->op
== TOKint64
||
1834 newval
->op
== TOKfloat64
||
1835 newval
->op
== TOKchar
||
1836 newval
->op
== TOKcomplex80
)
1838 return tb
->isscalar();
1840 if (newval
->op
== TOKnull
)
1842 return tb
->ty
== Tnull
||
1843 tb
->ty
== Tpointer
||
1845 tb
->ty
== Taarray
||
1847 tb
->ty
== Tdelegate
;
1850 if (newval
->op
== TOKstring
)
1851 return true; // CTFE would directly use the StringExp in AST.
1852 if (newval
->op
== TOKarrayliteral
)
1853 return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
1854 if (newval
->op
== TOKassocarrayliteral
)
1855 return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
1856 if (newval
->op
== TOKstructliteral
)
1857 return true; //((StructLiteralExp *)newval)->ownedByCtfe;
1858 if (newval
->op
== TOKclassreference
)
1861 if (newval
->op
== TOKvector
)
1862 return true; // vector literal
1864 if (newval
->op
== TOKfunction
)
1865 return true; // function literal or delegate literal
1866 if (newval
->op
== TOKdelegate
)
1868 // &struct.func or &clasinst.func
1870 Expression
*ethis
= ((DelegateExp
*)newval
)->e1
;
1871 return (ethis
->op
== TOKstructliteral
||
1872 ethis
->op
== TOKclassreference
||
1873 (ethis
->op
== TOKvar
&& ((VarExp
*)ethis
)->var
== ((DelegateExp
*)newval
)->func
));
1875 if (newval
->op
== TOKsymoff
)
1877 // function pointer, or pointer to static variable
1878 Declaration
*d
= ((SymOffExp
*)newval
)->var
;
1879 return d
->isFuncDeclaration() || d
->isDataseg();
1881 if (newval
->op
== TOKtypeid
)
1886 if (newval
->op
== TOKaddress
)
1888 // e1 should be a CTFE reference
1889 Expression
*e1
= ((AddrExp
*)newval
)->e1
;
1890 return tb
->ty
== Tpointer
&&
1891 ((e1
->op
== TOKstructliteral
&& isCtfeValueValid(e1
)) ||
1892 (e1
->op
== TOKvar
) ||
1893 (e1
->op
== TOKdotvar
&& isCtfeReferenceValid(e1
)) ||
1894 (e1
->op
== TOKindex
&& isCtfeReferenceValid(e1
)) ||
1895 (e1
->op
== TOKslice
&& e1
->type
->toBasetype()->ty
== Tsarray
));
1897 if (newval
->op
== TOKslice
)
1899 // e1 should be an array aggregate
1900 SliceExp
*se
= (SliceExp
*)newval
;
1901 assert(se
->lwr
&& se
->lwr
->op
== TOKint64
);
1902 assert(se
->upr
&& se
->upr
->op
== TOKint64
);
1903 return (tb
->ty
== Tarray
||
1904 tb
->ty
== Tsarray
) &&
1905 (se
->e1
->op
== TOKstring
||
1906 se
->e1
->op
== TOKarrayliteral
);
1909 if (newval
->op
== TOKvoid
)
1910 return true; // uninitialized value
1912 newval
->error("CTFE internal error: illegal CTFE value %s", newval
->toChars());
1916 bool isCtfeReferenceValid(Expression
*newval
)
1918 if (newval
->op
== TOKthis
)
1920 if (newval
->op
== TOKvar
)
1922 VarDeclaration
*v
= ((VarExp
*)newval
)->var
->isVarDeclaration();
1924 // Must not be a reference to a reference
1927 if (newval
->op
== TOKindex
)
1929 Expression
*eagg
= ((IndexExp
*)newval
)->e1
;
1930 return eagg
->op
== TOKstring
||
1931 eagg
->op
== TOKarrayliteral
||
1932 eagg
->op
== TOKassocarrayliteral
;
1934 if (newval
->op
== TOKdotvar
)
1936 Expression
*eagg
= ((DotVarExp
*)newval
)->e1
;
1937 return (eagg
->op
== TOKstructliteral
|| eagg
->op
== TOKclassreference
) &&
1938 isCtfeValueValid(eagg
);
1941 // Internally a ref variable may directly point a stack memory.
1942 // e.g. ref int v = 1;
1943 return isCtfeValueValid(newval
);
1946 // Used for debugging only
1947 void showCtfeExpr(Expression
*e
, int level
)
1949 for (int i
= level
; i
> 0; --i
) printf(" ");
1950 Expressions
*elements
= NULL
;
1951 // We need the struct definition to detect block assignment
1952 StructDeclaration
*sd
= NULL
;
1953 ClassDeclaration
*cd
= NULL
;
1954 if (e
->op
== TOKstructliteral
)
1956 elements
= ((StructLiteralExp
*)e
)->elements
;
1957 sd
= ((StructLiteralExp
*)e
)->sd
;
1958 printf("STRUCT type = %s %p:\n", e
->type
->toChars(),
1961 else if (e
->op
== TOKclassreference
)
1963 elements
= ((ClassReferenceExp
*)e
)->value
->elements
;
1964 cd
= ((ClassReferenceExp
*)e
)->originalClass();
1965 printf("CLASS type = %s %p:\n", e
->type
->toChars(),
1966 ((ClassReferenceExp
*)e
)->value
);
1968 else if (e
->op
== TOKarrayliteral
)
1970 elements
= ((ArrayLiteralExp
*)e
)->elements
;
1971 printf("ARRAY LITERAL type=%s %p:\n", e
->type
->toChars(),
1974 else if (e
->op
== TOKassocarrayliteral
)
1976 printf("AA LITERAL type=%s %p:\n", e
->type
->toChars(),
1979 else if (e
->op
== TOKstring
)
1981 printf("STRING %s %p\n", e
->toChars(),
1982 ((StringExp
*)e
)->string
);
1984 else if (e
->op
== TOKslice
)
1986 printf("SLICE %p: %s\n", e
, e
->toChars());
1987 showCtfeExpr(((SliceExp
*)e
)->e1
, level
+ 1);
1989 else if (e
->op
== TOKvar
)
1991 printf("VAR %p %s\n", e
, e
->toChars());
1992 VarDeclaration
*v
= ((VarExp
*)e
)->var
->isVarDeclaration();
1993 if (v
&& getValue(v
))
1994 showCtfeExpr(getValue(v
), level
+ 1);
1996 else if (e
->op
== TOKaddress
)
1998 // This is potentially recursive. We mustn't try to print the thing we're pointing to.
1999 printf("POINTER %p to %p: %s\n", e
, ((AddrExp
*)e
)->e1
, e
->toChars());
2002 printf("VALUE %p: %s\n", e
, e
->toChars());
2006 size_t fieldsSoFar
= 0;
2007 for (size_t i
= 0; i
< elements
->dim
; i
++)
2009 Expression
*z
= NULL
;
2010 VarDeclaration
*v
= NULL
;
2013 printf("...(total %d elements)\n", (int)elements
->dim
);
2023 while (i
- fieldsSoFar
>= cd
->fields
.dim
)
2025 fieldsSoFar
+= cd
->fields
.dim
;
2027 for (int j
= level
; j
> 0; --j
) printf(" ");
2028 printf(" BASE CLASS: %s\n", cd
->toChars());
2030 v
= cd
->fields
[i
- fieldsSoFar
];
2031 assert((elements
->dim
+ i
) >= (fieldsSoFar
+ cd
->fields
.dim
));
2032 size_t indx
= (elements
->dim
- fieldsSoFar
)- cd
->fields
.dim
+ i
;
2033 assert(indx
< elements
->dim
);
2034 z
= (*elements
)[indx
];
2038 for (int j
= level
; j
> 0; --j
) printf(" ");
2045 // If it is a void assignment, use the default initializer
2046 if ((v
->type
->ty
!= z
->type
->ty
) && v
->type
->ty
== Tsarray
)
2048 for (int j
= level
; --j
; ) printf(" ");
2049 printf(" field: block initalized static array\n");
2053 showCtfeExpr(z
, level
+ 1);
2058 /*************************** Void initialization ***************************/
2060 UnionExp
voidInitLiteral(Type
*t
, VarDeclaration
*var
)
2063 if (t
->ty
== Tsarray
)
2065 TypeSArray
*tsa
= (TypeSArray
*)t
;
2066 Expression
*elem
= voidInitLiteral(tsa
->next
, var
).copy();
2068 // For aggregate value types (structs, static arrays) we must
2069 // create an a separate copy for each element.
2070 bool mustCopy
= (elem
->op
== TOKarrayliteral
|| elem
->op
== TOKstructliteral
);
2072 Expressions
*elements
= new Expressions();
2073 size_t d
= (size_t)tsa
->dim
->toInteger();
2074 elements
->setDim(d
);
2075 for (size_t i
= 0; i
< d
; i
++)
2077 if (mustCopy
&& i
> 0)
2078 elem
= copyLiteral(elem
).copy();
2079 (*elements
)[i
] = elem
;
2081 new(&ue
) ArrayLiteralExp(var
->loc
, elements
);
2082 ArrayLiteralExp
*ae
= (ArrayLiteralExp
*)ue
.exp();
2084 ae
->ownedByCtfe
= OWNEDctfe
;
2086 else if (t
->ty
== Tstruct
)
2088 TypeStruct
*ts
= (TypeStruct
*)t
;
2089 Expressions
*exps
= new Expressions();
2090 exps
->setDim(ts
->sym
->fields
.dim
);
2091 for (size_t i
= 0; i
< ts
->sym
->fields
.dim
; i
++)
2093 (*exps
)[i
] = voidInitLiteral(ts
->sym
->fields
[i
]->type
, ts
->sym
->fields
[i
]).copy();
2095 new(&ue
) StructLiteralExp(var
->loc
, ts
->sym
, exps
);
2096 StructLiteralExp
*se
= (StructLiteralExp
*)ue
.exp();
2098 se
->ownedByCtfe
= OWNEDctfe
;
2101 new(&ue
) VoidInitExp(var
, t
);