1
2/* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 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 */
20struct 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 */
36class ClassReferenceExp : public Expression
37{
38public:
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);
48    void accept(Visitor *v) { v->visit(this); }
49};
50
51// The various functions are used only to detect compiler CTFE bugs
52Expression *getValue(VarDeclaration *vd);
53bool hasValue(VarDeclaration *vd);
54void setValueNull(VarDeclaration *vd);
55void setValueWithoutChecking(VarDeclaration *vd, Expression *newval);
56void 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
60int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v);
61
62
63/** An uninitialized value
64 */
65class VoidInitExp : public Expression
66{
67public:
68    VarDeclaration *var;
69
70    VoidInitExp(VarDeclaration *var, Type *type);
71    const char *toChars();
72    void accept(Visitor *v) { v->visit(this); }
73};
74
75// Create an appropriate void initializer
76UnionExp voidInitLiteral(Type *t, VarDeclaration *var);
77
78/** Fake class which holds the thrown exception.
79    Used for implementing exception handling.
80*/
81class ThrownExceptionExp : public Expression
82{
83public:
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();
89    void accept(Visitor *v) { v->visit(this); }
90};
91
92/****************************************************************/
93
94// This type is only used by the interpreter.
95
96class CTFEExp : public Expression
97{
98public:
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
110    static bool isCantExp(Expression *e) { return e && e->op == TOKcantexp; }
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
118bool exceptionOrCantInterpret(Expression *e);
119
120// Used for debugging only
121void showCtfeExpr(Expression *e, int level = 0);
122
123/// Return true if this is a valid CTFE expression
124bool isCtfeValueValid(Expression *newval);
125bool isCtfeReferenceValid(Expression *newval);
126
127/// Given expr, which evaluates to an array/AA/string literal,
128/// return true if it needs to be copied
129bool 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.
133UnionExp copyLiteral(Expression *e);
134
135/// Set this literal to the given type, copying it if necessary
136Expression *paintTypeOntoLiteral(Type *type, Expression *lit);
137Expression *paintTypeOntoLiteral(UnionExp *pue, Type *type, Expression *lit);
138UnionExp paintTypeOntoLiteralCopy(Type *type, Expression *lit);
139
140/// Convert from a CTFE-internal slice, into a normal Expression
141Expression *resolveSlice(Expression *e, UnionExp *pue = NULL);
142
143/// Determine the array length, without interpreting the expression.
144uinteger_t resolveArrayLength(Expression *e);
145
146/// Create an array literal consisting of 'elem' duplicated 'dim' times.
147ArrayLiteralExp *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.
151StringExp *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 */
161void assignInPlace(Expression *dest, Expression *src);
162
163/// Duplicate the elements array, then set field 'indexToChange' = newelem.
164Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);
165
166/// Given an AA literal aae,  set arr[index] = newval and return the new array.
167Expression *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.
173UnionExp 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)
179bool isPointer(Type *t);
180
181// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer.
182bool 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.
187bool 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.
191Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs);
192
193/// Return true if agg1 and agg2 are pointers to the same memory block
194bool pointToSameMemoryBlock(Expression *agg1, Expression *agg2);
195
196// return e1 - e2 as an integer, or error if not possible
197UnionExp 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
201int 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
205UnionExp 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
210bool isFloatIntPaint(Type *to, Type *from);
211
212// Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
213Expression *paintFloatInt(UnionExp *pue, Expression *fromVal, Type *to);
214
215/// Return true if t is an AA
216bool isAssocArray(Type *t);
217
218/// Given a template AA type, extract the corresponding built-in AA type
219TypeAArray *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 */
225Expression *findKeyInAA(Loc loc, AssocArrayLiteralExp *ae, Expression *e2);
226
227/// True if type is TypeInfo_Class
228bool 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
237bool isCtfeComparable(Expression *e);
238
239/// Evaluate ==, !=.  Resolves slices before comparing. Returns 0 or 1
240int ctfeEqual(Loc loc, TOK op, Expression *e1, Expression *e2);
241
242/// Evaluate is, !is.  Resolves slices before comparing. Returns 0 or 1
243int ctfeIdentity(Loc loc, TOK op, Expression *e1, Expression *e2);
244
245/// Returns rawCmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
246int specificCmp(TOK op, int rawCmp);
247
248/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
249int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2);
250
251/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
252int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2);
253
254/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
255int realCmp(TOK op, real_t r1, real_t r2);
256
257/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
258int ctfeCmp(Loc loc, TOK op, Expression *e1, Expression *e2);
259
260/// Returns e1 ~ e2. Resolves slices before concatenation.
261UnionExp 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.
265Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx);
266
267/// Cast 'e' of type 'type' to type 'to'.
268Expression *ctfeCast(UnionExp *pue, Loc loc, Type *type, Type *to, Expression *e);
269