1 /** 2 * Semantic analysis of initializers. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/initsem.d, _initsem.d) 8 * Documentation: https://dlang.org/phobos/dmd_initsem.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/initsem.d 10 */ 11 12 module dmd.initsem; 13 14 import core.stdc.stdio; 15 import core.checkedint; 16 17 import dmd.aggregate; 18 import dmd.aliasthis; 19 import dmd.arraytypes; 20 import dmd.astenums; 21 import dmd.dcast; 22 import dmd.declaration; 23 import dmd.dinterpret; 24 import dmd.dscope; 25 import dmd.dstruct; 26 import dmd.dsymbol; 27 import dmd.dtemplate; 28 import dmd.errors; 29 import dmd.expression; 30 import dmd.expressionsem; 31 import dmd.func; 32 import dmd.globals; 33 import dmd.hdrgen; 34 import dmd.id; 35 import dmd.identifier; 36 import dmd.importc; 37 import dmd.init; 38 import dmd.location; 39 import dmd.mtype; 40 import dmd.opover; 41 import dmd.statement; 42 import dmd.target; 43 import dmd.tokens; 44 import dmd.typesem; 45 46 /******************************** 47 * If possible, convert array initializer to associative array initializer. 48 * 49 * Params: 50 * ai = array initializer to be converted 51 * 52 * Returns: 53 * The converted associative array initializer or ErrorExp if `ai` 54 * is not an associative array initializer. 55 */ 56 Expression toAssocArrayLiteral(ArrayInitializer ai) 57 { 58 //printf("ArrayInitializer::toAssocArrayInitializer(%s)\n", ai.toChars()); 59 //static int i; if (++i == 2) assert(0); 60 const dim = ai.value.length; 61 if (!dim) 62 { 63 error(ai.loc, "invalid associative array initializer `%s`, use `null` instead", 64 toChars(ai)); 65 return ErrorExp.get(); 66 } 67 auto no(const char* format, Initializer i) 68 { 69 error(i.loc, format, toChars(i)); 70 return ErrorExp.get(); 71 } 72 Expression e; 73 auto keys = new Expressions(dim); 74 auto values = new Expressions(dim); 75 for (size_t i = 0; i < dim; i++) 76 { 77 Initializer iz = ai.value[i]; 78 assert(iz); 79 e = iz.initializerToExpression(); 80 if (!e) 81 return no("invalid value `%s` in initializer", iz); 82 (*values)[i] = e; 83 e = ai.index[i]; 84 if (!e) 85 return no("missing key for value `%s` in initializer", iz); 86 (*keys)[i] = e; 87 } 88 e = new AssocArrayLiteralExp(ai.loc, keys, values); 89 return e; 90 } 91 92 /****************************************** 93 * Perform semantic analysis on init. 94 * Params: 95 * init = Initializer AST node 96 * sc = context 97 * tx = type that the initializer needs to become. If tx is an incomplete 98 * type and the initializer completes it, it is updated to be the 99 * complete type. ImportC has incomplete types 100 * needInterpret = if CTFE needs to be run on this, 101 * such as if it is the initializer for a const declaration 102 * Returns: 103 * `Initializer` with completed semantic analysis, `ErrorInitializer` if errors 104 * were encountered 105 */ 106 extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret) 107 { 108 Type t = tx; 109 110 static Initializer err() 111 { 112 return new ErrorInitializer(); 113 } 114 115 Initializer visitVoid(VoidInitializer i) 116 { 117 i.type = t; 118 return i; 119 } 120 121 Initializer visitError(ErrorInitializer i) 122 { 123 return i; 124 } 125 126 Initializer visitStruct(StructInitializer i) 127 { 128 //printf("StructInitializer::semantic(t = %s) %s\n", t.toChars(), i.toChars()); 129 /* This works by replacing the StructInitializer with an ExpInitializer. 130 */ 131 t = t.toBasetype(); 132 if (t.ty == Tsarray && t.nextOf().toBasetype().ty == Tstruct) 133 t = t.nextOf().toBasetype(); 134 if (auto ts = t.isTypeStruct()) 135 { 136 StructDeclaration sd = ts.sym; 137 // check if the sd has a regular ctor (user defined non-copy ctor) 138 // that is not disabled. 139 if (sd.hasRegularCtor(true)) 140 { 141 error(i.loc, "%s `%s` has constructors, cannot use `{ initializers }`, use `%s( initializers )` instead", sd.kind(), sd.toChars(), sd.toChars()); 142 return err(); 143 } 144 sd.size(i.loc); 145 if (sd.sizeok != Sizeok.done) 146 return err(); 147 148 Expression getExp(size_t j, Type fieldType) 149 { 150 // Convert initializer to Expression `ex` 151 auto tm = fieldType.addMod(t.mod); 152 auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); 153 auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); 154 if (ex.op != EXP.error) 155 i.value[j] = iz; 156 return ex; 157 } 158 auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc); 159 if (!elements) 160 return err(); 161 162 // Make a StructLiteralExp out of elements[] 163 auto sle = new StructLiteralExp(i.loc, sd, elements, t); 164 if (!sd.fill(i.loc, *elements, false)) 165 return err(); 166 sle.type = t; 167 auto ie = new ExpInitializer(i.loc, sle); 168 return ie.initializerSemantic(sc, t, needInterpret); 169 } 170 else if ((t.ty == Tdelegate || t.isPtrToFunction()) && i.value.length == 0) 171 { 172 const tok = (t.ty == Tdelegate) ? TOK.delegate_ : TOK.function_; 173 /* Rewrite as empty delegate literal { } 174 */ 175 Type tf = new TypeFunction(ParameterList(), null, LINK.d); 176 auto fd = new FuncLiteralDeclaration(i.loc, Loc.initial, tf, tok, null); 177 fd.fbody = new CompoundStatement(i.loc, new Statements()); 178 fd.endloc = i.loc; 179 Expression e = new FuncExp(i.loc, fd); 180 auto ie = new ExpInitializer(i.loc, e); 181 return ie.initializerSemantic(sc, t, needInterpret); 182 } 183 if (t.ty != Terror) 184 error(i.loc, "a struct is not a valid initializer for a `%s`", t.toChars()); 185 return err(); 186 } 187 188 Initializer visitArray(ArrayInitializer i) 189 { 190 uint length; 191 const(uint) amax = 0x80000000; 192 bool errors = false; 193 //printf("ArrayInitializer::semantic(%s), ai: %s %p\n", t.toChars(), i.toChars(), i); 194 if (i.sem) // if semantic() already run 195 { 196 return i; 197 } 198 i.sem = true; 199 t = t.toBasetype(); 200 switch (t.ty) 201 { 202 case Tsarray: 203 case Tarray: 204 break; 205 case Tvector: 206 t = t.isTypeVector().basetype; 207 break; 208 case Taarray: 209 case Tstruct: // consider implicit constructor call 210 { 211 Expression e; 212 // note: MyStruct foo = [1:2, 3:4] is correct code if MyStruct has a this(int[int]) 213 if (t.ty == Taarray || i.isAssociativeArray()) 214 e = i.toAssocArrayLiteral(); 215 else 216 e = i.initializerToExpression(); 217 // Bugzilla 13987 218 if (!e) 219 { 220 error(i.loc, "cannot use array to initialize `%s`", t.toChars()); 221 return err(); 222 } 223 auto ei = new ExpInitializer(e.loc, e); 224 return ei.initializerSemantic(sc, t, needInterpret); 225 } 226 case Tpointer: 227 if (t.nextOf().ty != Tfunction) 228 break; 229 goto default; 230 default: 231 error(i.loc, "cannot use array to initialize `%s`", t.toChars()); 232 return err(); 233 } 234 i.type = t; 235 length = 0; 236 for (size_t j = 0; j < i.index.length; j++) 237 { 238 Expression idx = i.index[j]; 239 if (idx) 240 { 241 sc = sc.startCTFE(); 242 idx = idx.expressionSemantic(sc); 243 sc = sc.endCTFE(); 244 idx = idx.ctfeInterpret(); 245 i.index[j] = idx; 246 const uinteger_t idxvalue = idx.toInteger(); 247 if (idxvalue >= amax) 248 { 249 error(i.loc, "array index %llu overflow", idxvalue); 250 errors = true; 251 } 252 length = cast(uint)idxvalue; 253 if (idx.op == EXP.error) 254 errors = true; 255 } 256 Initializer val = i.value[j]; 257 ExpInitializer ei = val.isExpInitializer(); 258 if (ei && !idx) 259 ei.expandTuples = true; 260 auto tn = t.nextOf(); 261 val = val.initializerSemantic(sc, tn, needInterpret); 262 if (val.isErrorInitializer()) 263 errors = true; 264 ei = val.isExpInitializer(); 265 // found a tuple, expand it 266 if (ei && ei.exp.op == EXP.tuple) 267 { 268 TupleExp te = ei.exp.isTupleExp(); 269 i.index.remove(j); 270 i.value.remove(j); 271 for (size_t k = 0; k < te.exps.length; ++k) 272 { 273 Expression e = (*te.exps)[k]; 274 i.index.insert(j + k, cast(Expression)null); 275 i.value.insert(j + k, new ExpInitializer(e.loc, e)); 276 } 277 j--; 278 continue; 279 } 280 else 281 { 282 i.value[j] = val; 283 } 284 length++; 285 if (length == 0) 286 { 287 error(i.loc, "array dimension overflow"); 288 return err(); 289 } 290 if (length > i.dim) 291 i.dim = length; 292 } 293 if (auto tsa = t.isTypeSArray()) 294 { 295 if (sc.flags & SCOPE.Cfile && tsa.isIncomplete()) 296 { 297 // Change to array of known length 298 auto tn = tsa.next.toBasetype(); 299 tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, i.dim, Type.tsize_t)); 300 tx = tsa; // rewrite caller's type 301 i.type = tsa; // remember for later passes 302 } 303 else 304 { 305 uinteger_t edim = tsa.dim.toInteger(); 306 if (i.dim > edim) 307 { 308 error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim); 309 return err(); 310 } 311 } 312 } 313 if (errors) 314 return err(); 315 316 const sz = t.nextOf().size(); 317 if (sz == SIZE_INVALID) 318 return err(); 319 bool overflow; 320 const max = mulu(i.dim, sz, overflow); 321 if (overflow || max >= amax) 322 { 323 error(i.loc, "array dimension %llu exceeds max of %llu", ulong(i.dim), ulong(amax / sz)); 324 return err(); 325 } 326 //printf("returns ai: %s\n", i.toChars()); 327 return i; 328 } 329 330 Initializer visitExp(ExpInitializer i) 331 { 332 //printf("ExpInitializer::semantic(%s), type = %s\n", i.exp.toChars(), t.toChars()); 333 if (needInterpret) 334 sc = sc.startCTFE(); 335 i.exp = i.exp.expressionSemantic(sc); 336 i.exp = resolveProperties(sc, i.exp); 337 if (needInterpret) 338 sc = sc.endCTFE(); 339 if (i.exp.op == EXP.error) 340 return err(); 341 uint olderrors = global.errors; 342 343 /* ImportC: convert arrays to pointers, functions to pointers to functions 344 */ 345 Type tb = t.toBasetype(); 346 if (tb.isTypePointer()) 347 i.exp = i.exp.arrayFuncConv(sc); 348 349 /* Save the expression before ctfe 350 * Otherwise the error message would contain for example "&[0][0]" instead of "new int" 351 * Regression: https://issues.dlang.org/show_bug.cgi?id=21687 352 */ 353 Expression currExp = i.exp; 354 if (needInterpret) 355 { 356 // If the result will be implicitly cast, move the cast into CTFE 357 // to avoid premature truncation of polysemous types. 358 // eg real [] x = [1.1, 2.2]; should use real precision. 359 if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile)) 360 { 361 i.exp = i.exp.implicitCastTo(sc, t); 362 } 363 if (!global.gag && olderrors != global.errors) 364 { 365 return i; 366 } 367 if (sc.flags & SCOPE.Cfile) 368 { 369 /* the interpreter turns (char*)"string" into &"string"[0] which then 370 * it cannot interpret. Resolve that case by doing optimize() first 371 */ 372 i.exp = i.exp.optimize(WANTvalue); 373 if (i.exp.isSymOffExp()) 374 { 375 /* `static variable cannot be read at compile time` 376 * https://issues.dlang.org/show_bug.cgi?id=22513 377 * Maybe this would be better addressed in ctfeInterpret()? 378 */ 379 needInterpret = NeedInterpret.INITnointerpret; 380 } 381 } 382 if (needInterpret) 383 i.exp = i.exp.ctfeInterpret(); 384 if (i.exp.op == EXP.voidExpression) 385 error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead."); 386 } 387 else 388 { 389 i.exp = i.exp.optimize(WANTvalue); 390 } 391 392 if (!global.gag && olderrors != global.errors) 393 { 394 return i; // Failed, suppress duplicate error messages 395 } 396 if (i.exp.type.isTypeTuple() && i.exp.type.isTypeTuple().arguments.length == 0) 397 { 398 Type et = i.exp.type; 399 i.exp = new TupleExp(i.exp.loc, new Expressions()); 400 i.exp.type = et; 401 } 402 if (i.exp.op == EXP.type) 403 { 404 error(i.exp.loc, "initializer must be an expression, not `%s`", i.exp.toChars()); 405 return err(); 406 } 407 // Make sure all pointers are constants 408 if (needInterpret && hasNonConstPointers(i.exp)) 409 { 410 error(i.exp.loc, "cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars()); 411 return err(); 412 } 413 Type ti = i.exp.type.toBasetype(); 414 if (i.exp.op == EXP.tuple && i.expandTuples && !i.exp.implicitConvTo(t)) 415 { 416 return new ExpInitializer(i.loc, i.exp); 417 } 418 /* Look for case of initializing a static array with a too-short 419 * string literal, such as: 420 * char[5] foo = "abc"; 421 * Allow this by doing an explicit cast, which will lengthen the string 422 * literal. 423 */ 424 if (i.exp.op == EXP.string_ && tb.ty == Tsarray) 425 { 426 StringExp se = i.exp.isStringExp(); 427 Type typeb = se.type.toBasetype(); 428 TY tynto = tb.nextOf().ty; 429 if (!se.committed && 430 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && 431 se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger()) 432 { 433 i.exp = se.castTo(sc, t); 434 goto L1; 435 } 436 437 /* Lop off terminating 0 of initializer for: 438 * static char s[5] = "hello"; 439 */ 440 if (sc.flags & SCOPE.Cfile && 441 typeb.ty == Tsarray && 442 tynto.isSomeChar && 443 tb.isTypeSArray().dim.toInteger() + 1 == typeb.isTypeSArray().dim.toInteger()) 444 { 445 i.exp = se.castTo(sc, t); 446 goto L1; 447 } 448 } 449 /* C11 6.7.9-14..15 450 * Initialize an array of unknown size with a string. 451 * Change to static array of known size 452 */ 453 if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() && 454 tb.isTypeSArray() && tb.isTypeSArray().isIncomplete()) 455 { 456 StringExp se = i.exp.isStringExp(); 457 auto ts = new TypeSArray(tb.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t)); 458 t = typeSemantic(ts, Loc.initial, sc); 459 i.exp.type = t; 460 tx = t; 461 } 462 463 // Look for implicit constructor call 464 if (tb.ty == Tstruct && !(ti.ty == Tstruct && tb.toDsymbol(sc) == ti.toDsymbol(sc)) && !i.exp.implicitConvTo(t)) 465 { 466 StructDeclaration sd = tb.isTypeStruct().sym; 467 if (sd.ctor) 468 { 469 // Rewrite as S().ctor(exp) 470 Expression e; 471 e = new StructLiteralExp(i.loc, sd, null); 472 e = new DotIdExp(i.loc, e, Id.ctor); 473 e = new CallExp(i.loc, e, i.exp); 474 e = e.expressionSemantic(sc); 475 if (needInterpret) 476 i.exp = e.ctfeInterpret(); 477 else 478 i.exp = e.optimize(WANTvalue); 479 } 480 else if (search_function(sd, Id.call)) 481 { 482 /* https://issues.dlang.org/show_bug.cgi?id=1547 483 * 484 * Look for static opCall 485 * 486 * Rewrite as: 487 * i.exp = typeof(sd).opCall(arguments) 488 */ 489 490 Expression e = typeDotIdExp(i.loc, sd.type, Id.call); 491 e = new CallExp(i.loc, e, i.exp); 492 e = e.expressionSemantic(sc); 493 e = resolveProperties(sc, e); 494 if (needInterpret) 495 i.exp = e.ctfeInterpret(); 496 else 497 i.exp = e.optimize(WANTvalue); 498 } 499 } 500 501 // Look for the case of statically initializing an array with a single member. 502 // Recursively strip static array / enum layers until a compatible element is found, 503 // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found 504 // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]] 505 // int[2] = new Object => null 506 Expression sarrayRepeat(Type tb) 507 { 508 auto tsa = tb.isTypeSArray(); 509 if (!tsa) 510 return null; 511 512 // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars()); 513 Expression elem = null; 514 if (i.exp.implicitConvTo(tb.nextOf())) 515 elem = i.exp.implicitCastTo(sc, tb.nextOf()); 516 else if (auto ae = sarrayRepeat(tb.nextOf().toBasetype())) 517 elem = ae; 518 else 519 return null; 520 521 auto arrayElements = new Expressions(cast(size_t) tsa.dim.toInteger()); 522 foreach (ref e; *arrayElements) 523 e = elem; 524 return new ArrayLiteralExp(i.exp.loc, tb, elem, arrayElements); 525 } 526 527 if (auto sa = sarrayRepeat(tb)) 528 { 529 // printf("sa = %s\n", sa.toChars()); 530 i.exp = sa; 531 } 532 533 { 534 auto tta = t.isTypeSArray(); 535 if (i.exp.implicitConvTo(t)) 536 { 537 i.exp = i.exp.implicitCastTo(sc, t); 538 } 539 else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() && 540 tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) && 541 ti.ty == Tsarray && ti.nextOf().ty == Tchar) 542 { 543 /* unsigned char bbb[1] = ""; 544 * signed char ccc[1] = ""; 545 */ 546 i.exp = i.exp.castTo(sc, t); 547 } 548 else 549 { 550 auto tba = tb.isTypeSArray(); 551 // Look for mismatch of compile-time known length to emit 552 // better diagnostic message, as same as AssignExp::semantic. 553 if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch) 554 { 555 uinteger_t dim1 = tba.dim.toInteger(); 556 uinteger_t dim2 = dim1; 557 if (auto ale = i.exp.isArrayLiteralExp()) 558 { 559 dim2 = ale.elements ? ale.elements.length : 0; 560 } 561 else if (auto se = i.exp.isSliceExp()) 562 { 563 if (Type tx = toStaticArrayType(se)) 564 dim2 = tx.isTypeSArray().dim.toInteger(); 565 } 566 if (dim1 != dim2) 567 { 568 error(i.exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 569 i.exp = ErrorExp.get(); 570 } 571 } 572 Type et = i.exp.type; 573 const errors = global.startGagging(); 574 i.exp = i.exp.implicitCastTo(sc, t); 575 if (global.endGagging(errors)) 576 error(currExp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars()); 577 } 578 } 579 L1: 580 if (i.exp.op == EXP.error) 581 { 582 return i; 583 } 584 if (needInterpret) 585 i.exp = i.exp.ctfeInterpret(); 586 else 587 i.exp = i.exp.optimize(WANTvalue); 588 //printf("-ExpInitializer::semantic(): "); i.exp.print(); 589 return i; 590 } 591 592 Initializer visitC(CInitializer ci) 593 { 594 //printf("CInitializer::semantic() tx: %s t: %s ci: %s\n", (tx ? tx.toChars() : "".ptr), t.toChars(), ci.toChars()); 595 /* Rewrite CInitializer into ExpInitializer, ArrayInitializer, or StructInitializer 596 */ 597 t = t.toBasetype(); 598 599 if (auto tv = t.isTypeVector()) 600 t = tv.basetype; 601 602 /* If `{ expression }` return the expression initializer 603 */ 604 ExpInitializer isBraceExpression() 605 { 606 auto dil = ci.initializerList[]; 607 return (dil.length == 1 && !dil[0].designatorList) 608 ? dil[0].initializer.isExpInitializer() 609 : null; 610 } 611 612 /******************************** 613 */ 614 bool overlaps(VarDeclaration field, VarDeclaration[] fields, StructInitializer si) 615 { 616 foreach (fld; fields) 617 { 618 if (field.isOverlappedWith(fld)) 619 { 620 // look for initializer corresponding with fld 621 foreach (i, ident; si.field[]) 622 { 623 if (ident == fld.ident && si.value[i]) 624 return true; // already an initializer for `field` 625 } 626 } 627 } 628 return false; 629 } 630 631 /* Run semantic on ExpInitializer, see if it represents entire struct ts 632 */ 633 bool representsStruct(ExpInitializer ei, TypeStruct ts) 634 { 635 if (needInterpret) 636 sc = sc.startCTFE(); 637 ei.exp = ei.exp.expressionSemantic(sc); 638 ei.exp = resolveProperties(sc, ei.exp); 639 if (needInterpret) 640 sc = sc.endCTFE(); 641 return ei.exp.implicitConvTo(ts) != MATCH.nomatch; // initializer represents the entire struct 642 } 643 644 /* If { } are omitted from substructs, use recursion to reconstruct where 645 * brackets go 646 * Params: 647 * ts = substruct to initialize 648 * index = index into ci.initializer, updated 649 * Returns: struct initializer for this substruct 650 */ 651 Initializer subStruct()(TypeStruct ts, ref size_t index) 652 { 653 //printf("subStruct(ts: %s, index %d)\n", ts.toChars(), cast(int)index); 654 655 auto si = new StructInitializer(ci.loc); 656 StructDeclaration sd = ts.sym; 657 sd.size(ci.loc); 658 if (sd.sizeok != Sizeok.done) 659 { 660 index = ci.initializerList.length; 661 return err(); 662 } 663 const nfields = sd.fields.length; 664 665 foreach (fieldi; 0 .. nfields) 666 { 667 if (index >= ci.initializerList.length) 668 break; // ran out of initializers 669 auto di = ci.initializerList[index]; 670 if (di.designatorList && fieldi != 0) 671 break; // back to top level 672 else 673 { 674 VarDeclaration field; 675 while (1) // skip field if it overlaps with previously seen fields 676 { 677 field = sd.fields[fieldi]; 678 ++fieldi; 679 if (!overlaps(field, sd.fields[], si)) 680 break; 681 if (fieldi == nfields) 682 break; 683 } 684 auto tn = field.type.toBasetype(); 685 auto tnsa = tn.isTypeSArray(); 686 auto tns = tn.isTypeStruct(); 687 auto ix = di.initializer; 688 if (tnsa && ix.isExpInitializer()) 689 { 690 ExpInitializer ei = ix.isExpInitializer(); 691 if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) 692 { 693 si.addInit(field.ident, ei); 694 ++index; 695 } 696 else 697 si.addInit(field.ident, subArray(tnsa, index)); // fwd ref of subArray is why subStruct is a template 698 } 699 else if (tns && ix.isExpInitializer()) 700 { 701 /* Disambiguate between an exp representing the entire 702 * struct, and an exp representing the first field of the struct 703 */ 704 if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct 705 { 706 si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret)); 707 ++index; 708 } 709 else // field initializers for struct 710 si.addInit(field.ident, subStruct(tns, index)); // the first field 711 } 712 else 713 { 714 si.addInit(field.ident, ix); 715 ++index; 716 } 717 } 718 } 719 //printf("subStruct() returns ai: %s, index: %d\n", si.toChars(), cast(int)index); 720 return si; 721 } 722 723 /* If { } are omitted from subarrays, use recursion to reconstruct where 724 * brackets go 725 * Params: 726 * tsa = subarray to initialize 727 * index = index into ci.initializer, updated 728 * Returns: array initializer for this subarray 729 */ 730 Initializer subArray(TypeSArray tsa, ref size_t index) 731 { 732 //printf("array(tsa: %s, index %d)\n", tsa.toChars(), cast(int)index); 733 if (tsa.isIncomplete()) 734 { 735 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified" 736 assert(0); // should have been detected by parser 737 } 738 739 auto tnsa = tsa.nextOf().toBasetype().isTypeSArray(); 740 741 auto ai = new ArrayInitializer(ci.loc); 742 ai.isCarray = true; 743 744 foreach (n; 0 .. cast(size_t)tsa.dim.toInteger()) 745 { 746 if (index >= ci.initializerList.length) 747 break; // ran out of initializers 748 auto di = ci.initializerList[index]; 749 if (di.designatorList) 750 break; // back to top level 751 else if (tnsa && di.initializer.isExpInitializer()) 752 { 753 ExpInitializer ei = di.initializer.isExpInitializer(); 754 if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) 755 { 756 ai.addInit(null, ei); 757 ++index; 758 } 759 else 760 ai.addInit(null, subArray(tnsa, index)); 761 } 762 else 763 { 764 ai.addInit(null, di.initializer); 765 ++index; 766 } 767 } 768 //printf("array() returns ai: %s, index: %d\n", ai.toChars(), cast(int)index); 769 return ai; 770 } 771 772 if (auto ts = t.isTypeStruct()) 773 { 774 auto si = new StructInitializer(ci.loc); 775 StructDeclaration sd = ts.sym; 776 sd.size(ci.loc); // run semantic() on sd to get fields 777 if (sd.sizeok != Sizeok.done) 778 { 779 return err(); 780 } 781 const nfields = sd.fields.length; 782 size_t fieldi = 0; 783 784 Loop1: 785 for (size_t index = 0; index < ci.initializerList.length; ) 786 { 787 CInitializer cprev; 788 L1: 789 DesigInit di = ci.initializerList[index]; 790 Designators* dlist = di.designatorList; 791 if (dlist) 792 { 793 const length = (*dlist).length; 794 if (length == 0 || !(*dlist)[0].ident) 795 { 796 error(ci.loc, "`.identifier` expected for C struct field initializer `%s`", toChars(ci)); 797 return err(); 798 } 799 if (length > 1) 800 { 801 error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci)); 802 return err(); 803 } 804 auto id = (*dlist)[0].ident; 805 foreach (k, f; sd.fields[]) // linear search for now 806 { 807 if (f.ident == id) 808 { 809 fieldi = k; 810 si.addInit(id, di.initializer); 811 ++fieldi; 812 ++index; 813 continue Loop1; 814 } 815 } 816 if (cprev) 817 { 818 /* The peeling didn't work, so unpeel it 819 */ 820 ci = cprev; 821 di = ci.initializerList[index]; 822 goto L2; 823 } 824 error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars()); 825 return err(); 826 } 827 else 828 { 829 if (fieldi == nfields) 830 break; 831 if (index == 0 && ci.initializerList.length == 1 && di.initializer.isCInitializer()) 832 { 833 /* Try peeling off this set of { } and see if it works 834 */ 835 cprev = ci; 836 ci = di.initializer.isCInitializer(); 837 goto L1; 838 } 839 840 L2: 841 VarDeclaration field; 842 while (1) // skip field if it overlaps with previously seen fields 843 { 844 field = sd.fields[fieldi]; 845 ++fieldi; 846 if (!overlaps(field, sd.fields[], si)) 847 break; 848 if (fieldi == nfields) 849 break; 850 } 851 auto tn = field.type.toBasetype(); 852 auto tnsa = tn.isTypeSArray(); 853 auto tns = tn.isTypeStruct(); 854 auto ix = di.initializer; 855 if (tnsa && ix.isExpInitializer()) 856 { 857 ExpInitializer ei = ix.isExpInitializer(); 858 if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) 859 { 860 si.addInit(field.ident, ei); 861 ++index; 862 } 863 else 864 si.addInit(field.ident, subArray(tnsa, index)); 865 } 866 else if (tns && ix.isExpInitializer()) 867 { 868 /* Disambiguate between an exp representing the entire 869 * struct, and an exp representing the first field of the struct 870 */ 871 if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct 872 { 873 si.addInit(field.ident, initializerSemantic(ix, sc, tn, needInterpret)); 874 ++index; 875 } 876 else // field initializers for struct 877 si.addInit(field.ident, subStruct(tns, index)); // the first field 878 } 879 else 880 { 881 si.addInit(field.ident, di.initializer); 882 ++index; 883 } 884 } 885 } 886 return initializerSemantic(si, sc, t, needInterpret); 887 } 888 else if (auto ta = t.isTypeSArray()) 889 { 890 auto tn = t.nextOf().toBasetype(); // element type of array 891 892 /* If it's an array of integral being initialized by `{ string }` 893 * replace with `string` 894 */ 895 if (tn.isintegral()) 896 { 897 if (ExpInitializer ei = isBraceExpression()) 898 { 899 if (ei.exp.isStringExp()) 900 return ei.initializerSemantic(sc, t, needInterpret); 901 } 902 } 903 904 auto tnsa = tn.isTypeSArray(); // array of array 905 auto tns = tn.isTypeStruct(); // array of struct 906 907 auto ai = new ArrayInitializer(ci.loc); 908 ai.isCarray = true; 909 for (size_t index = 0; index < ci.initializerList.length; ) 910 { 911 auto di = ci.initializerList[index]; 912 if (auto dlist = di.designatorList) 913 { 914 const length = (*dlist).length; 915 if (length == 0 || !(*dlist)[0].exp) 916 { 917 error(ci.loc, "`[ constant-expression ]` expected for C array element initializer `%s`", toChars(ci)); 918 return err(); 919 } 920 if (length > 1) 921 { 922 error(ci.loc, "only 1 designator currently allowed for C array element initializer `%s`", toChars(ci)); 923 return err(); 924 } 925 //printf("tn: %s, di.initializer: %s\n", tn.toChars(), di.initializer.toChars()); 926 auto ix = di.initializer; 927 if (tnsa && ix.isExpInitializer()) 928 { 929 // Wrap initializer in [ ] 930 auto ain = new ArrayInitializer(ci.loc); 931 ain.addInit(null, di.initializer); 932 ix = ain; 933 ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); 934 ++index; 935 } 936 else if (tns && ix.isExpInitializer()) 937 { 938 /* Disambiguate between an exp representing the entire 939 * struct, and an exp representing the first field of the struct 940 */ 941 if (representsStruct(ix.isExpInitializer(), tns)) // initializer represents the entire struct 942 { 943 ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); 944 ++index; 945 } 946 else // field initializers for struct 947 ai.addInit((*dlist)[0].exp, subStruct(tns, index)); // the first field 948 } 949 else 950 { 951 ai.addInit((*dlist)[0].exp, initializerSemantic(ix, sc, tn, needInterpret)); 952 ++index; 953 } 954 } 955 else if (tnsa && di.initializer.isExpInitializer()) 956 { 957 ExpInitializer ei = di.initializer.isExpInitializer(); 958 if (ei.exp.isStringExp() && tnsa.nextOf().isintegral()) 959 { 960 ai.addInit(null, ei); 961 ++index; 962 } 963 else 964 ai.addInit(null, subArray(tnsa, index)); 965 } 966 else if (tns && di.initializer.isExpInitializer()) 967 { 968 /* Disambiguate between an exp representing the entire 969 * struct, and an exp representing the first field of the struct 970 */ 971 if (representsStruct(di.initializer.isExpInitializer(), tns)) // initializer represents the entire struct 972 { 973 ai.addInit(null, initializerSemantic(di.initializer, sc, tn, needInterpret)); 974 ++index; 975 } 976 else // field initializers for struct 977 ai.addInit(null, subStruct(tns, index)); // the first field 978 } 979 else 980 { 981 ai.addInit(null, initializerSemantic(di.initializer, sc, tn, needInterpret)); 982 ++index; 983 } 984 } 985 return initializerSemantic(ai, sc, tx, needInterpret); 986 } 987 else if (ExpInitializer ei = isBraceExpression()) 988 { 989 return visitExp(ei); 990 } 991 else 992 { 993 error(ci.loc, "unrecognized C initializer `%s`", toChars(ci)); 994 return err(); 995 } 996 } 997 998 mixin VisitInitializer!Initializer visit; 999 auto result = visit.VisitInitializer(init); 1000 return (result !is null) ? result : new ErrorInitializer(); 1001 } 1002 1003 /*********************** 1004 * Translate init to an `Expression` in order to infer the type. 1005 * Params: 1006 * init = `Initializer` AST node 1007 * sc = context 1008 * Returns: 1009 * an equivalent `ExpInitializer` if successful, or `ErrorInitializer` if it cannot be translated 1010 */ 1011 Initializer inferType(Initializer init, Scope* sc) 1012 { 1013 Initializer visitVoid(VoidInitializer i) 1014 { 1015 error(i.loc, "cannot infer type from void initializer"); 1016 return new ErrorInitializer(); 1017 } 1018 1019 Initializer visitError(ErrorInitializer i) 1020 { 1021 return i; 1022 } 1023 1024 Initializer visitStruct(StructInitializer i) 1025 { 1026 error(i.loc, "cannot infer type from struct initializer"); 1027 return new ErrorInitializer(); 1028 } 1029 1030 Initializer visitArray(ArrayInitializer init) 1031 { 1032 //printf("ArrayInitializer::inferType() %s\n", toChars()); 1033 Expressions* keys = null; 1034 Expressions* values; 1035 if (init.isAssociativeArray()) 1036 { 1037 keys = new Expressions(init.value.length); 1038 values = new Expressions(init.value.length); 1039 for (size_t i = 0; i < init.value.length; i++) 1040 { 1041 Expression e = init.index[i]; 1042 if (!e) 1043 goto Lno; 1044 (*keys)[i] = e; 1045 Initializer iz = init.value[i]; 1046 if (!iz) 1047 goto Lno; 1048 iz = iz.inferType(sc); 1049 if (iz.isErrorInitializer()) 1050 { 1051 return iz; 1052 } 1053 (*values)[i] = iz.isExpInitializer().exp; 1054 assert(!(*values)[i].isErrorExp()); 1055 } 1056 Expression e = new AssocArrayLiteralExp(init.loc, keys, values); 1057 auto ei = new ExpInitializer(init.loc, e); 1058 return ei.inferType(sc); 1059 } 1060 else 1061 { 1062 auto elements = new Expressions(init.value.length); 1063 elements.zero(); 1064 for (size_t i = 0; i < init.value.length; i++) 1065 { 1066 assert(!init.index[i]); // already asserted by isAssociativeArray() 1067 Initializer iz = init.value[i]; 1068 if (!iz) 1069 goto Lno; 1070 iz = iz.inferType(sc); 1071 if (iz.isErrorInitializer()) 1072 { 1073 return iz; 1074 } 1075 (*elements)[i] = iz.isExpInitializer().exp; 1076 assert(!(*elements)[i].isErrorExp()); 1077 } 1078 Expression e = new ArrayLiteralExp(init.loc, null, elements); 1079 auto ei = new ExpInitializer(init.loc, e); 1080 return ei.inferType(sc); 1081 } 1082 Lno: 1083 if (keys) 1084 { 1085 error(init.loc, "not an associative array initializer"); 1086 } 1087 else 1088 { 1089 error(init.loc, "cannot infer type from array initializer"); 1090 } 1091 return new ErrorInitializer(); 1092 } 1093 1094 Initializer visitExp(ExpInitializer init) 1095 { 1096 //printf("ExpInitializer::inferType() %s\n", init.toChars()); 1097 init.exp = init.exp.expressionSemantic(sc); 1098 1099 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 1100 if (init.exp.op == EXP.type) 1101 init.exp = resolveAliasThis(sc, init.exp); 1102 1103 init.exp = resolveProperties(sc, init.exp); 1104 if (auto se = init.exp.isScopeExp()) 1105 { 1106 TemplateInstance ti = se.sds.isTemplateInstance(); 1107 if (ti && ti.semanticRun == PASS.semantic && !ti.aliasdecl) 1108 error(se.loc, "cannot infer type from %s `%s`, possible circular dependency", se.sds.kind(), se.toChars()); 1109 else 1110 error(se.loc, "cannot infer type from %s `%s`", se.sds.kind(), se.toChars()); 1111 return new ErrorInitializer(); 1112 } 1113 1114 // Give error for overloaded function addresses 1115 bool hasOverloads; 1116 if (auto f = isFuncAddress(init.exp, &hasOverloads)) 1117 { 1118 if (f.checkForwardRef(init.loc)) 1119 { 1120 return new ErrorInitializer(); 1121 } 1122 if (hasOverloads && !f.isUnique()) 1123 { 1124 error(init.exp.loc, "cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); 1125 return new ErrorInitializer(); 1126 } 1127 } 1128 if (auto ae = init.exp.isAddrExp()) 1129 { 1130 if (ae.e1.op == EXP.overloadSet) 1131 { 1132 error(init.exp.loc, "cannot infer type from overloaded function symbol `%s`", init.exp.toChars()); 1133 return new ErrorInitializer(); 1134 } 1135 } 1136 if (init.exp.isErrorExp()) 1137 { 1138 return new ErrorInitializer(); 1139 } 1140 if (!init.exp.type) 1141 { 1142 return new ErrorInitializer(); 1143 } 1144 return init; 1145 } 1146 1147 Initializer visitC(CInitializer i) 1148 { 1149 //printf("CInitializer.inferType()\n"); 1150 error(i.loc, "TODO C inferType initializers not supported yet"); 1151 return new ErrorInitializer(); 1152 } 1153 1154 mixin VisitInitializer!Initializer visit; 1155 auto result = visit.VisitInitializer(init); 1156 return (result !is null) ? result : new ErrorInitializer(); 1157 } 1158 1159 /*********************** 1160 * Translate init to an `Expression`. 1161 * Params: 1162 * init = `Initializer` AST node 1163 * itype = if not `null`, type to coerce expression to 1164 * isCfile = default initializers are different with C 1165 * Returns: 1166 * `Expression` created, `null` if cannot, `ErrorExp` for other errors 1167 */ 1168 extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false) 1169 { 1170 //printf("initializerToExpression() isCfile: %d\n", isCfile); 1171 1172 Expression visitVoid(VoidInitializer) 1173 { 1174 return null; 1175 } 1176 1177 Expression visitError(ErrorInitializer) 1178 { 1179 return ErrorExp.get(); 1180 } 1181 1182 /*************************************** 1183 * This works by transforming a struct initializer into 1184 * a struct literal. In the future, the two should be the 1185 * same thing. 1186 */ 1187 Expression visitStruct(StructInitializer) 1188 { 1189 // cannot convert to an expression without target 'ad' 1190 return null; 1191 } 1192 1193 /******************************** 1194 * If possible, convert array initializer to array literal. 1195 * Otherwise return NULL. 1196 */ 1197 Expression visitArray(ArrayInitializer init) 1198 { 1199 //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); 1200 //static int i; if (++i == 2) assert(0); 1201 uint edim; // the length of the resulting array literal 1202 const(uint) amax = 0x80000000; 1203 Type t = null; // type of the array literal being initialized 1204 if (init.type) 1205 { 1206 if (init.type == Type.terror) 1207 { 1208 return ErrorExp.get(); 1209 } 1210 t = init.type.toBasetype(); 1211 switch (t.ty) 1212 { 1213 case Tvector: 1214 t = t.isTypeVector().basetype; 1215 goto case Tsarray; 1216 1217 case Tsarray: 1218 uinteger_t adim = t.isTypeSArray().dim.toInteger(); 1219 if (adim >= amax) 1220 return null; 1221 edim = cast(uint)adim; 1222 break; 1223 1224 case Tpointer: 1225 case Tarray: 1226 edim = init.dim; 1227 break; 1228 1229 default: 1230 assert(0); 1231 } 1232 } 1233 else 1234 { 1235 /* Calculate the length of the array literal 1236 */ 1237 edim = cast(uint)init.value.length; 1238 size_t j = 0; 1239 foreach (i; 0 .. init.value.length) 1240 { 1241 if (auto e = init.index[i]) 1242 { 1243 if (e.op == EXP.int64) 1244 { 1245 const uinteger_t idxval = e.toInteger(); 1246 if (idxval >= amax) 1247 return null; 1248 j = cast(size_t)idxval; 1249 } 1250 else 1251 return null; 1252 } 1253 ++j; 1254 if (j > edim) 1255 edim = cast(uint)j; 1256 } 1257 } 1258 1259 auto elements = new Expressions(edim); 1260 elements.zero(); 1261 size_t j = 0; 1262 foreach (i; 0 .. init.value.length) 1263 { 1264 if (auto e = init.index[i]) 1265 j = cast(size_t)e.toInteger(); 1266 assert(j < edim); 1267 if (Initializer iz = init.value[i]) 1268 { 1269 if (Expression ex = iz.initializerToExpression(null, isCfile)) 1270 { 1271 (*elements)[j] = ex; 1272 ++j; 1273 } 1274 else 1275 return null; 1276 } 1277 else 1278 return null; 1279 } 1280 1281 /* Fill in any missing elements with the default initializer 1282 */ 1283 Expression defaultInit = null; // lazily create it 1284 foreach (ref element; (*elements)[0 .. edim]) 1285 { 1286 if (!element) 1287 { 1288 if (!init.type) // don't know what type to use 1289 return null; 1290 if (!defaultInit) 1291 defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile); 1292 element = defaultInit; 1293 } 1294 } 1295 1296 /* Expand any static array initializers that are a single expression 1297 * into an array of them 1298 * e => [e, e, ..., e, e] 1299 */ 1300 if (t) 1301 { 1302 Type tn = t.nextOf().toBasetype(); 1303 if (tn.ty == Tsarray) 1304 { 1305 const dim = cast(size_t)(cast(TypeSArray)tn).dim.toInteger(); 1306 Type te = tn.nextOf().toBasetype(); 1307 foreach (ref e; *elements) 1308 { 1309 if (te.equals(e.type)) 1310 { 1311 auto elements2 = new Expressions(dim); 1312 foreach (ref e2; *elements2) 1313 e2 = e; 1314 e = new ArrayLiteralExp(e.loc, tn, elements2); 1315 } 1316 } 1317 } 1318 } 1319 1320 /* If any elements are errors, then the whole thing is an error 1321 */ 1322 foreach (e; (*elements)[0 .. edim]) 1323 { 1324 if (e.op == EXP.error) 1325 { 1326 return e; 1327 } 1328 } 1329 1330 Expression e = new ArrayLiteralExp(init.loc, init.type, elements); 1331 return e; 1332 } 1333 1334 Expression visitExp(ExpInitializer i) 1335 { 1336 if (itype) 1337 { 1338 //printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars()); 1339 Type tb = itype.toBasetype(); 1340 Expression e = (i.exp.op == EXP.construct || i.exp.op == EXP.blit) ? (cast(AssignExp)i.exp).e2 : i.exp; 1341 if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf())) 1342 { 1343 TypeSArray tsa = cast(TypeSArray)tb; 1344 size_t d = cast(size_t)tsa.dim.toInteger(); 1345 auto elements = new Expressions(d); 1346 for (size_t j = 0; j < d; j++) 1347 (*elements)[j] = e; 1348 auto ae = new ArrayLiteralExp(e.loc, itype, elements); 1349 return ae; 1350 } 1351 } 1352 return i.exp; 1353 } 1354 1355 Expression visitC(CInitializer i) 1356 { 1357 //printf("CInitializer.initializerToExpression(null, true)\n"); 1358 return null; 1359 } 1360 1361 mixin VisitInitializer!Expression visit; 1362 return visit.VisitInitializer(init); 1363 } 1364 1365 1366 /************************************** 1367 * Determine if expression has non-constant pointers, or more precisely, 1368 * a pointer that CTFE cannot handle. 1369 * Params: 1370 * e = expression to check 1371 * Returns: 1372 * true if it has non-constant pointers 1373 */ 1374 private bool hasNonConstPointers(Expression e) 1375 { 1376 static bool checkArray(Expressions* elems) 1377 { 1378 foreach (e; *elems) 1379 { 1380 if (e && hasNonConstPointers(e)) 1381 return true; 1382 } 1383 return false; 1384 } 1385 1386 if (e.type.ty == Terror) 1387 return false; 1388 if (e.op == EXP.null_) 1389 return false; 1390 if (auto se = e.isStructLiteralExp()) 1391 { 1392 return checkArray(se.elements); 1393 } 1394 if (auto ae = e.isArrayLiteralExp()) 1395 { 1396 if (!ae.type.nextOf().hasPointers()) 1397 return false; 1398 return checkArray(ae.elements); 1399 } 1400 if (auto ae = e.isAssocArrayLiteralExp()) 1401 { 1402 if (ae.type.nextOf().hasPointers() && checkArray(ae.values)) 1403 return true; 1404 if (ae.type.isTypeAArray().index.hasPointers()) 1405 return checkArray(ae.keys); 1406 return false; 1407 } 1408 if (auto ae = e.isAddrExp()) 1409 { 1410 if (ae.type.nextOf().isImmutable() || ae.type.nextOf().isConst()) 1411 { 1412 return false; 1413 } 1414 if (auto se = ae.e1.isStructLiteralExp()) 1415 { 1416 if (!(se.stageflags & stageSearchPointers)) 1417 { 1418 const old = se.stageflags; 1419 se.stageflags |= stageSearchPointers; 1420 bool ret = checkArray(se.elements); 1421 se.stageflags = old; 1422 return ret; 1423 } 1424 else 1425 { 1426 return false; 1427 } 1428 } 1429 return true; 1430 } 1431 if (e.type.ty == Tpointer && !e.type.isPtrToFunction()) 1432 { 1433 if (e.op == EXP.symbolOffset) // address of a global is OK 1434 return false; 1435 if (e.op == EXP.int64) // cast(void *)int is OK 1436 return false; 1437 if (e.op == EXP.string_) // "abc".ptr is OK 1438 return false; 1439 return true; 1440 } 1441 return false; 1442 } 1443 1444 /** 1445 Given the names and values of a `StructInitializer` or `CallExp`, 1446 resolve it to a list of expressions to construct a `StructLiteralExp`. 1447 1448 Params: 1449 sd = struct 1450 t = type of struct (potentially including qualifiers such as `const` or `immutable`) 1451 sc = scope of the expression initializing the struct 1452 iloc = location of expression initializing the struct 1453 names = identifiers passed in argument list, `null` entries for positional arguments 1454 getExp = function that, given an index into `names` and destination type, returns the initializing expression 1455 getLoc = function that, given an index into `names`, returns a location for error messages 1456 1457 Returns: list of expressions ordered to the struct's fields, or `null` on error 1458 */ 1459 Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* sc, 1460 Loc iloc, Identifier[] names, scope Expression delegate(size_t i, Type fieldType) getExp, 1461 scope Loc delegate(size_t i) getLoc 1462 ) 1463 { 1464 //expandTuples for non-identity arguments? 1465 const nfields = sd.nonHiddenFields(); 1466 auto elements = new Expressions(nfields); 1467 auto elems = (*elements)[]; 1468 foreach (ref elem; elems) 1469 elem = null; 1470 1471 // Run semantic for explicitly given initializers 1472 // TODO: this part is slightly different from StructLiteralExp::semantic. 1473 bool errors = false; 1474 size_t fieldi = 0; 1475 foreach (j, id; names) 1476 { 1477 const argLoc = getLoc(j); 1478 if (id) 1479 { 1480 // Determine `fieldi` that `id` matches 1481 Dsymbol s = sd.search(iloc, id); 1482 if (!s) 1483 { 1484 s = sd.search_correct(id); 1485 if (s) 1486 error(argLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars()); 1487 else 1488 error(argLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); 1489 return null; 1490 } 1491 s.checkDeprecated(iloc, sc); 1492 s = s.toAlias(); 1493 1494 // Find out which field index `s` is 1495 for (fieldi = 0; 1; fieldi++) 1496 { 1497 if (fieldi >= nfields) 1498 { 1499 error(iloc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars()); 1500 return null; 1501 } 1502 if (s == sd.fields[fieldi]) 1503 break; 1504 } 1505 } 1506 if (nfields == 0) 1507 { 1508 error(argLoc, "initializer provided for struct `%s` with no fields", sd.toChars()); 1509 return null; 1510 } 1511 if (j >= nfields) 1512 { 1513 error(argLoc, "too many initializers for `%s` with %d field%s", sd.toChars(), 1514 cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr); 1515 return null; 1516 } 1517 1518 VarDeclaration vd = sd.fields[fieldi]; 1519 if (elems[fieldi]) 1520 { 1521 error(argLoc, "duplicate initializer for field `%s`", vd.toChars()); 1522 errors = true; 1523 elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors 1524 ++fieldi; 1525 continue; 1526 } 1527 1528 // Check for @safe violations 1529 if (vd.type.hasPointers) 1530 { 1531 if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize || 1532 (vd.offset & (target.ptrsize - 1)))) 1533 { 1534 if (sc.setUnsafe(false, argLoc, 1535 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd)) 1536 { 1537 errors = true; 1538 elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors 1539 ++fieldi; 1540 continue; 1541 } 1542 } 1543 } 1544 1545 // Check for overlapping initializations (can happen with unions) 1546 foreach (k, v2; sd.fields[0 .. nfields]) 1547 { 1548 if (vd.isOverlappedWith(v2) && elems[k]) 1549 { 1550 error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); 1551 enum errorMsg = "`struct` initializers that contain anonymous unions" ~ 1552 " must initialize only the first member of a `union`. All subsequent" ~ 1553 " non-overlapping fields are default initialized"; 1554 if (!sd.isUnionDeclaration()) 1555 .errorSupplemental(elems[k].loc, errorMsg); 1556 errors = true; 1557 continue; 1558 } 1559 } 1560 1561 assert(sc); 1562 1563 auto ex = getExp(j, vd.type); 1564 1565 if (ex.op == EXP.error) 1566 { 1567 errors = true; 1568 elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors 1569 ++fieldi; 1570 continue; 1571 } 1572 1573 elems[fieldi] = doCopyOrMove(sc, ex); 1574 ++fieldi; 1575 } 1576 if (errors) 1577 return null; 1578 1579 return elements; 1580 }