1 
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/dlang/dmd/blob/master/src/ctfe.h
9  */
10 
11 #pragma once
12 
13 #include "arraytypes.h"
14 #include "tokens.h"
15 #include "expression.h"
16 
17 /**
18    Global status of the CTFE engine. Mostly used for performance diagnostics
19  */
20 struct CtfeStatus
21 {
22     static int callDepth; // current number of recursive calls
23     /* When printing a stack trace,
24      * suppress this number of calls
25      */
26     static int stackTraceCallsToSuppress;
27     static int maxCallDepth; // highest number of recursive calls
28     static int numArrayAllocs; // Number of allocated arrays
29     static int numAssignments; // total number of assignments executed
30 };
31 
32 /**
33   A reference to a class, or an interface. We need this when we
34   point to a base class (we must record what the type is).
35  */
36 class ClassReferenceExp : public Expression
37 {
38 public:
39     StructLiteralExp *value;
40     ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type);
41     ClassDeclaration *originalClass();
42 
43     /// Return index of the field, or -1 if not found
44     int getFieldIndex(Type *fieldtype, unsigned fieldoffset);
45     /// Return index of the field, or -1 if not found
46     /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
47     int findFieldIndexByName(VarDeclaration *v);
accept(Visitor * v)48     void accept(Visitor *v) { v->visit(this); }
49 };
50 
51 // The various functions are used only to detect compiler CTFE bugs
52 Expression *getValue(VarDeclaration *vd);
53 bool hasValue(VarDeclaration *vd);
54 void setValueNull(VarDeclaration *vd);
55 void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
56 void setValue(VarDeclaration *vd, Expression *newval);
57 
58 /// Return index of the field, or -1 if not found
59 /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
60 int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
61 
62 
63 /** An uninitialized value
64  */
65 class VoidInitExp : public Expression
66 {
67 public:
68     VarDeclaration *var;
69 
70     VoidInitExp(VarDeclaration *var, Type *type);
71     const char *toChars();
accept(Visitor * v)72     void accept(Visitor *v) { v->visit(this); }
73 };
74 
75 // Create an appropriate void initializer
76 UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
77 
78 /** Fake class which holds the thrown exception.
79     Used for implementing exception handling.
80 */
81 class ThrownExceptionExp : public Expression
82 {
83 public:
84     ClassReferenceExp *thrown; // the thing being tossed
85     ThrownExceptionExp(Loc loc, ClassReferenceExp *victim);
86     const char *toChars();
87     /// Generate an error message when this exception is not caught
88     void generateUncaughtError();
accept(Visitor * v)89     void accept(Visitor *v) { v->visit(this); }
90 };
91 
92 /****************************************************************/
93 
94 // This type is only used by the interpreter.
95 
96 class CTFEExp : public Expression
97 {
98 public:
99     CTFEExp(TOK tok);
100 
101     const char *toChars();
102 
103     // Handy instances to share
104     static CTFEExp *cantexp;
105     static CTFEExp *voidexp;
106     static CTFEExp *breakexp;
107     static CTFEExp *continueexp;
108     static CTFEExp *gotoexp;
109 
isCantExp(Expression * e)110     static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
isGotoExp(Expression * e)111     static bool isGotoExp(Expression *e) { return e && e->op == TOKgoto; }
112 };
113 
114 /****************************************************************/
115 
116 
117 /// True if 'e' is TOKcantexp, or an exception
118 bool exceptionOrCantInterpret(Expression *e);
119 
120 // Used for debugging only
121 void showCtfeExpr(Expression *e, int level = 0);
122 
123 /// Return true if this is a valid CTFE expression
124 bool isCtfeValueValid(Expression *newval);
125 bool isCtfeReferenceValid(Expression *newval);
126 
127 /// Given expr, which evaluates to an array/AA/string literal,
128 /// return true if it needs to be copied
129 bool needToCopyLiteral(Expression *expr);
130 
131 /// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
132 /// This value will be used for in-place modification.
133 UnionExp copyLiteral(Expression *e);
134 
135 /// Set this literal to the given type, copying it if necessary
136 Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
137 Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit);
138 UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
139 
140 /// Convert from a CTFE-internal slice, into a normal Expression
141 Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
142 
143 /// Determine the array length, without interpreting the expression.
144 uinteger_t resolveArrayLength(Expression *e);
145 
146 /// Create an array literal consisting of 'elem' duplicated 'dim' times.
147 ArrayLiteralExp *createBlockDuplicatedArrayLiteral(UnionExp *pue, Loc loc, Type *type,
148         Expression *elem, size_t dim);
149 
150 /// Create a string literal consisting of 'value' duplicated 'dim' times.
151 StringExp *createBlockDuplicatedStringLiteral(UnionExp *pue, Loc loc, Type *type,
152         unsigned value, size_t dim, unsigned char sz);
153 
154 
155 /* Set dest = src, where both dest and src are container value literals
156  * (ie, struct literals, or static arrays (can be an array literal or a string)
157  * Assignment is recursively in-place.
158  * Purpose: any reference to a member of 'dest' will remain valid after the
159  * assignment.
160  */
161 void assignInPlace(Expression *dest, Expression *src);
162 
163 /// Duplicate the elements array, then set field 'indexToChange' = newelem.
164 Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
165 
166 /// Given an AA literal aae,  set arr[index] = newval and return the new array.
167 Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae,
168     Expression *index, Expression *newval);
169 
170 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
171 /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
172 /// all new elements will be set to the default initializer for the element type.
173 UnionExp changeArrayLiteralLength(Loc loc, TypeArray *arrayType,
174     Expression *oldval,  size_t oldlen, size_t newlen);
175 
176 
177 
178 /// Return true if t is a pointer (not a function pointer)
179 bool isPointer(Type *t);
180 
181 // For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
182 bool isTrueBool(Expression *e);
183 
184 /// Is it safe to convert from srcPointee* to destPointee* ?
185 ///  srcPointee is the genuine type (never void).
186 ///  destPointee may be void.
187 bool isSafePointerCast(Type *srcPointee, Type *destPointee);
188 
189 /// Given pointer e, return the memory block expression it points to,
190 /// and set ofs to the offset within that memory block.
191 Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
192 
193 /// Return true if agg1 and agg2 are pointers to the same memory block
194 bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
195 
196 // return e1 - e2 as an integer, or error if not possible
197 UnionExp pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2);
198 
199 /// Return 1 if true, 0 if false
200 /// -1 if comparison is illegal because they point to non-comparable memory blocks
201 int comparePointers(TOK op, Expression *agg1, dinteger_t ofs1, Expression *agg2, dinteger_t ofs2);
202 
203 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
204 // and op is TOKadd or TOKmin
205 UnionExp pointerArithmetic(Loc loc, TOK op, Type *type,
206     Expression *eptr, Expression *e2);
207 
208 // True if conversion from type 'from' to 'to' involves a reinterpret_cast
209 // floating point -> integer or integer -> floating point
210 bool isFloatIntPaint(Type *to, Type *from);
211 
212 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
213 Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to);
214 
215 /// Return true if t is an AA
216 bool isAssocArray(Type *t);
217 
218 /// Given a template AA type, extract the corresponding built-in AA type
219 TypeAArray *toBuiltinAAType(Type *t);
220 
221 /*  Given an AA literal 'ae', and a key 'e2':
222  *  Return ae[e2] if present, or NULL if not found.
223  *  Return TOKcantexp on error.
224  */
225 Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
226 
227 /// True if type is TypeInfo_Class
228 bool isTypeInfo_Class(Type *type);
229 
230 
231 /***********************************************
232       COW const-folding operations
233 ***********************************************/
234 
235 /// Return true if non-pointer expression e can be compared
236 /// with >,is, ==, etc, using ctfeCmp, ctfeEquals, ctfeIdentity
237 bool isCtfeComparable(Expression *e);
238 
239 /// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
240 int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
241 
242 /// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
243 int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
244 
245 /// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
246 int specificCmp(TOK op, int rawCmp);
247 
248 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
249 int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
250 
251 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
252 int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
253 
254 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
255 int realCmp(TOK op, real_t r1, real_t r2);
256 
257 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
258 int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
259 
260 /// Returns e1 ~ e2. Resolves slices before concatenation.
261 UnionExp ctfeCat(Loc loc, Type *type, Expression *e1, Expression *e2);
262 
263 /// Same as for constfold.Index, except that it only works for static arrays,
264 /// dynamic arrays, and strings.
265 Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
266 
267 /// Cast 'e' of type 'type' to type 'to'.
268 Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e);
269