1 1.1 mrg /** 2 1.1 mrg * CTFE for expressions involving pointers, slices, array concatenation etc. 3 1.1 mrg * 4 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 5 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d) 8 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_ctfeexpr.html 9 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d 10 1.1 mrg */ 11 1.1 mrg 12 1.1 mrg module dmd.ctfeexpr; 13 1.1 mrg 14 1.1 mrg import core.stdc.stdio; 15 1.1 mrg import core.stdc.stdlib; 16 1.1 mrg import core.stdc.string; 17 1.1 mrg import dmd.arraytypes; 18 1.1 mrg import dmd.astenums; 19 1.1 mrg import dmd.constfold; 20 1.1 mrg import dmd.compiler; 21 1.1 mrg import dmd.dclass; 22 1.1 mrg import dmd.declaration; 23 1.1 mrg import dmd.dinterpret; 24 1.1 mrg import dmd.dstruct; 25 1.1 mrg import dmd.dtemplate; 26 1.1 mrg import dmd.errors; 27 1.1 mrg import dmd.expression; 28 1.1 mrg import dmd.func; 29 1.1 mrg import dmd.globals; 30 1.1 mrg import dmd.mtype; 31 1.1 mrg import dmd.root.complex; 32 1.1 mrg import dmd.root.ctfloat; 33 1.1 mrg import dmd.root.port; 34 1.1 mrg import dmd.root.rmem; 35 1.1 mrg import dmd.tokens; 36 1.1 mrg import dmd.visitor; 37 1.1 mrg 38 1.1 mrg 39 1.1 mrg /*********************************************************** 40 1.1 mrg * A reference to a class, or an interface. We need this when we 41 1.1 mrg * point to a base class (we must record what the type is). 42 1.1 mrg */ 43 1.1 mrg extern (C++) final class ClassReferenceExp : Expression 44 1.1 mrg { 45 1.1 mrg StructLiteralExp value; 46 1.1 mrg 47 1.1 mrg extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) 48 1.1 mrg { 49 1.1 mrg super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp)); 50 1.1 mrg assert(lit && lit.sd && lit.sd.isClassDeclaration()); 51 1.1 mrg this.value = lit; 52 1.1 mrg this.type = type; 53 1.1 mrg } 54 1.1 mrg 55 1.1 mrg ClassDeclaration originalClass() 56 1.1 mrg { 57 1.1 mrg return value.sd.isClassDeclaration(); 58 1.1 mrg } 59 1.1 mrg 60 1.1 mrg // Return index of the field, or -1 if not found 61 1.1 mrg private int getFieldIndex(Type fieldtype, uint fieldoffset) 62 1.1 mrg { 63 1.1 mrg ClassDeclaration cd = originalClass(); 64 1.1 mrg uint fieldsSoFar = 0; 65 1.1 mrg for (size_t j = 0; j < value.elements.dim; j++) 66 1.1 mrg { 67 1.1 mrg while (j - fieldsSoFar >= cd.fields.dim) 68 1.1 mrg { 69 1.1 mrg fieldsSoFar += cd.fields.dim; 70 1.1 mrg cd = cd.baseClass; 71 1.1 mrg } 72 1.1 mrg VarDeclaration v2 = cd.fields[j - fieldsSoFar]; 73 1.1 mrg if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size()) 74 1.1 mrg { 75 1.1 mrg return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); 76 1.1 mrg } 77 1.1 mrg } 78 1.1 mrg return -1; 79 1.1 mrg } 80 1.1 mrg 81 1.1 mrg // Return index of the field, or -1 if not found 82 1.1 mrg // Same as getFieldIndex, but checks for a direct match with the VarDeclaration 83 1.1 mrg int findFieldIndexByName(VarDeclaration v) 84 1.1 mrg { 85 1.1 mrg ClassDeclaration cd = originalClass(); 86 1.1 mrg size_t fieldsSoFar = 0; 87 1.1 mrg for (size_t j = 0; j < value.elements.dim; j++) 88 1.1 mrg { 89 1.1 mrg while (j - fieldsSoFar >= cd.fields.dim) 90 1.1 mrg { 91 1.1 mrg fieldsSoFar += cd.fields.dim; 92 1.1 mrg cd = cd.baseClass; 93 1.1 mrg } 94 1.1 mrg VarDeclaration v2 = cd.fields[j - fieldsSoFar]; 95 1.1 mrg if (v == v2) 96 1.1 mrg { 97 1.1 mrg return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); 98 1.1 mrg } 99 1.1 mrg } 100 1.1 mrg return -1; 101 1.1 mrg } 102 1.1 mrg 103 1.1 mrg override void accept(Visitor v) 104 1.1 mrg { 105 1.1 mrg v.visit(this); 106 1.1 mrg } 107 1.1 mrg } 108 1.1 mrg 109 1.1 mrg /************************* 110 1.1 mrg * Same as getFieldIndex, but checks for a direct match with the VarDeclaration 111 1.1 mrg * Returns: 112 1.1 mrg * index of the field, or -1 if not found 113 1.1 mrg */ 114 1.1 mrg int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure 115 1.1 mrg { 116 1.1 mrg foreach (i, field; sd.fields) 117 1.1 mrg { 118 1.1 mrg if (field == v) 119 1.1 mrg return cast(int)i; 120 1.1 mrg } 121 1.1 mrg return -1; 122 1.1 mrg } 123 1.1 mrg 124 1.1 mrg /*********************************************************** 125 1.1 mrg * Fake class which holds the thrown exception. 126 1.1 mrg * Used for implementing exception handling. 127 1.1 mrg */ 128 1.1 mrg extern (C++) final class ThrownExceptionExp : Expression 129 1.1 mrg { 130 1.1 mrg ClassReferenceExp thrown; // the thing being tossed 131 1.1 mrg 132 1.1 mrg extern (D) this(const ref Loc loc, ClassReferenceExp victim) 133 1.1 mrg { 134 1.1 mrg super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp)); 135 1.1 mrg this.thrown = victim; 136 1.1 mrg this.type = victim.type; 137 1.1 mrg } 138 1.1 mrg 139 1.1 mrg override const(char)* toChars() const 140 1.1 mrg { 141 1.1 mrg return "CTFE ThrownException"; 142 1.1 mrg } 143 1.1 mrg 144 1.1 mrg // Generate an error message when this exception is not caught 145 1.1 mrg extern (D) void generateUncaughtError() 146 1.1 mrg { 147 1.1 mrg UnionExp ue = void; 148 1.1 mrg Expression e = resolveSlice((*thrown.value.elements)[0], &ue); 149 1.1 mrg StringExp se = e.toStringExp(); 150 1.1 mrg thrown.error("uncaught CTFE exception `%s(%s)`", thrown.type.toChars(), se ? se.toChars() : e.toChars()); 151 1.1 mrg /* Also give the line where the throw statement was. We won't have it 152 1.1 mrg * in the case where the ThrowStatement is generated internally 153 1.1 mrg * (eg, in ScopeStatement) 154 1.1 mrg */ 155 1.1 mrg if (loc.isValid() && !loc.equals(thrown.loc)) 156 1.1 mrg .errorSupplemental(loc, "thrown from here"); 157 1.1 mrg } 158 1.1 mrg 159 1.1 mrg override void accept(Visitor v) 160 1.1 mrg { 161 1.1 mrg v.visit(this); 162 1.1 mrg } 163 1.1 mrg } 164 1.1 mrg 165 1.1 mrg /*********************************************************** 166 1.1 mrg * This type is only used by the interpreter. 167 1.1 mrg */ 168 1.1 mrg extern (C++) final class CTFEExp : Expression 169 1.1 mrg { 170 1.1 mrg extern (D) this(EXP tok) 171 1.1 mrg { 172 1.1 mrg super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp)); 173 1.1 mrg type = Type.tvoid; 174 1.1 mrg } 175 1.1 mrg 176 1.1 mrg override const(char)* toChars() const 177 1.1 mrg { 178 1.1 mrg switch (op) 179 1.1 mrg { 180 1.1 mrg case EXP.cantExpression: 181 1.1 mrg return "<cant>"; 182 1.1 mrg case EXP.voidExpression: 183 1.1 mrg return "cast(void)0"; 184 1.1 mrg case EXP.showCtfeContext: 185 1.1 mrg return "<error>"; 186 1.1 mrg case EXP.break_: 187 1.1 mrg return "<break>"; 188 1.1 mrg case EXP.continue_: 189 1.1 mrg return "<continue>"; 190 1.1 mrg case EXP.goto_: 191 1.1 mrg return "<goto>"; 192 1.1 mrg default: 193 1.1 mrg assert(0); 194 1.1 mrg } 195 1.1 mrg } 196 1.1 mrg 197 1.1 mrg extern (D) __gshared CTFEExp cantexp; 198 1.1 mrg extern (D) __gshared CTFEExp voidexp; 199 1.1 mrg extern (D) __gshared CTFEExp breakexp; 200 1.1 mrg extern (D) __gshared CTFEExp continueexp; 201 1.1 mrg extern (D) __gshared CTFEExp gotoexp; 202 1.1 mrg /* Used when additional information is needed regarding 203 1.1 mrg * a ctfe error. 204 1.1 mrg */ 205 1.1 mrg extern (D) __gshared CTFEExp showcontext; 206 1.1 mrg 207 1.1 mrg extern (D) static bool isCantExp(const Expression e) 208 1.1 mrg { 209 1.1 mrg return e && e.op == EXP.cantExpression; 210 1.1 mrg } 211 1.1 mrg 212 1.1 mrg extern (D) static bool isGotoExp(const Expression e) 213 1.1 mrg { 214 1.1 mrg return e && e.op == EXP.goto_; 215 1.1 mrg } 216 1.1 mrg } 217 1.1 mrg 218 1.1 mrg // True if 'e' is CTFEExp::cantexp, or an exception 219 1.1 mrg bool exceptionOrCantInterpret(const Expression e) 220 1.1 mrg { 221 1.1 mrg return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext); 222 1.1 mrg } 223 1.1 mrg 224 1.1 mrg /************** Aggregate literals (AA/string/array/struct) ******************/ 225 1.1 mrg // Given expr, which evaluates to an array/AA/string literal, 226 1.1 mrg // return true if it needs to be copied 227 1.1 mrg bool needToCopyLiteral(const Expression expr) 228 1.1 mrg { 229 1.1 mrg Expression e = cast()expr; 230 1.1 mrg for (;;) 231 1.1 mrg { 232 1.1 mrg switch (e.op) 233 1.1 mrg { 234 1.1 mrg case EXP.arrayLiteral: 235 1.1 mrg return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code; 236 1.1 mrg case EXP.assocArrayLiteral: 237 1.1 mrg return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code; 238 1.1 mrg case EXP.structLiteral: 239 1.1 mrg return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code; 240 1.1 mrg case EXP.string_: 241 1.1 mrg case EXP.this_: 242 1.1 mrg case EXP.variable: 243 1.1 mrg return false; 244 1.1 mrg case EXP.assign: 245 1.1 mrg return false; 246 1.1 mrg case EXP.index: 247 1.1 mrg case EXP.dotVariable: 248 1.1 mrg case EXP.slice: 249 1.1 mrg case EXP.cast_: 250 1.1 mrg e = e.isUnaExp().e1; 251 1.1 mrg continue; 252 1.1 mrg case EXP.concatenate: 253 1.1 mrg return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2); 254 1.1 mrg case EXP.concatenateAssign: 255 1.1 mrg case EXP.concatenateElemAssign: 256 1.1 mrg case EXP.concatenateDcharAssign: 257 1.1 mrg e = e.isBinExp().e2; 258 1.1 mrg continue; 259 1.1 mrg default: 260 1.1 mrg return false; 261 1.1 mrg } 262 1.1 mrg } 263 1.1 mrg } 264 1.1 mrg 265 1.1 mrg private Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null) 266 1.1 mrg { 267 1.1 mrg if (!oldelems) 268 1.1 mrg return oldelems; 269 1.1 mrg incArrayAllocs(); 270 1.1 mrg auto newelems = new Expressions(oldelems.dim); 271 1.1 mrg foreach (i, el; *oldelems) 272 1.1 mrg { 273 1.1 mrg (*newelems)[i] = copyLiteral(el ? el : basis).copy(); 274 1.1 mrg } 275 1.1 mrg return newelems; 276 1.1 mrg } 277 1.1 mrg 278 1.1 mrg // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. 279 1.1 mrg // This value will be used for in-place modification. 280 1.1 mrg UnionExp copyLiteral(Expression e) 281 1.1 mrg { 282 1.1 mrg UnionExp ue = void; 283 1.1 mrg if (auto se = e.isStringExp()) // syntaxCopy doesn't make a copy for StringExp! 284 1.1 mrg { 285 1.1 mrg char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz); 286 1.1 mrg const slice = se.peekData(); 287 1.1 mrg memcpy(s, slice.ptr, slice.length); 288 1.1 mrg emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz); 289 1.1 mrg StringExp se2 = ue.exp().isStringExp(); 290 1.1 mrg se2.committed = se.committed; 291 1.1 mrg se2.postfix = se.postfix; 292 1.1 mrg se2.type = se.type; 293 1.1 mrg se2.ownedByCtfe = OwnedBy.ctfe; 294 1.1 mrg return ue; 295 1.1 mrg } 296 1.1 mrg if (auto ale = e.isArrayLiteralExp()) 297 1.1 mrg { 298 1.1 mrg auto elements = copyLiteralArray(ale.elements, ale.basis); 299 1.1 mrg 300 1.1 mrg emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements); 301 1.1 mrg 302 1.1 mrg ArrayLiteralExp r = ue.exp().isArrayLiteralExp(); 303 1.1 mrg r.ownedByCtfe = OwnedBy.ctfe; 304 1.1 mrg return ue; 305 1.1 mrg } 306 1.1 mrg if (auto aae = e.isAssocArrayLiteralExp()) 307 1.1 mrg { 308 1.1 mrg emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); 309 1.1 mrg AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp(); 310 1.1 mrg r.type = e.type; 311 1.1 mrg r.ownedByCtfe = OwnedBy.ctfe; 312 1.1 mrg return ue; 313 1.1 mrg } 314 1.1 mrg if (auto sle = e.isStructLiteralExp()) 315 1.1 mrg { 316 1.1 mrg /* syntaxCopy doesn't work for struct literals, because of a nasty special 317 1.1 mrg * case: block assignment is permitted inside struct literals, eg, 318 1.1 mrg * an int[4] array can be initialized with a single int. 319 1.1 mrg */ 320 1.1 mrg auto oldelems = sle.elements; 321 1.1 mrg auto newelems = new Expressions(oldelems.dim); 322 1.1 mrg foreach (i, ref el; *newelems) 323 1.1 mrg { 324 1.1 mrg // We need the struct definition to detect block assignment 325 1.1 mrg auto v = sle.sd.fields[i]; 326 1.1 mrg auto m = (*oldelems)[i]; 327 1.1 mrg 328 1.1 mrg // If it is a void assignment, use the default initializer 329 1.1 mrg if (!m) 330 1.1 mrg m = voidInitLiteral(v.type, v).copy(); 331 1.1 mrg 332 1.1 mrg if (v.type.ty == Tarray || v.type.ty == Taarray) 333 1.1 mrg { 334 1.1 mrg // Don't have to copy array references 335 1.1 mrg } 336 1.1 mrg else 337 1.1 mrg { 338 1.1 mrg // Buzilla 15681: Copy the source element always. 339 1.1 mrg m = copyLiteral(m).copy(); 340 1.1 mrg 341 1.1 mrg // Block assignment from inside struct literals 342 1.1 mrg if (v.type.ty != m.type.ty && v.type.ty == Tsarray) 343 1.1 mrg { 344 1.1 mrg auto tsa = v.type.isTypeSArray(); 345 1.1 mrg auto len = cast(size_t)tsa.dim.toInteger(); 346 1.1 mrg m = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, m, len); 347 1.1 mrg if (m == ue.exp()) 348 1.1 mrg m = ue.copy(); 349 1.1 mrg } 350 1.1 mrg } 351 1.1 mrg el = m; 352 1.1 mrg } 353 1.1 mrg emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype); 354 1.1 mrg auto r = ue.exp().isStructLiteralExp(); 355 1.1 mrg r.type = e.type; 356 1.1 mrg r.ownedByCtfe = OwnedBy.ctfe; 357 1.1 mrg r.origin = sle.origin; 358 1.1 mrg return ue; 359 1.1 mrg } 360 1.1 mrg if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_) 361 1.1 mrg { 362 1.1 mrg // Simple value types 363 1.1 mrg // Keep e1 for DelegateExp and DotVarExp 364 1.1 mrg emplaceExp!(UnionExp)(&ue, e); 365 1.1 mrg Expression r = ue.exp(); 366 1.1 mrg r.type = e.type; 367 1.1 mrg return ue; 368 1.1 mrg } 369 1.1 mrg if (auto se = e.isSliceExp()) 370 1.1 mrg { 371 1.1 mrg if (se.type.toBasetype().ty == Tsarray) 372 1.1 mrg { 373 1.1 mrg // same with resolveSlice() 374 1.1 mrg if (se.e1.op == EXP.null_) 375 1.1 mrg { 376 1.1 mrg emplaceExp!(NullExp)(&ue, se.loc, se.type); 377 1.1 mrg return ue; 378 1.1 mrg } 379 1.1 mrg ue = Slice(se.type, se.e1, se.lwr, se.upr); 380 1.1 mrg auto r = ue.exp().isArrayLiteralExp(); 381 1.1 mrg r.elements = copyLiteralArray(r.elements); 382 1.1 mrg r.ownedByCtfe = OwnedBy.ctfe; 383 1.1 mrg return ue; 384 1.1 mrg } 385 1.1 mrg else 386 1.1 mrg { 387 1.1 mrg // Array slices only do a shallow copy 388 1.1 mrg emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr); 389 1.1 mrg Expression r = ue.exp(); 390 1.1 mrg r.type = e.type; 391 1.1 mrg return ue; 392 1.1 mrg } 393 1.1 mrg } 394 1.1 mrg if (isPointer(e.type)) 395 1.1 mrg { 396 1.1 mrg // For pointers, we only do a shallow copy. 397 1.1 mrg if (auto ae = e.isAddrExp()) 398 1.1 mrg emplaceExp!(AddrExp)(&ue, e.loc, ae.e1); 399 1.1 mrg else if (auto ie = e.isIndexExp()) 400 1.1 mrg emplaceExp!(IndexExp)(&ue, e.loc, ie.e1, ie.e2); 401 1.1 mrg else if (auto dve = e.isDotVarExp()) 402 1.1 mrg { 403 1.1 mrg emplaceExp!(DotVarExp)(&ue, e.loc, dve.e1, dve.var, dve.hasOverloads); 404 1.1 mrg } 405 1.1 mrg else 406 1.1 mrg assert(0); 407 1.1 mrg 408 1.1 mrg Expression r = ue.exp(); 409 1.1 mrg r.type = e.type; 410 1.1 mrg return ue; 411 1.1 mrg } 412 1.1 mrg if (auto cre = e.isClassReferenceExp()) 413 1.1 mrg { 414 1.1 mrg emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type); 415 1.1 mrg return ue; 416 1.1 mrg } 417 1.1 mrg if (e.op == EXP.error) 418 1.1 mrg { 419 1.1 mrg emplaceExp!(UnionExp)(&ue, e); 420 1.1 mrg return ue; 421 1.1 mrg } 422 1.1 mrg e.error("CTFE internal error: literal `%s`", e.toChars()); 423 1.1 mrg assert(0); 424 1.1 mrg } 425 1.1 mrg 426 1.1 mrg /* Deal with type painting. 427 1.1 mrg * Type painting is a major nuisance: we can't just set 428 1.1 mrg * e.type = type, because that would change the original literal. 429 1.1 mrg * But, we can't simply copy the literal either, because that would change 430 1.1 mrg * the values of any pointers. 431 1.1 mrg */ 432 1.1 mrg Expression paintTypeOntoLiteral(Type type, Expression lit) 433 1.1 mrg { 434 1.1 mrg if (lit.type.equals(type)) 435 1.1 mrg return lit; 436 1.1 mrg return paintTypeOntoLiteralCopy(type, lit).copy(); 437 1.1 mrg } 438 1.1 mrg 439 1.1 mrg Expression paintTypeOntoLiteral(UnionExp* pue, Type type, Expression lit) 440 1.1 mrg { 441 1.1 mrg if (lit.type.equals(type)) 442 1.1 mrg return lit; 443 1.1 mrg *pue = paintTypeOntoLiteralCopy(type, lit); 444 1.1 mrg return pue.exp(); 445 1.1 mrg } 446 1.1 mrg 447 1.1 mrg private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) 448 1.1 mrg { 449 1.1 mrg UnionExp ue; 450 1.1 mrg if (lit.type.equals(type)) 451 1.1 mrg { 452 1.1 mrg emplaceExp!(UnionExp)(&ue, lit); 453 1.1 mrg return ue; 454 1.1 mrg } 455 1.1 mrg // If it is a cast to inout, retain the original type of the referenced part. 456 1.1 mrg if (type.hasWild()) 457 1.1 mrg { 458 1.1 mrg emplaceExp!(UnionExp)(&ue, lit); 459 1.1 mrg ue.exp().type = type; 460 1.1 mrg return ue; 461 1.1 mrg } 462 1.1 mrg if (auto se = lit.isSliceExp()) 463 1.1 mrg { 464 1.1 mrg emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr); 465 1.1 mrg } 466 1.1 mrg else if (auto ie = lit.isIndexExp()) 467 1.1 mrg { 468 1.1 mrg emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2); 469 1.1 mrg } 470 1.1 mrg else if (lit.op == EXP.arrayLiteral) 471 1.1 mrg { 472 1.1 mrg emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); 473 1.1 mrg } 474 1.1 mrg else if (lit.op == EXP.string_) 475 1.1 mrg { 476 1.1 mrg // For strings, we need to introduce another level of indirection 477 1.1 mrg emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); 478 1.1 mrg } 479 1.1 mrg else if (auto aae = lit.isAssocArrayLiteralExp()) 480 1.1 mrg { 481 1.1 mrg // TODO: we should be creating a reference to this AAExp, not 482 1.1 mrg // just a ref to the keys and values. 483 1.1 mrg OwnedBy wasOwned = aae.ownedByCtfe; 484 1.1 mrg emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values); 485 1.1 mrg aae = ue.exp().isAssocArrayLiteralExp(); 486 1.1 mrg aae.ownedByCtfe = wasOwned; 487 1.1 mrg } 488 1.1 mrg else 489 1.1 mrg { 490 1.1 mrg // Can't type paint from struct to struct*; this needs another 491 1.1 mrg // level of indirection 492 1.1 mrg if (lit.op == EXP.structLiteral && isPointer(type)) 493 1.1 mrg lit.error("CTFE internal error: painting `%s`", type.toChars()); 494 1.1 mrg ue = copyLiteral(lit); 495 1.1 mrg } 496 1.1 mrg ue.exp().type = type; 497 1.1 mrg return ue; 498 1.1 mrg } 499 1.1 mrg 500 1.1 mrg /************************************* 501 1.1 mrg * If e is a SliceExp, constant fold it. 502 1.1 mrg * Params: 503 1.1 mrg * e = expression to resolve 504 1.1 mrg * pue = if not null, store resulting expression here 505 1.1 mrg * Returns: 506 1.1 mrg * resulting expression 507 1.1 mrg */ 508 1.1 mrg Expression resolveSlice(Expression e, UnionExp* pue = null) 509 1.1 mrg { 510 1.1 mrg SliceExp se = e.isSliceExp(); 511 1.1 mrg if (!se) 512 1.1 mrg return e; 513 1.1 mrg if (se.e1.op == EXP.null_) 514 1.1 mrg return se.e1; 515 1.1 mrg if (pue) 516 1.1 mrg { 517 1.1 mrg *pue = Slice(e.type, se.e1, se.lwr, se.upr); 518 1.1 mrg return pue.exp(); 519 1.1 mrg } 520 1.1 mrg else 521 1.1 mrg return Slice(e.type, se.e1, se.lwr, se.upr).copy(); 522 1.1 mrg } 523 1.1 mrg 524 1.1 mrg /* Determine the array length, without interpreting it. 525 1.1 mrg * e must be an array literal, or a slice 526 1.1 mrg * It's very wasteful to resolve the slice when we only 527 1.1 mrg * need the length. 528 1.1 mrg */ 529 1.1 mrg uinteger_t resolveArrayLength(Expression e) 530 1.1 mrg { 531 1.1 mrg switch (e.op) 532 1.1 mrg { 533 1.1 mrg case EXP.vector: 534 1.1 mrg return e.isVectorExp().dim; 535 1.1 mrg 536 1.1 mrg case EXP.null_: 537 1.1 mrg return 0; 538 1.1 mrg 539 1.1 mrg case EXP.slice: 540 1.1 mrg { 541 1.1 mrg auto se = e.isSliceExp(); 542 1.1 mrg const ilo = se.lwr.toInteger(); 543 1.1 mrg const iup = se.upr.toInteger(); 544 1.1 mrg return iup - ilo; 545 1.1 mrg } 546 1.1 mrg 547 1.1 mrg case EXP.string_: 548 1.1 mrg return e.isStringExp().len; 549 1.1 mrg 550 1.1 mrg case EXP.arrayLiteral: 551 1.1 mrg { 552 1.1 mrg const ale = e.isArrayLiteralExp(); 553 1.1 mrg return ale.elements ? ale.elements.dim : 0; 554 1.1 mrg } 555 1.1 mrg 556 1.1 mrg case EXP.assocArrayLiteral: 557 1.1 mrg { 558 1.1 mrg return e.isAssocArrayLiteralExp().keys.dim; 559 1.1 mrg } 560 1.1 mrg 561 1.1 mrg default: 562 1.1 mrg assert(0); 563 1.1 mrg } 564 1.1 mrg } 565 1.1 mrg 566 1.1 mrg /****************************** 567 1.1 mrg * Helper for NewExp 568 1.1 mrg * Create an array literal consisting of 'elem' duplicated 'dim' times. 569 1.1 mrg * Params: 570 1.1 mrg * pue = where to store result 571 1.1 mrg * loc = source location where the interpretation occurs 572 1.1 mrg * type = target type of the result 573 1.1 mrg * elem = the source of array element, it will be owned by the result 574 1.1 mrg * dim = element number of the result 575 1.1 mrg * Returns: 576 1.1 mrg * Constructed ArrayLiteralExp 577 1.1 mrg */ 578 1.1 mrg ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc loc, Type type, Expression elem, size_t dim) 579 1.1 mrg { 580 1.1 mrg if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray) 581 1.1 mrg { 582 1.1 mrg // If it is a multidimensional array literal, do it recursively 583 1.1 mrg auto tsa = type.nextOf().isTypeSArray(); 584 1.1 mrg const len = cast(size_t)tsa.dim.toInteger(); 585 1.1 mrg elem = createBlockDuplicatedArrayLiteral(pue, loc, type.nextOf(), elem, len); 586 1.1 mrg if (elem == pue.exp()) 587 1.1 mrg elem = pue.copy(); 588 1.1 mrg } 589 1.1 mrg 590 1.1 mrg // Buzilla 15681 591 1.1 mrg const tb = elem.type.toBasetype(); 592 1.1 mrg const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray; 593 1.1 mrg 594 1.1 mrg auto elements = new Expressions(dim); 595 1.1 mrg foreach (i, ref el; *elements) 596 1.1 mrg { 597 1.1 mrg el = mustCopy && i ? copyLiteral(elem).copy() : elem; 598 1.1 mrg } 599 1.1 mrg emplaceExp!(ArrayLiteralExp)(pue, loc, type, elements); 600 1.1 mrg auto ale = pue.exp().isArrayLiteralExp(); 601 1.1 mrg ale.ownedByCtfe = OwnedBy.ctfe; 602 1.1 mrg return ale; 603 1.1 mrg } 604 1.1 mrg 605 1.1 mrg /****************************** 606 1.1 mrg * Helper for NewExp 607 1.1 mrg * Create a string literal consisting of 'value' duplicated 'dim' times. 608 1.1 mrg */ 609 1.1 mrg StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz) 610 1.1 mrg { 611 1.1 mrg auto s = cast(char*)mem.xcalloc(dim, sz); 612 1.1 mrg foreach (elemi; 0 .. dim) 613 1.1 mrg { 614 1.1 mrg switch (sz) 615 1.1 mrg { 616 1.1 mrg case 1: 617 1.1 mrg s[elemi] = cast(char)value; 618 1.1 mrg break; 619 1.1 mrg case 2: 620 1.1 mrg (cast(wchar*)s)[elemi] = cast(wchar)value; 621 1.1 mrg break; 622 1.1 mrg case 4: 623 1.1 mrg (cast(dchar*)s)[elemi] = value; 624 1.1 mrg break; 625 1.1 mrg default: 626 1.1 mrg assert(0); 627 1.1 mrg } 628 1.1 mrg } 629 1.1 mrg emplaceExp!(StringExp)(pue, loc, s[0 .. dim * sz], dim, sz); 630 1.1 mrg auto se = pue.exp().isStringExp(); 631 1.1 mrg se.type = type; 632 1.1 mrg se.committed = true; 633 1.1 mrg se.ownedByCtfe = OwnedBy.ctfe; 634 1.1 mrg return se; 635 1.1 mrg } 636 1.1 mrg 637 1.1 mrg // Return true if t is an AA 638 1.1 mrg bool isAssocArray(Type t) 639 1.1 mrg { 640 1.1 mrg return t.toBasetype().isTypeAArray() !is null; 641 1.1 mrg } 642 1.1 mrg 643 1.1 mrg // Given a template AA type, extract the corresponding built-in AA type 644 1.1 mrg TypeAArray toBuiltinAAType(Type t) 645 1.1 mrg { 646 1.1 mrg return t.toBasetype().isTypeAArray(); 647 1.1 mrg } 648 1.1 mrg 649 1.1 mrg /************** TypeInfo operations ************************************/ 650 1.1 mrg // Return true if type is TypeInfo_Class 651 1.1 mrg bool isTypeInfo_Class(const Type type) 652 1.1 mrg { 653 1.1 mrg auto tc = cast()type.isTypeClass(); 654 1.1 mrg return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null)); 655 1.1 mrg } 656 1.1 mrg 657 1.1 mrg /************** Pointer operations ************************************/ 658 1.1 mrg // Return true if t is a pointer (not a function pointer) 659 1.1 mrg bool isPointer(Type t) 660 1.1 mrg { 661 1.1 mrg Type tb = t.toBasetype(); 662 1.1 mrg return tb.ty == Tpointer && tb.nextOf().ty != Tfunction; 663 1.1 mrg } 664 1.1 mrg 665 1.1 mrg // For CTFE only. Returns true if 'e' is true or a non-null pointer. 666 1.1 mrg bool isTrueBool(Expression e) 667 1.1 mrg { 668 1.1 mrg return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_); 669 1.1 mrg } 670 1.1 mrg 671 1.1 mrg /* Is it safe to convert from srcPointee* to destPointee* ? 672 1.1 mrg * srcPointee is the genuine type (never void). 673 1.1 mrg * destPointee may be void. 674 1.1 mrg */ 675 1.1 mrg bool isSafePointerCast(Type srcPointee, Type destPointee) 676 1.1 mrg { 677 1.1 mrg // It's safe to cast S** to D** if it's OK to cast S* to D* 678 1.1 mrg while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer) 679 1.1 mrg { 680 1.1 mrg srcPointee = srcPointee.nextOf(); 681 1.1 mrg destPointee = destPointee.nextOf(); 682 1.1 mrg } 683 1.1 mrg // It's OK if both are the same (modulo const) 684 1.1 mrg if (srcPointee.constConv(destPointee)) 685 1.1 mrg return true; 686 1.1 mrg 687 1.1 mrg // It's ok to cast from/to shared because CTFE is single threaded anyways 688 1.1 mrg if (srcPointee.unSharedOf() == destPointee.unSharedOf()) 689 1.1 mrg return true; 690 1.1 mrg 691 1.1 mrg // It's OK if function pointers differ only in safe/pure/nothrow 692 1.1 mrg if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) 693 1.1 mrg return srcPointee.covariant(destPointee) == Covariant.yes || 694 1.1 mrg destPointee.covariant(srcPointee) == Covariant.yes; 695 1.1 mrg // it's OK to cast to void* 696 1.1 mrg if (destPointee.ty == Tvoid) 697 1.1 mrg return true; 698 1.1 mrg // It's OK to cast from V[K] to void* 699 1.1 mrg if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr) 700 1.1 mrg return true; 701 1.1 mrg // It's OK if they are the same size (static array of) integers, eg: 702 1.1 mrg // int* --> uint* 703 1.1 mrg // int[5][] --> uint[5][] 704 1.1 mrg if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray) 705 1.1 mrg { 706 1.1 mrg if (srcPointee.size() != destPointee.size()) 707 1.1 mrg return false; 708 1.1 mrg srcPointee = srcPointee.baseElemOf(); 709 1.1 mrg destPointee = destPointee.baseElemOf(); 710 1.1 mrg } 711 1.1 mrg return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size(); 712 1.1 mrg } 713 1.1 mrg 714 1.1 mrg Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) 715 1.1 mrg { 716 1.1 mrg *ofs = 0; 717 1.1 mrg if (auto ae = e.isAddrExp()) 718 1.1 mrg e = ae.e1; 719 1.1 mrg if (auto soe = e.isSymOffExp()) 720 1.1 mrg *ofs = soe.offset; 721 1.1 mrg if (auto dve = e.isDotVarExp()) 722 1.1 mrg { 723 1.1 mrg auto ex = dve.e1; 724 1.1 mrg const v = dve.var.isVarDeclaration(); 725 1.1 mrg assert(v); 726 1.1 mrg StructLiteralExp se = (ex.op == EXP.classReference) 727 1.1 mrg ? ex.isClassReferenceExp().value 728 1.1 mrg : ex.isStructLiteralExp(); 729 1.1 mrg 730 1.1 mrg // We can't use getField, because it makes a copy 731 1.1 mrg const i = (ex.op == EXP.classReference) 732 1.1 mrg ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset) 733 1.1 mrg : se.getFieldIndex(e.type, v.offset); 734 1.1 mrg e = (*se.elements)[i]; 735 1.1 mrg } 736 1.1 mrg if (auto ie = e.isIndexExp()) 737 1.1 mrg { 738 1.1 mrg // Note that each AA element is part of its own memory block 739 1.1 mrg if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64) 740 1.1 mrg { 741 1.1 mrg *ofs = ie.e2.toInteger(); 742 1.1 mrg return ie.e1; 743 1.1 mrg } 744 1.1 mrg } 745 1.1 mrg if (auto se = e.isSliceExp()) 746 1.1 mrg { 747 1.1 mrg if (se && e.type.toBasetype().ty == Tsarray && 748 1.1 mrg (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64) 749 1.1 mrg { 750 1.1 mrg *ofs = se.lwr.toInteger(); 751 1.1 mrg return se.e1; 752 1.1 mrg } 753 1.1 mrg } 754 1.1 mrg 755 1.1 mrg // It can be a `null` disguised as a cast, e.g. `cast(void*)0`. 756 1.1 mrg if (auto ie = e.isIntegerExp()) 757 1.1 mrg if (ie.type.ty == Tpointer && ie.getInteger() == 0) 758 1.1 mrg return new NullExp(ie.loc, e.type.nextOf()); 759 1.1 mrg // Those casts are invalid, but let the rest of the code handle it, 760 1.1 mrg // as it could be something like `x !is null`, which doesn't need 761 1.1 mrg // to dereference the pointer, even if the pointer is `cast(void*)420`. 762 1.1 mrg 763 1.1 mrg return e; 764 1.1 mrg } 765 1.1 mrg 766 1.1 mrg /** Return true if agg1 and agg2 are pointers to the same memory block 767 1.1 mrg */ 768 1.1 mrg bool pointToSameMemoryBlock(Expression agg1, Expression agg2) 769 1.1 mrg { 770 1.1 mrg if (agg1 == agg2) 771 1.1 mrg return true; 772 1.1 mrg // For integers cast to pointers, we regard them as non-comparable 773 1.1 mrg // unless they are identical. (This may be overly strict). 774 1.1 mrg if (agg1.op == EXP.int64 && agg2.op == EXP.int64 && agg1.toInteger() == agg2.toInteger()) 775 1.1 mrg { 776 1.1 mrg return true; 777 1.1 mrg } 778 1.1 mrg // Note that type painting can occur with VarExp, so we 779 1.1 mrg // must compare the variables being pointed to. 780 1.1 mrg if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var) 781 1.1 mrg { 782 1.1 mrg return true; 783 1.1 mrg } 784 1.1 mrg if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var) 785 1.1 mrg { 786 1.1 mrg return true; 787 1.1 mrg } 788 1.1 mrg return false; 789 1.1 mrg } 790 1.1 mrg 791 1.1 mrg // return e1 - e2 as an integer, or error if not possible 792 1.1 mrg Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2) 793 1.1 mrg { 794 1.1 mrg dinteger_t ofs1, ofs2; 795 1.1 mrg Expression agg1 = getAggregateFromPointer(e1, &ofs1); 796 1.1 mrg Expression agg2 = getAggregateFromPointer(e2, &ofs2); 797 1.1 mrg if (agg1 == agg2) 798 1.1 mrg { 799 1.1 mrg Type pointee = (cast(TypePointer)agg1.type).next; 800 1.1 mrg const sz = pointee.size(); 801 1.1 mrg emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); 802 1.1 mrg } 803 1.1 mrg else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ && 804 1.1 mrg agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr) 805 1.1 mrg { 806 1.1 mrg Type pointee = (cast(TypePointer)agg1.type).next; 807 1.1 mrg const sz = pointee.size(); 808 1.1 mrg emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); 809 1.1 mrg } 810 1.1 mrg else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && 811 1.1 mrg agg1.isSymOffExp().var == agg2.isSymOffExp().var) 812 1.1 mrg { 813 1.1 mrg emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type); 814 1.1 mrg } 815 1.1 mrg else 816 1.1 mrg { 817 1.1 mrg error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars()); 818 1.1 mrg emplaceExp!(CTFEExp)(pue, EXP.cantExpression); 819 1.1 mrg } 820 1.1 mrg return pue.exp(); 821 1.1 mrg } 822 1.1 mrg 823 1.1 mrg // Return eptr op e2, where eptr is a pointer, e2 is an integer, 824 1.1 mrg // and op is EXP.add or EXP.min 825 1.1 mrg Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2) 826 1.1 mrg { 827 1.1 mrg if (eptr.type.nextOf().ty == Tvoid) 828 1.1 mrg { 829 1.1 mrg error(loc, "cannot perform arithmetic on `void*` pointers at compile time"); 830 1.1 mrg Lcant: 831 1.1 mrg emplaceExp!(CTFEExp)(pue, EXP.cantExpression); 832 1.1 mrg return pue.exp(); 833 1.1 mrg } 834 1.1 mrg if (eptr.op == EXP.address) 835 1.1 mrg eptr = eptr.isAddrExp().e1; 836 1.1 mrg dinteger_t ofs1; 837 1.1 mrg Expression agg1 = getAggregateFromPointer(eptr, &ofs1); 838 1.1 mrg if (agg1.op == EXP.symbolOffset) 839 1.1 mrg { 840 1.1 mrg if (agg1.isSymOffExp().var.type.ty != Tsarray) 841 1.1 mrg { 842 1.1 mrg error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time"); 843 1.1 mrg goto Lcant; 844 1.1 mrg } 845 1.1 mrg } 846 1.1 mrg else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral) 847 1.1 mrg { 848 1.1 mrg error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); 849 1.1 mrg goto Lcant; 850 1.1 mrg } 851 1.1 mrg dinteger_t ofs2 = e2.toInteger(); 852 1.1 mrg Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next; 853 1.1 mrg dinteger_t sz = pointee.size(); 854 1.1 mrg sinteger_t indx; 855 1.1 mrg dinteger_t len; 856 1.1 mrg if (agg1.op == EXP.symbolOffset) 857 1.1 mrg { 858 1.1 mrg indx = ofs1 / sz; 859 1.1 mrg len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger(); 860 1.1 mrg } 861 1.1 mrg else 862 1.1 mrg { 863 1.1 mrg Expression dollar = ArrayLength(Type.tsize_t, agg1).copy(); 864 1.1 mrg assert(!CTFEExp.isCantExp(dollar)); 865 1.1 mrg indx = ofs1; 866 1.1 mrg len = dollar.toInteger(); 867 1.1 mrg } 868 1.1 mrg if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus) 869 1.1 mrg indx += ofs2 / sz; 870 1.1 mrg else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus) 871 1.1 mrg indx -= ofs2 / sz; 872 1.1 mrg else 873 1.1 mrg { 874 1.1 mrg error(loc, "CTFE internal error: bad pointer operation"); 875 1.1 mrg goto Lcant; 876 1.1 mrg } 877 1.1 mrg if (indx < 0 || len < indx) 878 1.1 mrg { 879 1.1 mrg error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len); 880 1.1 mrg goto Lcant; 881 1.1 mrg } 882 1.1 mrg if (agg1.op == EXP.symbolOffset) 883 1.1 mrg { 884 1.1 mrg emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz); 885 1.1 mrg SymOffExp se = pue.exp().isSymOffExp(); 886 1.1 mrg se.type = type; 887 1.1 mrg return pue.exp(); 888 1.1 mrg } 889 1.1 mrg if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_) 890 1.1 mrg { 891 1.1 mrg error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars()); 892 1.1 mrg goto Lcant; 893 1.1 mrg } 894 1.1 mrg if (eptr.type.toBasetype().ty == Tsarray) 895 1.1 mrg { 896 1.1 mrg dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger(); 897 1.1 mrg // Create a CTFE pointer &agg1[indx .. indx+dim] 898 1.1 mrg auto se = ctfeEmplaceExp!SliceExp(loc, agg1, 899 1.1 mrg ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t), 900 1.1 mrg ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t)); 901 1.1 mrg se.type = type.toBasetype().nextOf(); 902 1.1 mrg emplaceExp!(AddrExp)(pue, loc, se); 903 1.1 mrg pue.exp().type = type; 904 1.1 mrg return pue.exp(); 905 1.1 mrg } 906 1.1 mrg // Create a CTFE pointer &agg1[indx] 907 1.1 mrg auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t); 908 1.1 mrg Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs); 909 1.1 mrg ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992 910 1.1 mrg emplaceExp!(AddrExp)(pue, loc, ie); 911 1.1 mrg pue.exp().type = type; 912 1.1 mrg return pue.exp(); 913 1.1 mrg } 914 1.1 mrg 915 1.1 mrg // Return 1 if true, 0 if false 916 1.1 mrg // -1 if comparison is illegal because they point to non-comparable memory blocks 917 1.1 mrg int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2) 918 1.1 mrg { 919 1.1 mrg if (pointToSameMemoryBlock(agg1, agg2)) 920 1.1 mrg { 921 1.1 mrg int n; 922 1.1 mrg switch (op) 923 1.1 mrg { 924 1.1 mrg case EXP.lessThan: 925 1.1 mrg n = (ofs1 < ofs2); 926 1.1 mrg break; 927 1.1 mrg case EXP.lessOrEqual: 928 1.1 mrg n = (ofs1 <= ofs2); 929 1.1 mrg break; 930 1.1 mrg case EXP.greaterThan: 931 1.1 mrg n = (ofs1 > ofs2); 932 1.1 mrg break; 933 1.1 mrg case EXP.greaterOrEqual: 934 1.1 mrg n = (ofs1 >= ofs2); 935 1.1 mrg break; 936 1.1 mrg case EXP.identity: 937 1.1 mrg case EXP.equal: 938 1.1 mrg n = (ofs1 == ofs2); 939 1.1 mrg break; 940 1.1 mrg case EXP.notIdentity: 941 1.1 mrg case EXP.notEqual: 942 1.1 mrg n = (ofs1 != ofs2); 943 1.1 mrg break; 944 1.1 mrg default: 945 1.1 mrg assert(0); 946 1.1 mrg } 947 1.1 mrg return n; 948 1.1 mrg } 949 1.1 mrg const null1 = (agg1.op == EXP.null_); 950 1.1 mrg const null2 = (agg2.op == EXP.null_); 951 1.1 mrg int cmp; 952 1.1 mrg if (null1 || null2) 953 1.1 mrg { 954 1.1 mrg switch (op) 955 1.1 mrg { 956 1.1 mrg case EXP.lessThan: 957 1.1 mrg cmp = null1 && !null2; 958 1.1 mrg break; 959 1.1 mrg case EXP.greaterThan: 960 1.1 mrg cmp = !null1 && null2; 961 1.1 mrg break; 962 1.1 mrg case EXP.lessOrEqual: 963 1.1 mrg cmp = null1; 964 1.1 mrg break; 965 1.1 mrg case EXP.greaterOrEqual: 966 1.1 mrg cmp = null2; 967 1.1 mrg break; 968 1.1 mrg case EXP.identity: 969 1.1 mrg case EXP.equal: 970 1.1 mrg case EXP.notIdentity: // 'cmp' gets inverted below 971 1.1 mrg case EXP.notEqual: 972 1.1 mrg cmp = (null1 == null2); 973 1.1 mrg break; 974 1.1 mrg default: 975 1.1 mrg assert(0); 976 1.1 mrg } 977 1.1 mrg } 978 1.1 mrg else 979 1.1 mrg { 980 1.1 mrg switch (op) 981 1.1 mrg { 982 1.1 mrg case EXP.identity: 983 1.1 mrg case EXP.equal: 984 1.1 mrg case EXP.notIdentity: // 'cmp' gets inverted below 985 1.1 mrg case EXP.notEqual: 986 1.1 mrg cmp = 0; 987 1.1 mrg break; 988 1.1 mrg default: 989 1.1 mrg return -1; // memory blocks are different 990 1.1 mrg } 991 1.1 mrg } 992 1.1 mrg if (op == EXP.notIdentity || op == EXP.notEqual) 993 1.1 mrg cmp ^= 1; 994 1.1 mrg return cmp; 995 1.1 mrg } 996 1.1 mrg 997 1.1 mrg // True if conversion from type 'from' to 'to' involves a reinterpret_cast 998 1.1 mrg // floating point -> integer or integer -> floating point 999 1.1 mrg bool isFloatIntPaint(Type to, Type from) 1000 1.1 mrg { 1001 1.1 mrg return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral()); 1002 1.1 mrg } 1003 1.1 mrg 1004 1.1 mrg // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. 1005 1.1 mrg Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to) 1006 1.1 mrg { 1007 1.1 mrg if (exceptionOrCantInterpret(fromVal)) 1008 1.1 mrg return fromVal; 1009 1.1 mrg assert(to.size() == 4 || to.size() == 8); 1010 1.1 mrg return Compiler.paintAsType(pue, fromVal, to); 1011 1.1 mrg } 1012 1.1 mrg 1013 1.1 mrg /******** Constant folding, with support for CTFE ***************************/ 1014 1.1 mrg /// Return true if non-pointer expression e can be compared 1015 1.1 mrg /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity 1016 1.1 mrg bool isCtfeComparable(Expression e) 1017 1.1 mrg { 1018 1.1 mrg if (e.op == EXP.slice) 1019 1.1 mrg e = e.isSliceExp().e1; 1020 1.1 mrg if (e.isConst() != 1) 1021 1.1 mrg { 1022 1.1 mrg if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference) 1023 1.1 mrg { 1024 1.1 mrg return true; 1025 1.1 mrg } 1026 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=14123 1027 1.1 mrg // TypeInfo object is comparable in CTFE 1028 1.1 mrg if (e.op == EXP.typeid_) 1029 1.1 mrg return true; 1030 1.1 mrg return false; 1031 1.1 mrg } 1032 1.1 mrg return true; 1033 1.1 mrg } 1034 1.1 mrg 1035 1.1 mrg /// Map EXP comparison ops 1036 1.1 mrg private bool numCmp(N)(EXP op, N n1, N n2) 1037 1.1 mrg { 1038 1.1 mrg switch (op) 1039 1.1 mrg { 1040 1.1 mrg case EXP.lessThan: 1041 1.1 mrg return n1 < n2; 1042 1.1 mrg case EXP.lessOrEqual: 1043 1.1 mrg return n1 <= n2; 1044 1.1 mrg case EXP.greaterThan: 1045 1.1 mrg return n1 > n2; 1046 1.1 mrg case EXP.greaterOrEqual: 1047 1.1 mrg return n1 >= n2; 1048 1.1 mrg 1049 1.1 mrg default: 1050 1.1 mrg assert(0); 1051 1.1 mrg } 1052 1.1 mrg } 1053 1.1 mrg 1054 1.1 mrg /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1055 1.1 mrg bool specificCmp(EXP op, int rawCmp) 1056 1.1 mrg { 1057 1.1 mrg return numCmp!int(op, rawCmp, 0); 1058 1.1 mrg } 1059 1.1 mrg 1060 1.1 mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1061 1.1 mrg bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) 1062 1.1 mrg { 1063 1.1 mrg return numCmp!dinteger_t(op, n1, n2); 1064 1.1 mrg } 1065 1.1 mrg 1066 1.1 mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1067 1.1 mrg bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) 1068 1.1 mrg { 1069 1.1 mrg return numCmp!sinteger_t(op, n1, n2); 1070 1.1 mrg } 1071 1.1 mrg 1072 1.1 mrg /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1073 1.1 mrg bool realCmp(EXP op, real_t r1, real_t r2) 1074 1.1 mrg { 1075 1.1 mrg // Don't rely on compiler, handle NAN arguments separately 1076 1.1 mrg if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered 1077 1.1 mrg { 1078 1.1 mrg switch (op) 1079 1.1 mrg { 1080 1.1 mrg case EXP.lessThan: 1081 1.1 mrg case EXP.lessOrEqual: 1082 1.1 mrg case EXP.greaterThan: 1083 1.1 mrg case EXP.greaterOrEqual: 1084 1.1 mrg return false; 1085 1.1 mrg 1086 1.1 mrg default: 1087 1.1 mrg assert(0); 1088 1.1 mrg } 1089 1.1 mrg } 1090 1.1 mrg else 1091 1.1 mrg { 1092 1.1 mrg return numCmp!real_t(op, r1, r2); 1093 1.1 mrg } 1094 1.1 mrg } 1095 1.1 mrg 1096 1.1 mrg /* Conceptually the same as memcmp(e1, e2). 1097 1.1 mrg * e1 and e2 may be strings, arrayliterals, or slices. 1098 1.1 mrg * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. 1099 1.1 mrg * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. 1100 1.1 mrg * Returns: 1101 1.1 mrg * -1,0,1 1102 1.1 mrg */ 1103 1.1 mrg private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len) 1104 1.1 mrg { 1105 1.1 mrg // Resolve slices, if necessary 1106 1.1 mrg uinteger_t lo1 = 0; 1107 1.1 mrg uinteger_t lo2 = 0; 1108 1.1 mrg 1109 1.1 mrg Expression x1 = e1; 1110 1.1 mrg if (auto sle1 = x1.isSliceExp()) 1111 1.1 mrg { 1112 1.1 mrg lo1 = sle1.lwr.toInteger(); 1113 1.1 mrg x1 = sle1.e1; 1114 1.1 mrg } 1115 1.1 mrg auto se1 = x1.isStringExp(); 1116 1.1 mrg auto ae1 = x1.isArrayLiteralExp(); 1117 1.1 mrg 1118 1.1 mrg Expression x2 = e2; 1119 1.1 mrg if (auto sle2 = x2.isSliceExp()) 1120 1.1 mrg { 1121 1.1 mrg lo2 = sle2.lwr.toInteger(); 1122 1.1 mrg x2 = sle2.e1; 1123 1.1 mrg } 1124 1.1 mrg auto se2 = x2.isStringExp(); 1125 1.1 mrg auto ae2 = x2.isArrayLiteralExp(); 1126 1.1 mrg 1127 1.1 mrg // Now both must be either EXP.arrayLiteral or EXP.string_ 1128 1.1 mrg if (se1 && se2) 1129 1.1 mrg return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); 1130 1.1 mrg if (se1 && ae2) 1131 1.1 mrg return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); 1132 1.1 mrg if (se2 && ae1) 1133 1.1 mrg return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len); 1134 1.1 mrg assert(ae1 && ae2); 1135 1.1 mrg // Comparing two array literals. This case is potentially recursive. 1136 1.1 mrg // If they aren't strings, we just need an equality check rather than 1137 1.1 mrg // a full cmp. 1138 1.1 mrg const bool needCmp = ae1.type.nextOf().isintegral(); 1139 1.1 mrg foreach (size_t i; 0 .. cast(size_t)len) 1140 1.1 mrg { 1141 1.1 mrg Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)]; 1142 1.1 mrg Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)]; 1143 1.1 mrg if (needCmp) 1144 1.1 mrg { 1145 1.1 mrg const sinteger_t c = ee1.toInteger() - ee2.toInteger(); 1146 1.1 mrg if (c > 0) 1147 1.1 mrg return 1; 1148 1.1 mrg if (c < 0) 1149 1.1 mrg return -1; 1150 1.1 mrg } 1151 1.1 mrg else 1152 1.1 mrg { 1153 1.1 mrg if (ctfeRawCmp(loc, ee1, ee2)) 1154 1.1 mrg return 1; 1155 1.1 mrg } 1156 1.1 mrg } 1157 1.1 mrg return 0; 1158 1.1 mrg } 1159 1.1 mrg 1160 1.1 mrg /* Given a delegate expression e, return .funcptr. 1161 1.1 mrg * If e is NullExp, return NULL. 1162 1.1 mrg */ 1163 1.1 mrg private FuncDeclaration funcptrOf(Expression e) 1164 1.1 mrg { 1165 1.1 mrg assert(e.type.ty == Tdelegate); 1166 1.1 mrg if (auto de = e.isDelegateExp()) 1167 1.1 mrg return de.func; 1168 1.1 mrg if (auto fe = e.isFuncExp()) 1169 1.1 mrg return fe.fd; 1170 1.1 mrg assert(e.op == EXP.null_); 1171 1.1 mrg return null; 1172 1.1 mrg } 1173 1.1 mrg 1174 1.1 mrg private bool isArray(const Expression e) 1175 1.1 mrg { 1176 1.1 mrg return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_; 1177 1.1 mrg } 1178 1.1 mrg 1179 1.1 mrg /***** 1180 1.1 mrg * Params: 1181 1.1 mrg * loc = source file location 1182 1.1 mrg * e1 = left operand 1183 1.1 mrg * e2 = right operand 1184 1.1 mrg * identity = true for `is` identity comparisons 1185 1.1 mrg * Returns: 1186 1.1 mrg * For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. 1187 1.1 mrg * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. 1188 1.1 mrg */ 1189 1.1 mrg private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false) 1190 1.1 mrg { 1191 1.1 mrg if (e1.op == EXP.classReference || e2.op == EXP.classReference) 1192 1.1 mrg { 1193 1.1 mrg if (e1.op == EXP.classReference && e2.op == EXP.classReference && 1194 1.1 mrg e1.isClassReferenceExp().value == e2.isClassReferenceExp().value) 1195 1.1 mrg return 0; 1196 1.1 mrg return 1; 1197 1.1 mrg } 1198 1.1 mrg if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_) 1199 1.1 mrg { 1200 1.1 mrg // printf("e1: %s\n", e1.toChars()); 1201 1.1 mrg // printf("e2: %s\n", e2.toChars()); 1202 1.1 mrg Type t1 = isType(e1.isTypeidExp().obj); 1203 1.1 mrg Type t2 = isType(e2.isTypeidExp().obj); 1204 1.1 mrg assert(t1); 1205 1.1 mrg assert(t2); 1206 1.1 mrg return t1 != t2; 1207 1.1 mrg } 1208 1.1 mrg // null == null, regardless of type 1209 1.1 mrg if (e1.op == EXP.null_ && e2.op == EXP.null_) 1210 1.1 mrg return 0; 1211 1.1 mrg if (e1.type.ty == Tpointer && e2.type.ty == Tpointer) 1212 1.1 mrg { 1213 1.1 mrg // Can only be an equality test. 1214 1.1 mrg dinteger_t ofs1, ofs2; 1215 1.1 mrg Expression agg1 = getAggregateFromPointer(e1, &ofs1); 1216 1.1 mrg Expression agg2 = getAggregateFromPointer(e2, &ofs2); 1217 1.1 mrg if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)) 1218 1.1 mrg { 1219 1.1 mrg if (ofs1 == ofs2) 1220 1.1 mrg return 0; 1221 1.1 mrg } 1222 1.1 mrg return 1; 1223 1.1 mrg } 1224 1.1 mrg if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate) 1225 1.1 mrg { 1226 1.1 mrg // If .funcptr isn't the same, they are not equal 1227 1.1 mrg if (funcptrOf(e1) != funcptrOf(e2)) 1228 1.1 mrg return 1; 1229 1.1 mrg // If both are delegate literals, assume they have the 1230 1.1 mrg // same closure pointer. TODO: We don't support closures yet! 1231 1.1 mrg if (e1.op == EXP.function_ && e2.op == EXP.function_) 1232 1.1 mrg return 0; 1233 1.1 mrg assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_); 1234 1.1 mrg // Same .funcptr. Do they have the same .ptr? 1235 1.1 mrg Expression ptr1 = e1.isDelegateExp().e1; 1236 1.1 mrg Expression ptr2 = e2.isDelegateExp().e1; 1237 1.1 mrg dinteger_t ofs1, ofs2; 1238 1.1 mrg Expression agg1 = getAggregateFromPointer(ptr1, &ofs1); 1239 1.1 mrg Expression agg2 = getAggregateFromPointer(ptr2, &ofs2); 1240 1.1 mrg // If they are EXP.variable, it means they are FuncDeclarations 1241 1.1 mrg if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)) 1242 1.1 mrg { 1243 1.1 mrg return 0; 1244 1.1 mrg } 1245 1.1 mrg return 1; 1246 1.1 mrg } 1247 1.1 mrg if (isArray(e1) && isArray(e2)) 1248 1.1 mrg { 1249 1.1 mrg const uinteger_t len1 = resolveArrayLength(e1); 1250 1.1 mrg const uinteger_t len2 = resolveArrayLength(e2); 1251 1.1 mrg // workaround for dmc optimizer bug calculating wrong len for 1252 1.1 mrg // uinteger_t len = (len1 < len2 ? len1 : len2); 1253 1.1 mrg // if (len == 0) ... 1254 1.1 mrg if (len1 > 0 && len2 > 0) 1255 1.1 mrg { 1256 1.1 mrg const uinteger_t len = (len1 < len2 ? len1 : len2); 1257 1.1 mrg const int res = ctfeCmpArrays(loc, e1, e2, len); 1258 1.1 mrg if (res != 0) 1259 1.1 mrg return res; 1260 1.1 mrg } 1261 1.1 mrg return cast(int)(len1 - len2); 1262 1.1 mrg } 1263 1.1 mrg if (e1.type.isintegral()) 1264 1.1 mrg { 1265 1.1 mrg return e1.toInteger() != e2.toInteger(); 1266 1.1 mrg } 1267 1.1 mrg if (e1.type.isreal() || e1.type.isimaginary()) 1268 1.1 mrg { 1269 1.1 mrg real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary(); 1270 1.1 mrg real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary(); 1271 1.1 mrg if (identity) 1272 1.1 mrg return !CTFloat.isIdentical(r1, r2); 1273 1.1 mrg if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered 1274 1.1 mrg { 1275 1.1 mrg return 1; // they are not equal 1276 1.1 mrg } 1277 1.1 mrg else 1278 1.1 mrg { 1279 1.1 mrg return (r1 != r2); 1280 1.1 mrg } 1281 1.1 mrg } 1282 1.1 mrg else if (e1.type.iscomplex()) 1283 1.1 mrg { 1284 1.1 mrg auto c1 = e1.toComplex(); 1285 1.1 mrg auto c2 = e2.toComplex(); 1286 1.1 mrg if (identity) 1287 1.1 mrg { 1288 1.1 mrg return !RealIdentical(c1.re, c2.re) && !RealIdentical(c1.im, c2.im); 1289 1.1 mrg } 1290 1.1 mrg return c1 != c2; 1291 1.1 mrg } 1292 1.1 mrg if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) 1293 1.1 mrg { 1294 1.1 mrg StructLiteralExp es1 = e1.isStructLiteralExp(); 1295 1.1 mrg StructLiteralExp es2 = e2.isStructLiteralExp(); 1296 1.1 mrg // For structs, we only need to return 0 or 1 (< and > aren't legal). 1297 1.1 mrg if (es1.sd != es2.sd) 1298 1.1 mrg return 1; 1299 1.1 mrg else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) 1300 1.1 mrg return 0; // both arrays are empty 1301 1.1 mrg else if (!es1.elements || !es2.elements) 1302 1.1 mrg return 1; 1303 1.1 mrg else if (es1.elements.dim != es2.elements.dim) 1304 1.1 mrg return 1; 1305 1.1 mrg else 1306 1.1 mrg { 1307 1.1 mrg foreach (size_t i; 0 .. es1.elements.dim) 1308 1.1 mrg { 1309 1.1 mrg Expression ee1 = (*es1.elements)[i]; 1310 1.1 mrg Expression ee2 = (*es2.elements)[i]; 1311 1.1 mrg 1312 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=16284 1313 1.1 mrg if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp 1314 1.1 mrg continue; 1315 1.1 mrg 1316 1.1 mrg if (ee1 == ee2) 1317 1.1 mrg continue; 1318 1.1 mrg if (!ee1 || !ee2) 1319 1.1 mrg return 1; 1320 1.1 mrg const int cmp = ctfeRawCmp(loc, ee1, ee2, identity); 1321 1.1 mrg if (cmp) 1322 1.1 mrg return 1; 1323 1.1 mrg } 1324 1.1 mrg return 0; // All elements are equal 1325 1.1 mrg } 1326 1.1 mrg } 1327 1.1 mrg if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral) 1328 1.1 mrg { 1329 1.1 mrg AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp(); 1330 1.1 mrg AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp(); 1331 1.1 mrg size_t dim = es1.keys.dim; 1332 1.1 mrg if (es2.keys.dim != dim) 1333 1.1 mrg return 1; 1334 1.1 mrg bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim); 1335 1.1 mrg memset(used, 0, bool.sizeof * dim); 1336 1.1 mrg foreach (size_t i; 0 .. dim) 1337 1.1 mrg { 1338 1.1 mrg Expression k1 = (*es1.keys)[i]; 1339 1.1 mrg Expression v1 = (*es1.values)[i]; 1340 1.1 mrg Expression v2 = null; 1341 1.1 mrg foreach (size_t j; 0 .. dim) 1342 1.1 mrg { 1343 1.1 mrg if (used[j]) 1344 1.1 mrg continue; 1345 1.1 mrg Expression k2 = (*es2.keys)[j]; 1346 1.1 mrg if (ctfeRawCmp(loc, k1, k2, identity)) 1347 1.1 mrg continue; 1348 1.1 mrg used[j] = true; 1349 1.1 mrg v2 = (*es2.values)[j]; 1350 1.1 mrg break; 1351 1.1 mrg } 1352 1.1 mrg if (!v2 || ctfeRawCmp(loc, v1, v2, identity)) 1353 1.1 mrg { 1354 1.1 mrg mem.xfree(used); 1355 1.1 mrg return 1; 1356 1.1 mrg } 1357 1.1 mrg } 1358 1.1 mrg mem.xfree(used); 1359 1.1 mrg return 0; 1360 1.1 mrg } 1361 1.1 mrg else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_) 1362 1.1 mrg { 1363 1.1 mrg return e1.isAssocArrayLiteralExp.keys.dim != 0; 1364 1.1 mrg } 1365 1.1 mrg else if (e1.op == EXP.null_ && e2.op == EXP.assocArrayLiteral) 1366 1.1 mrg { 1367 1.1 mrg return e2.isAssocArrayLiteralExp.keys.dim != 0; 1368 1.1 mrg } 1369 1.1 mrg 1370 1.1 mrg error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1.toChars(), e2.toChars()); 1371 1.1 mrg assert(0); 1372 1.1 mrg } 1373 1.1 mrg 1374 1.1 mrg /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 1375 1.1 mrg bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2) 1376 1.1 mrg { 1377 1.1 mrg return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual); 1378 1.1 mrg } 1379 1.1 mrg 1380 1.1 mrg /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 1381 1.1 mrg bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2) 1382 1.1 mrg { 1383 1.1 mrg //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars()); 1384 1.1 mrg //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr, 1385 1.1 mrg // EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars()); 1386 1.1 mrg bool cmp; 1387 1.1 mrg if (e1.op == EXP.null_) 1388 1.1 mrg { 1389 1.1 mrg cmp = (e2.op == EXP.null_); 1390 1.1 mrg } 1391 1.1 mrg else if (e2.op == EXP.null_) 1392 1.1 mrg { 1393 1.1 mrg cmp = false; 1394 1.1 mrg } 1395 1.1 mrg else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset) 1396 1.1 mrg { 1397 1.1 mrg SymOffExp es1 = e1.isSymOffExp(); 1398 1.1 mrg SymOffExp es2 = e2.isSymOffExp(); 1399 1.1 mrg cmp = (es1.var == es2.var && es1.offset == es2.offset); 1400 1.1 mrg } 1401 1.1 mrg else if (e1.type.isreal()) 1402 1.1 mrg cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal()); 1403 1.1 mrg else if (e1.type.isimaginary()) 1404 1.1 mrg cmp = RealIdentical(e1.toImaginary(), e2.toImaginary()); 1405 1.1 mrg else if (e1.type.iscomplex()) 1406 1.1 mrg { 1407 1.1 mrg complex_t v1 = e1.toComplex(); 1408 1.1 mrg complex_t v2 = e2.toComplex(); 1409 1.1 mrg cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1)); 1410 1.1 mrg } 1411 1.1 mrg else 1412 1.1 mrg { 1413 1.1 mrg cmp = !ctfeRawCmp(loc, e1, e2, true); 1414 1.1 mrg } 1415 1.1 mrg if (op == EXP.notIdentity || op == EXP.notEqual) 1416 1.1 mrg cmp ^= true; 1417 1.1 mrg return cmp; 1418 1.1 mrg } 1419 1.1 mrg 1420 1.1 mrg /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1 1421 1.1 mrg bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2) 1422 1.1 mrg { 1423 1.1 mrg Type t1 = e1.type.toBasetype(); 1424 1.1 mrg Type t2 = e2.type.toBasetype(); 1425 1.1 mrg 1426 1.1 mrg if (t1.isString() && t2.isString()) 1427 1.1 mrg return specificCmp(op, ctfeRawCmp(loc, e1, e2)); 1428 1.1 mrg else if (t1.isreal()) 1429 1.1 mrg return realCmp(op, e1.toReal(), e2.toReal()); 1430 1.1 mrg else if (t1.isimaginary()) 1431 1.1 mrg return realCmp(op, e1.toImaginary(), e2.toImaginary()); 1432 1.1 mrg else if (t1.isunsigned() || t2.isunsigned()) 1433 1.1 mrg return intUnsignedCmp(op, e1.toInteger(), e2.toInteger()); 1434 1.1 mrg else 1435 1.1 mrg return intSignedCmp(op, e1.toInteger(), e2.toInteger()); 1436 1.1 mrg } 1437 1.1 mrg 1438 1.1 mrg UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) 1439 1.1 mrg { 1440 1.1 mrg Type t1 = e1.type.toBasetype(); 1441 1.1 mrg Type t2 = e2.type.toBasetype(); 1442 1.1 mrg UnionExp ue; 1443 1.1 mrg if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral()) 1444 1.1 mrg { 1445 1.1 mrg // [chars] ~ string => string (only valid for CTFE) 1446 1.1 mrg StringExp es1 = e2.isStringExp(); 1447 1.1 mrg ArrayLiteralExp es2 = e1.isArrayLiteralExp(); 1448 1.1 mrg const len = es1.len + es2.elements.dim; 1449 1.1 mrg const sz = es1.sz; 1450 1.1 mrg void* s = mem.xmalloc((len + 1) * sz); 1451 1.1 mrg const data1 = es1.peekData(); 1452 1.1 mrg memcpy(cast(char*)s + sz * es2.elements.dim, data1.ptr, data1.length); 1453 1.1 mrg foreach (size_t i; 0 .. es2.elements.dim) 1454 1.1 mrg { 1455 1.1 mrg Expression es2e = (*es2.elements)[i]; 1456 1.1 mrg if (es2e.op != EXP.int64) 1457 1.1 mrg { 1458 1.1 mrg emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); 1459 1.1 mrg return ue; 1460 1.1 mrg } 1461 1.1 mrg dinteger_t v = es2e.toInteger(); 1462 1.1 mrg Port.valcpy(cast(char*)s + i * sz, v, sz); 1463 1.1 mrg } 1464 1.1 mrg // Add terminating 0 1465 1.1 mrg memset(cast(char*)s + len * sz, 0, sz); 1466 1.1 mrg emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); 1467 1.1 mrg StringExp es = ue.exp().isStringExp(); 1468 1.1 mrg es.committed = 0; 1469 1.1 mrg es.type = type; 1470 1.1 mrg return ue; 1471 1.1 mrg } 1472 1.1 mrg if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral()) 1473 1.1 mrg { 1474 1.1 mrg // string ~ [chars] => string (only valid for CTFE) 1475 1.1 mrg // Concatenate the strings 1476 1.1 mrg StringExp es1 = e1.isStringExp(); 1477 1.1 mrg ArrayLiteralExp es2 = e2.isArrayLiteralExp(); 1478 1.1 mrg const len = es1.len + es2.elements.dim; 1479 1.1 mrg const sz = es1.sz; 1480 1.1 mrg void* s = mem.xmalloc((len + 1) * sz); 1481 1.1 mrg auto slice = es1.peekData(); 1482 1.1 mrg memcpy(s, slice.ptr, slice.length); 1483 1.1 mrg foreach (size_t i; 0 .. es2.elements.dim) 1484 1.1 mrg { 1485 1.1 mrg Expression es2e = (*es2.elements)[i]; 1486 1.1 mrg if (es2e.op != EXP.int64) 1487 1.1 mrg { 1488 1.1 mrg emplaceExp!(CTFEExp)(&ue, EXP.cantExpression); 1489 1.1 mrg return ue; 1490 1.1 mrg } 1491 1.1 mrg const v = es2e.toInteger(); 1492 1.1 mrg Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz); 1493 1.1 mrg } 1494 1.1 mrg // Add terminating 0 1495 1.1 mrg memset(cast(char*)s + len * sz, 0, sz); 1496 1.1 mrg emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); 1497 1.1 mrg StringExp es = ue.exp().isStringExp(); 1498 1.1 mrg es.sz = sz; 1499 1.1 mrg es.committed = 0; //es1.committed; 1500 1.1 mrg es.type = type; 1501 1.1 mrg return ue; 1502 1.1 mrg } 1503 1.1 mrg if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) 1504 1.1 mrg { 1505 1.1 mrg // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] 1506 1.1 mrg ArrayLiteralExp es1 = e1.isArrayLiteralExp(); 1507 1.1 mrg ArrayLiteralExp es2 = e2.isArrayLiteralExp(); 1508 1.1 mrg emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements)); 1509 1.1 mrg es1 = ue.exp().isArrayLiteralExp(); 1510 1.1 mrg es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements)); 1511 1.1 mrg return ue; 1512 1.1 mrg } 1513 1.1 mrg if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf())) 1514 1.1 mrg { 1515 1.1 mrg // [ e1 ] ~ null ----> [ e1 ].dup 1516 1.1 mrg ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy()); 1517 1.1 mrg return ue; 1518 1.1 mrg } 1519 1.1 mrg if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) 1520 1.1 mrg { 1521 1.1 mrg // null ~ [ e2 ] ----> [ e2 ].dup 1522 1.1 mrg ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy()); 1523 1.1 mrg return ue; 1524 1.1 mrg } 1525 1.1 mrg ue = Cat(loc, type, e1, e2); 1526 1.1 mrg return ue; 1527 1.1 mrg } 1528 1.1 mrg 1529 1.1 mrg /* Given an AA literal 'ae', and a key 'e2': 1530 1.1 mrg * Return ae[e2] if present, or NULL if not found. 1531 1.1 mrg */ 1532 1.1 mrg Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2) 1533 1.1 mrg { 1534 1.1 mrg /* Search the keys backwards, in case there are duplicate keys 1535 1.1 mrg */ 1536 1.1 mrg for (size_t i = ae.keys.dim; i;) 1537 1.1 mrg { 1538 1.1 mrg --i; 1539 1.1 mrg Expression ekey = (*ae.keys)[i]; 1540 1.1 mrg const int eq = ctfeEqual(loc, EXP.equal, ekey, e2); 1541 1.1 mrg if (eq) 1542 1.1 mrg { 1543 1.1 mrg return (*ae.values)[i]; 1544 1.1 mrg } 1545 1.1 mrg } 1546 1.1 mrg return null; 1547 1.1 mrg } 1548 1.1 mrg 1549 1.1 mrg /* Same as for constfold.Index, except that it only works for static arrays, 1550 1.1 mrg * dynamic arrays, and strings. We know that e1 is an 1551 1.1 mrg * interpreted CTFE expression, so it cannot have side-effects. 1552 1.1 mrg */ 1553 1.1 mrg Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, uinteger_t indx) 1554 1.1 mrg { 1555 1.1 mrg //printf("ctfeIndex(e1 = %s)\n", e1.toChars()); 1556 1.1 mrg assert(e1.type); 1557 1.1 mrg if (auto es1 = e1.isStringExp()) 1558 1.1 mrg { 1559 1.1 mrg if (indx >= es1.len) 1560 1.1 mrg { 1561 1.1 mrg error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len); 1562 1.1 mrg return CTFEExp.cantexp; 1563 1.1 mrg } 1564 1.1 mrg emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type); 1565 1.1 mrg return pue.exp(); 1566 1.1 mrg } 1567 1.1 mrg 1568 1.1 mrg if (auto ale = e1.isArrayLiteralExp()) 1569 1.1 mrg { 1570 1.1 mrg if (indx >= ale.elements.dim) 1571 1.1 mrg { 1572 1.1 mrg error(loc, "array index %llu is out of bounds `%s[0 .. %llu]`", indx, e1.toChars(), cast(ulong)ale.elements.dim); 1573 1.1 mrg return CTFEExp.cantexp; 1574 1.1 mrg } 1575 1.1 mrg Expression e = (*ale.elements)[cast(size_t)indx]; 1576 1.1 mrg return paintTypeOntoLiteral(pue, type, e); 1577 1.1 mrg } 1578 1.1 mrg 1579 1.1 mrg assert(0); 1580 1.1 mrg } 1581 1.1 mrg 1582 1.1 mrg Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e, bool explicitCast = false) 1583 1.1 mrg { 1584 1.1 mrg Expression paint() 1585 1.1 mrg { 1586 1.1 mrg return paintTypeOntoLiteral(pue, to, e); 1587 1.1 mrg } 1588 1.1 mrg 1589 1.1 mrg if (e.op == EXP.null_) 1590 1.1 mrg return paint(); 1591 1.1 mrg 1592 1.1 mrg if (e.op == EXP.classReference) 1593 1.1 mrg { 1594 1.1 mrg // Disallow reinterpreting class casts. Do this by ensuring that 1595 1.1 mrg // the original class can implicitly convert to the target class. 1596 1.1 mrg // Also do not check 'alias this' for explicit cast expressions. 1597 1.1 mrg auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass(); 1598 1.1 mrg auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf()) 1599 1.1 mrg : tclass.implicitConvTo(to.mutableOf()); 1600 1.1 mrg if (match) 1601 1.1 mrg return paint(); 1602 1.1 mrg else 1603 1.1 mrg { 1604 1.1 mrg emplaceExp!(NullExp)(pue, loc, to); 1605 1.1 mrg return pue.exp(); 1606 1.1 mrg } 1607 1.1 mrg } 1608 1.1 mrg 1609 1.1 mrg // Allow TypeInfo type painting 1610 1.1 mrg if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to)) 1611 1.1 mrg return paint(); 1612 1.1 mrg 1613 1.1 mrg // Allow casting away const for struct literals 1614 1.1 mrg if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0)) 1615 1.1 mrg return paint(); 1616 1.1 mrg 1617 1.1 mrg Expression r; 1618 1.1 mrg if (e.type.equals(type) && type.equals(to)) 1619 1.1 mrg { 1620 1.1 mrg // necessary not to change e's address for pointer comparisons 1621 1.1 mrg r = e; 1622 1.1 mrg } 1623 1.1 mrg else if (to.toBasetype().ty == Tarray && 1624 1.1 mrg type.toBasetype().ty == Tarray && 1625 1.1 mrg to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size()) 1626 1.1 mrg { 1627 1.1 mrg // https://issues.dlang.org/show_bug.cgi?id=12495 1628 1.1 mrg // Array reinterpret casts: eg. string to immutable(ubyte)[] 1629 1.1 mrg return paint(); 1630 1.1 mrg } 1631 1.1 mrg else 1632 1.1 mrg { 1633 1.1 mrg *pue = Cast(loc, type, to, e); 1634 1.1 mrg r = pue.exp(); 1635 1.1 mrg } 1636 1.1 mrg 1637 1.1 mrg if (CTFEExp.isCantExp(r)) 1638 1.1 mrg error(loc, "cannot cast `%s` to `%s` at compile time", e.toChars(), to.toChars()); 1639 1.1 mrg 1640 1.1 mrg if (auto ae = e.isArrayLiteralExp()) 1641 1.1 mrg ae.ownedByCtfe = OwnedBy.ctfe; 1642 1.1 mrg 1643 1.1 mrg if (auto se = e.isStringExp()) 1644 1.1 mrg se.ownedByCtfe = OwnedBy.ctfe; 1645 1.1 mrg 1646 1.1 mrg return r; 1647 1.1 mrg } 1648 1.1 mrg 1649 1.1 mrg /******** Assignment helper functions ***************************/ 1650 1.1 mrg /* Set dest = src, where both dest and src are container value literals 1651 1.1 mrg * (ie, struct literals, or static arrays (can be an array literal or a string)) 1652 1.1 mrg * Assignment is recursively in-place. 1653 1.1 mrg * Purpose: any reference to a member of 'dest' will remain valid after the 1654 1.1 mrg * assignment. 1655 1.1 mrg */ 1656 1.1 mrg void assignInPlace(Expression dest, Expression src) 1657 1.1 mrg { 1658 1.1 mrg if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_)) 1659 1.1 mrg { 1660 1.1 mrg printf("invalid op %d %d\n", src.op, dest.op); 1661 1.1 mrg assert(0); 1662 1.1 mrg } 1663 1.1 mrg Expressions* oldelems; 1664 1.1 mrg Expressions* newelems; 1665 1.1 mrg if (dest.op == EXP.structLiteral) 1666 1.1 mrg { 1667 1.1 mrg assert(dest.op == src.op); 1668 1.1 mrg oldelems = dest.isStructLiteralExp().elements; 1669 1.1 mrg newelems = src.isStructLiteralExp().elements; 1670 1.1 mrg auto sd = dest.isStructLiteralExp().sd; 1671 1.1 mrg const nfields = sd.nonHiddenFields(); 1672 1.1 mrg const nvthis = sd.fields.dim - nfields; 1673 1.1 mrg if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim) 1674 1.1 mrg foreach (_; 0 .. newelems.dim - oldelems.dim) 1675 1.1 mrg oldelems.push(null); 1676 1.1 mrg } 1677 1.1 mrg else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral) 1678 1.1 mrg { 1679 1.1 mrg oldelems = dest.isArrayLiteralExp().elements; 1680 1.1 mrg newelems = src.isArrayLiteralExp().elements; 1681 1.1 mrg } 1682 1.1 mrg else if (dest.op == EXP.string_ && src.op == EXP.string_) 1683 1.1 mrg { 1684 1.1 mrg sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0); 1685 1.1 mrg return; 1686 1.1 mrg } 1687 1.1 mrg else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_) 1688 1.1 mrg { 1689 1.1 mrg sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0); 1690 1.1 mrg return; 1691 1.1 mrg } 1692 1.1 mrg else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_) 1693 1.1 mrg { 1694 1.1 mrg sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0); 1695 1.1 mrg return; 1696 1.1 mrg } 1697 1.1 mrg else 1698 1.1 mrg { 1699 1.1 mrg printf("invalid op %d %d\n", src.op, dest.op); 1700 1.1 mrg assert(0); 1701 1.1 mrg } 1702 1.1 mrg assert(oldelems.dim == newelems.dim); 1703 1.1 mrg foreach (size_t i; 0 .. oldelems.dim) 1704 1.1 mrg { 1705 1.1 mrg Expression e = (*newelems)[i]; 1706 1.1 mrg Expression o = (*oldelems)[i]; 1707 1.1 mrg if (e.op == EXP.structLiteral) 1708 1.1 mrg { 1709 1.1 mrg assert(o.op == e.op); 1710 1.1 mrg assignInPlace(o, e); 1711 1.1 mrg } 1712 1.1 mrg else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray) 1713 1.1 mrg { 1714 1.1 mrg assignInPlace(o, e); 1715 1.1 mrg } 1716 1.1 mrg else 1717 1.1 mrg { 1718 1.1 mrg (*oldelems)[i] = (*newelems)[i]; 1719 1.1 mrg } 1720 1.1 mrg } 1721 1.1 mrg } 1722 1.1 mrg 1723 1.1 mrg // Given an AA literal aae, set aae[index] = newval and return newval. 1724 1.1 mrg Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval) 1725 1.1 mrg { 1726 1.1 mrg /* Create new associative array literal reflecting updated key/value 1727 1.1 mrg */ 1728 1.1 mrg Expressions* keysx = aae.keys; 1729 1.1 mrg Expressions* valuesx = aae.values; 1730 1.1 mrg int updated = 0; 1731 1.1 mrg for (size_t j = valuesx.dim; j;) 1732 1.1 mrg { 1733 1.1 mrg j--; 1734 1.1 mrg Expression ekey = (*aae.keys)[j]; 1735 1.1 mrg int eq = ctfeEqual(loc, EXP.equal, ekey, index); 1736 1.1 mrg if (eq) 1737 1.1 mrg { 1738 1.1 mrg (*valuesx)[j] = newval; 1739 1.1 mrg updated = 1; 1740 1.1 mrg } 1741 1.1 mrg } 1742 1.1 mrg if (!updated) 1743 1.1 mrg { 1744 1.1 mrg // Append index/newval to keysx[]/valuesx[] 1745 1.1 mrg valuesx.push(newval); 1746 1.1 mrg keysx.push(index); 1747 1.1 mrg } 1748 1.1 mrg return newval; 1749 1.1 mrg } 1750 1.1 mrg 1751 1.1 mrg /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length 1752 1.1 mrg /// oldlen, change its length to newlen. If the newlen is longer than oldlen, 1753 1.1 mrg /// all new elements will be set to the default initializer for the element type. 1754 1.1 mrg Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen) 1755 1.1 mrg { 1756 1.1 mrg Type elemType = arrayType.next; 1757 1.1 mrg assert(elemType); 1758 1.1 mrg Expression defaultElem = elemType.defaultInitLiteral(loc); 1759 1.1 mrg auto elements = new Expressions(newlen); 1760 1.1 mrg // Resolve slices 1761 1.1 mrg size_t indxlo = 0; 1762 1.1 mrg if (oldval.op == EXP.slice) 1763 1.1 mrg { 1764 1.1 mrg indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger(); 1765 1.1 mrg oldval = oldval.isSliceExp().e1; 1766 1.1 mrg } 1767 1.1 mrg size_t copylen = oldlen < newlen ? oldlen : newlen; 1768 1.1 mrg if (oldval.op == EXP.string_) 1769 1.1 mrg { 1770 1.1 mrg StringExp oldse = oldval.isStringExp(); 1771 1.1 mrg void* s = mem.xcalloc(newlen + 1, oldse.sz); 1772 1.1 mrg const data = oldse.peekData(); 1773 1.1 mrg memcpy(s, data.ptr, copylen * oldse.sz); 1774 1.1 mrg const defaultValue = cast(uint)defaultElem.toInteger(); 1775 1.1 mrg foreach (size_t elemi; copylen .. newlen) 1776 1.1 mrg { 1777 1.1 mrg switch (oldse.sz) 1778 1.1 mrg { 1779 1.1 mrg case 1: 1780 1.1 mrg (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue; 1781 1.1 mrg break; 1782 1.1 mrg case 2: 1783 1.1 mrg (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue; 1784 1.1 mrg break; 1785 1.1 mrg case 4: 1786 1.1 mrg (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; 1787 1.1 mrg break; 1788 1.1 mrg default: 1789 1.1 mrg assert(0); 1790 1.1 mrg } 1791 1.1 mrg } 1792 1.1 mrg emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz); 1793 1.1 mrg StringExp se = pue.exp().isStringExp(); 1794 1.1 mrg se.type = arrayType; 1795 1.1 mrg se.sz = oldse.sz; 1796 1.1 mrg se.committed = oldse.committed; 1797 1.1 mrg se.ownedByCtfe = OwnedBy.ctfe; 1798 1.1 mrg } 1799 1.1 mrg else 1800 1.1 mrg { 1801 1.1 mrg if (oldlen != 0) 1802 1.1 mrg { 1803 1.1 mrg assert(oldval.op == EXP.arrayLiteral); 1804 1.1 mrg ArrayLiteralExp ae = oldval.isArrayLiteralExp(); 1805 1.1 mrg foreach (size_t i; 0 .. copylen) 1806 1.1 mrg (*elements)[i] = (*ae.elements)[indxlo + i]; 1807 1.1 mrg } 1808 1.1 mrg if (elemType.ty == Tstruct || elemType.ty == Tsarray) 1809 1.1 mrg { 1810 1.1 mrg /* If it is an aggregate literal representing a value type, 1811 1.1 mrg * we need to create a unique copy for each element 1812 1.1 mrg */ 1813 1.1 mrg foreach (size_t i; copylen .. newlen) 1814 1.1 mrg (*elements)[i] = copyLiteral(defaultElem).copy(); 1815 1.1 mrg } 1816 1.1 mrg else 1817 1.1 mrg { 1818 1.1 mrg foreach (size_t i; copylen .. newlen) 1819 1.1 mrg (*elements)[i] = defaultElem; 1820 1.1 mrg } 1821 1.1 mrg emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements); 1822 1.1 mrg ArrayLiteralExp aae = pue.exp().isArrayLiteralExp(); 1823 1.1 mrg aae.ownedByCtfe = OwnedBy.ctfe; 1824 1.1 mrg } 1825 1.1 mrg return pue.exp(); 1826 1.1 mrg } 1827 1.1 mrg 1828 1.1 mrg /*************************** CTFE Sanity Checks ***************************/ 1829 1.1 mrg 1830 1.1 mrg bool isCtfeValueValid(Expression newval) 1831 1.1 mrg { 1832 1.1 mrg Type tb = newval.type.toBasetype(); 1833 1.1 mrg switch (newval.op) 1834 1.1 mrg { 1835 1.1 mrg case EXP.int64: 1836 1.1 mrg case EXP.float64: 1837 1.1 mrg case EXP.char_: 1838 1.1 mrg case EXP.complex80: 1839 1.1 mrg return tb.isscalar(); 1840 1.1 mrg 1841 1.1 mrg case EXP.null_: 1842 1.1 mrg return tb.ty == Tnull || 1843 1.1 mrg tb.ty == Tpointer || 1844 1.1 mrg tb.ty == Tarray || 1845 1.1 mrg tb.ty == Taarray || 1846 1.1 mrg tb.ty == Tclass || 1847 1.1 mrg tb.ty == Tdelegate; 1848 1.1 mrg 1849 1.1 mrg case EXP.string_: 1850 1.1 mrg return true; // CTFE would directly use the StringExp in AST. 1851 1.1 mrg 1852 1.1 mrg case EXP.arrayLiteral: 1853 1.1 mrg return true; //((ArrayLiteralExp *)newval)->ownedByCtfe; 1854 1.1 mrg 1855 1.1 mrg case EXP.assocArrayLiteral: 1856 1.1 mrg return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe; 1857 1.1 mrg 1858 1.1 mrg case EXP.structLiteral: 1859 1.1 mrg return true; //((StructLiteralExp *)newval)->ownedByCtfe; 1860 1.1 mrg 1861 1.1 mrg case EXP.classReference: 1862 1.1 mrg return true; 1863 1.1 mrg 1864 1.1 mrg case EXP.type: 1865 1.1 mrg return true; 1866 1.1 mrg 1867 1.1 mrg case EXP.vector: 1868 1.1 mrg return true; // vector literal 1869 1.1 mrg 1870 1.1 mrg case EXP.function_: 1871 1.1 mrg return true; // function literal or delegate literal 1872 1.1 mrg 1873 1.1 mrg case EXP.delegate_: 1874 1.1 mrg { 1875 1.1 mrg // &struct.func or &clasinst.func 1876 1.1 mrg // &nestedfunc 1877 1.1 mrg Expression ethis = newval.isDelegateExp().e1; 1878 1.1 mrg return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func); 1879 1.1 mrg } 1880 1.1 mrg 1881 1.1 mrg case EXP.symbolOffset: 1882 1.1 mrg { 1883 1.1 mrg // function pointer, or pointer to static variable 1884 1.1 mrg Declaration d = newval.isSymOffExp().var; 1885 1.1 mrg return d.isFuncDeclaration() || d.isDataseg(); 1886 1.1 mrg } 1887 1.1 mrg 1888 1.1 mrg case EXP.typeid_: 1889 1.1 mrg { 1890 1.1 mrg // always valid 1891 1.1 mrg return true; 1892 1.1 mrg } 1893 1.1 mrg 1894 1.1 mrg case EXP.address: 1895 1.1 mrg { 1896 1.1 mrg // e1 should be a CTFE reference 1897 1.1 mrg Expression e1 = newval.isAddrExp().e1; 1898 1.1 mrg return tb.ty == Tpointer && 1899 1.1 mrg ( 1900 1.1 mrg (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) || 1901 1.1 mrg e1.op == EXP.variable || 1902 1.1 mrg e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) || 1903 1.1 mrg e1.op == EXP.index && isCtfeReferenceValid(e1) || 1904 1.1 mrg e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray 1905 1.1 mrg ); 1906 1.1 mrg } 1907 1.1 mrg 1908 1.1 mrg case EXP.slice: 1909 1.1 mrg { 1910 1.1 mrg // e1 should be an array aggregate 1911 1.1 mrg const SliceExp se = newval.isSliceExp(); 1912 1.1 mrg assert(se.lwr && se.lwr.op == EXP.int64); 1913 1.1 mrg assert(se.upr && se.upr.op == EXP.int64); 1914 1.1 mrg return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral); 1915 1.1 mrg } 1916 1.1 mrg 1917 1.1 mrg case EXP.void_: 1918 1.1 mrg return true; // uninitialized value 1919 1.1 mrg 1920 1.1 mrg default: 1921 1.1 mrg newval.error("CTFE internal error: illegal CTFE value `%s`", newval.toChars()); 1922 1.1 mrg return false; 1923 1.1 mrg } 1924 1.1 mrg } 1925 1.1 mrg 1926 1.1 mrg bool isCtfeReferenceValid(Expression newval) 1927 1.1 mrg { 1928 1.1 mrg switch (newval.op) 1929 1.1 mrg { 1930 1.1 mrg case EXP.this_: 1931 1.1 mrg return true; 1932 1.1 mrg 1933 1.1 mrg case EXP.variable: 1934 1.1 mrg { 1935 1.1 mrg const VarDeclaration v = newval.isVarExp().var.isVarDeclaration(); 1936 1.1 mrg assert(v); 1937 1.1 mrg // Must not be a reference to a reference 1938 1.1 mrg return true; 1939 1.1 mrg } 1940 1.1 mrg 1941 1.1 mrg case EXP.index: 1942 1.1 mrg { 1943 1.1 mrg const Expression eagg = newval.isIndexExp().e1; 1944 1.1 mrg return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral; 1945 1.1 mrg } 1946 1.1 mrg 1947 1.1 mrg case EXP.dotVariable: 1948 1.1 mrg { 1949 1.1 mrg Expression eagg = newval.isDotVarExp().e1; 1950 1.1 mrg return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg); 1951 1.1 mrg } 1952 1.1 mrg 1953 1.1 mrg default: 1954 1.1 mrg // Internally a ref variable may directly point a stack memory. 1955 1.1 mrg // e.g. ref int v = 1; 1956 1.1 mrg return isCtfeValueValid(newval); 1957 1.1 mrg } 1958 1.1 mrg } 1959 1.1 mrg 1960 1.1 mrg // Used for debugging only 1961 1.1 mrg void showCtfeExpr(Expression e, int level = 0) 1962 1.1 mrg { 1963 1.1 mrg for (int i = level; i > 0; --i) 1964 1.1 mrg printf(" "); 1965 1.1 mrg Expressions* elements = null; 1966 1.1 mrg // We need the struct definition to detect block assignment 1967 1.1 mrg StructDeclaration sd = null; 1968 1.1 mrg ClassDeclaration cd = null; 1969 1.1 mrg if (e.op == EXP.structLiteral) 1970 1.1 mrg { 1971 1.1 mrg elements = e.isStructLiteralExp().elements; 1972 1.1 mrg sd = e.isStructLiteralExp().sd; 1973 1.1 mrg printf("STRUCT type = %s %p:\n", e.type.toChars(), e); 1974 1.1 mrg } 1975 1.1 mrg else if (e.op == EXP.classReference) 1976 1.1 mrg { 1977 1.1 mrg elements = e.isClassReferenceExp().value.elements; 1978 1.1 mrg cd = e.isClassReferenceExp().originalClass(); 1979 1.1 mrg printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value); 1980 1.1 mrg } 1981 1.1 mrg else if (e.op == EXP.arrayLiteral) 1982 1.1 mrg { 1983 1.1 mrg elements = e.isArrayLiteralExp().elements; 1984 1.1 mrg printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e); 1985 1.1 mrg } 1986 1.1 mrg else if (e.op == EXP.assocArrayLiteral) 1987 1.1 mrg { 1988 1.1 mrg printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e); 1989 1.1 mrg } 1990 1.1 mrg else if (e.op == EXP.string_) 1991 1.1 mrg { 1992 1.1 mrg printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr); 1993 1.1 mrg } 1994 1.1 mrg else if (e.op == EXP.slice) 1995 1.1 mrg { 1996 1.1 mrg printf("SLICE %p: %s\n", e, e.toChars()); 1997 1.1 mrg showCtfeExpr(e.isSliceExp().e1, level + 1); 1998 1.1 mrg } 1999 1.1 mrg else if (e.op == EXP.variable) 2000 1.1 mrg { 2001 1.1 mrg printf("VAR %p %s\n", e, e.toChars()); 2002 1.1 mrg VarDeclaration v = e.isVarExp().var.isVarDeclaration(); 2003 1.1 mrg if (v && getValue(v)) 2004 1.1 mrg showCtfeExpr(getValue(v), level + 1); 2005 1.1 mrg } 2006 1.1 mrg else if (e.op == EXP.address) 2007 1.1 mrg { 2008 1.1 mrg // This is potentially recursive. We mustn't try to print the thing we're pointing to. 2009 1.1 mrg printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars()); 2010 1.1 mrg } 2011 1.1 mrg else 2012 1.1 mrg printf("VALUE %p: %s\n", e, e.toChars()); 2013 1.1 mrg if (elements) 2014 1.1 mrg { 2015 1.1 mrg size_t fieldsSoFar = 0; 2016 1.1 mrg for (size_t i = 0; i < elements.dim; i++) 2017 1.1 mrg { 2018 1.1 mrg Expression z = null; 2019 1.1 mrg VarDeclaration v = null; 2020 1.1 mrg if (i > 15) 2021 1.1 mrg { 2022 1.1 mrg printf("...(total %d elements)\n", cast(int)elements.dim); 2023 1.1 mrg return; 2024 1.1 mrg } 2025 1.1 mrg if (sd) 2026 1.1 mrg { 2027 1.1 mrg v = sd.fields[i]; 2028 1.1 mrg z = (*elements)[i]; 2029 1.1 mrg } 2030 1.1 mrg else if (cd) 2031 1.1 mrg { 2032 1.1 mrg while (i - fieldsSoFar >= cd.fields.dim) 2033 1.1 mrg { 2034 1.1 mrg fieldsSoFar += cd.fields.dim; 2035 1.1 mrg cd = cd.baseClass; 2036 1.1 mrg for (int j = level; j > 0; --j) 2037 1.1 mrg printf(" "); 2038 1.1 mrg printf(" BASE CLASS: %s\n", cd.toChars()); 2039 1.1 mrg } 2040 1.1 mrg v = cd.fields[i - fieldsSoFar]; 2041 1.1 mrg assert((elements.dim + i) >= (fieldsSoFar + cd.fields.dim)); 2042 1.1 mrg size_t indx = (elements.dim - fieldsSoFar) - cd.fields.dim + i; 2043 1.1 mrg assert(indx < elements.dim); 2044 1.1 mrg z = (*elements)[indx]; 2045 1.1 mrg } 2046 1.1 mrg if (!z) 2047 1.1 mrg { 2048 1.1 mrg for (int j = level; j > 0; --j) 2049 1.1 mrg printf(" "); 2050 1.1 mrg printf(" void\n"); 2051 1.1 mrg continue; 2052 1.1 mrg } 2053 1.1 mrg if (v) 2054 1.1 mrg { 2055 1.1 mrg // If it is a void assignment, use the default initializer 2056 1.1 mrg if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray) 2057 1.1 mrg { 2058 1.1 mrg for (int j = level; --j;) 2059 1.1 mrg printf(" "); 2060 1.1 mrg printf(" field: block initialized static array\n"); 2061 1.1 mrg continue; 2062 1.1 mrg } 2063 1.1 mrg } 2064 1.1 mrg showCtfeExpr(z, level + 1); 2065 1.1 mrg } 2066 1.1 mrg } 2067 1.1 mrg } 2068 1.1 mrg 2069 1.1 mrg /*************************** Void initialization ***************************/ 2070 1.1 mrg UnionExp voidInitLiteral(Type t, VarDeclaration var) 2071 1.1 mrg { 2072 1.1 mrg UnionExp ue; 2073 1.1 mrg if (t.ty == Tsarray) 2074 1.1 mrg { 2075 1.1 mrg TypeSArray tsa = cast(TypeSArray)t; 2076 1.1 mrg Expression elem = voidInitLiteral(tsa.next, var).copy(); 2077 1.1 mrg // For aggregate value types (structs, static arrays) we must 2078 1.1 mrg // create an a separate copy for each element. 2079 1.1 mrg const mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral); 2080 1.1 mrg const d = cast(size_t)tsa.dim.toInteger(); 2081 1.1 mrg auto elements = new Expressions(d); 2082 1.1 mrg foreach (i; 0 .. d) 2083 1.1 mrg { 2084 1.1 mrg if (mustCopy && i > 0) 2085 1.1 mrg elem = copyLiteral(elem).copy(); 2086 1.1 mrg (*elements)[i] = elem; 2087 1.1 mrg } 2088 1.1 mrg emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements); 2089 1.1 mrg ArrayLiteralExp ae = ue.exp().isArrayLiteralExp(); 2090 1.1 mrg ae.ownedByCtfe = OwnedBy.ctfe; 2091 1.1 mrg } 2092 1.1 mrg else if (t.ty == Tstruct) 2093 1.1 mrg { 2094 1.1 mrg TypeStruct ts = cast(TypeStruct)t; 2095 1.1 mrg auto exps = new Expressions(ts.sym.fields.dim); 2096 1.1 mrg foreach (size_t i; 0 .. ts.sym.fields.dim) 2097 1.1 mrg { 2098 1.1 mrg (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy(); 2099 1.1 mrg } 2100 1.1 mrg emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps); 2101 1.1 mrg StructLiteralExp se = ue.exp().isStructLiteralExp(); 2102 1.1 mrg se.type = ts; 2103 1.1 mrg se.ownedByCtfe = OwnedBy.ctfe; 2104 1.1 mrg } 2105 1.1 mrg else 2106 1.1 mrg emplaceExp!(VoidInitExp)(&ue, var); 2107 1.1 mrg return ue; 2108 1.1 mrg } 2109