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