1 /** 2 * Handle introspection functionality of the `__traits()` construct. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits) 5 * 6 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d) 10 * Documentation: https://dlang.org/phobos/dmd_traits.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/traits.d 12 */ 13 14 module dmd.traits; 15 16 import core.stdc.stdio; 17 18 import dmd.aggregate; 19 import dmd.arraytypes; 20 import dmd.astcodegen; 21 import dmd.attrib; 22 import dmd.canthrow; 23 import dmd.dclass; 24 import dmd.declaration; 25 import dmd.denum; 26 import dmd.dimport; 27 import dmd.dmodule; 28 import dmd.dscope; 29 import dmd.dsymbol; 30 import dmd.dsymbolsem; 31 import dmd.dtemplate; 32 import dmd.errors; 33 import dmd.expression; 34 import dmd.expressionsem; 35 import dmd.func; 36 import dmd.globals; 37 import dmd.hdrgen; 38 import dmd.id; 39 import dmd.identifier; 40 import dmd.mtype; 41 import dmd.nogc; 42 import dmd.parse; 43 import dmd.root.array; 44 import dmd.root.speller; 45 import dmd.root.stringtable; 46 import dmd.target; 47 import dmd.tokens; 48 import dmd.typesem; 49 import dmd.visitor; 50 import dmd.root.rootobject; 51 import dmd.root.outbuffer; 52 import dmd.root.string; 53 54 enum LOGSEMANTIC = false; 55 56 /************************ TraitsExp ************************************/ 57 58 /************************************** 59 * Convert `Expression` or `Type` to corresponding `Dsymbol`, additionally 60 * stripping off expression contexts. 61 * 62 * Some symbol related `__traits` ignore arguments expression contexts. 63 * For example: 64 * ---- 65 * struct S { void f() {} } 66 * S s; 67 * pragma(msg, __traits(isNested, s.f)); 68 * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`. 69 * ---- 70 * 71 * This is used for that common `__traits` behavior. 72 * 73 * Input: 74 * oarg object to get the symbol for 75 * Returns: 76 * Dsymbol the corresponding symbol for oarg 77 */ 78 private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) 79 { 80 if (auto e = isExpression(oarg)) 81 { 82 if (e.op == TOK.dotVariable) 83 return (cast(DotVarExp)e).var; 84 if (e.op == TOK.dotTemplateDeclaration) 85 return (cast(DotTemplateExp)e).td; 86 } 87 return getDsymbol(oarg); 88 } 89 90 private const StringTable!bool traitsStringTable; 91 92 shared static this() 93 { 94 static immutable string[] names = 95 [ 96 "isAbstractClass", 97 "isArithmetic", 98 "isAssociativeArray", 99 "isDisabled", 100 "isDeprecated", 101 "isFuture", 102 "isFinalClass", 103 "isPOD", 104 "isNested", 105 "isFloating", 106 "isIntegral", 107 "isScalar", 108 "isStaticArray", 109 "isUnsigned", 110 "isVirtualFunction", 111 "isVirtualMethod", 112 "isAbstractFunction", 113 "isFinalFunction", 114 "isOverrideFunction", 115 "isStaticFunction", 116 "isModule", 117 "isPackage", 118 "isRef", 119 "isOut", 120 "isLazy", 121 "isReturnOnStack", 122 "hasMember", 123 "identifier", 124 "getProtection", 125 "getVisibility", 126 "parent", 127 "child", 128 "getLinkage", 129 "getMember", 130 "getOverloads", 131 "getVirtualFunctions", 132 "getVirtualMethods", 133 "classInstanceSize", 134 "allMembers", 135 "derivedMembers", 136 "isSame", 137 "compiles", 138 "getAliasThis", 139 "getAttributes", 140 "getFunctionAttributes", 141 "getFunctionVariadicStyle", 142 "getParameterStorageClasses", 143 "getUnitTests", 144 "getVirtualIndex", 145 "getPointerBitmap", 146 "isZeroInit", 147 "getTargetInfo", 148 "getLocation", 149 "hasPostblit", 150 "hasCopyConstructor", 151 "isCopyable", 152 ]; 153 154 StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable; 155 stringTable._init(names.length); 156 157 foreach (s; names) 158 { 159 auto sv = stringTable.insert(s, true); 160 assert(sv); 161 } 162 } 163 164 /** 165 * get an array of size_t values that indicate possible pointer words in memory 166 * if interpreted as the type given as argument 167 * Returns: the size of the type in bytes, d_uns64.max on error 168 */ 169 d_uns64 getTypePointerBitmap(Loc loc, Type t, Array!(d_uns64)* data) 170 { 171 d_uns64 sz; 172 if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration()) 173 sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc); 174 else 175 sz = t.size(loc); 176 if (sz == SIZE_INVALID) 177 return d_uns64.max; 178 179 const sz_size_t = Type.tsize_t.size(loc); 180 if (sz > sz.max - sz_size_t) 181 { 182 error(loc, "size overflow for type `%s`", t.toChars()); 183 return d_uns64.max; 184 } 185 186 d_uns64 bitsPerWord = sz_size_t * 8; 187 d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t; 188 d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; 189 190 data.setDim(cast(size_t)cntdata); 191 data.zero(); 192 193 extern (C++) final class PointerBitmapVisitor : Visitor 194 { 195 alias visit = Visitor.visit; 196 public: 197 extern (D) this(Array!(d_uns64)* _data, d_uns64 _sz_size_t) 198 { 199 this.data = _data; 200 this.sz_size_t = _sz_size_t; 201 } 202 203 void setpointer(d_uns64 off) 204 { 205 d_uns64 ptroff = off / sz_size_t; 206 (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); 207 } 208 209 override void visit(Type t) 210 { 211 Type tb = t.toBasetype(); 212 if (tb != t) 213 tb.accept(this); 214 } 215 216 override void visit(TypeError t) 217 { 218 visit(cast(Type)t); 219 } 220 221 override void visit(TypeNext t) 222 { 223 assert(0); 224 } 225 226 override void visit(TypeBasic t) 227 { 228 if (t.ty == Tvoid) 229 setpointer(offset); 230 } 231 232 override void visit(TypeVector t) 233 { 234 } 235 236 override void visit(TypeArray t) 237 { 238 assert(0); 239 } 240 241 override void visit(TypeSArray t) 242 { 243 d_uns64 arrayoff = offset; 244 d_uns64 nextsize = t.next.size(); 245 if (nextsize == SIZE_INVALID) 246 error = true; 247 d_uns64 dim = t.dim.toInteger(); 248 for (d_uns64 i = 0; i < dim; i++) 249 { 250 offset = arrayoff + i * nextsize; 251 t.next.accept(this); 252 } 253 offset = arrayoff; 254 } 255 256 override void visit(TypeDArray t) 257 { 258 setpointer(offset + sz_size_t); 259 } 260 261 // dynamic array is {length,ptr} 262 override void visit(TypeAArray t) 263 { 264 setpointer(offset); 265 } 266 267 override void visit(TypePointer t) 268 { 269 if (t.nextOf().ty != Tfunction) // don't mark function pointers 270 setpointer(offset); 271 } 272 273 override void visit(TypeReference t) 274 { 275 setpointer(offset); 276 } 277 278 override void visit(TypeClass t) 279 { 280 setpointer(offset); 281 } 282 283 override void visit(TypeFunction t) 284 { 285 } 286 287 override void visit(TypeDelegate t) 288 { 289 setpointer(offset); 290 } 291 292 // delegate is {context, function} 293 override void visit(TypeQualified t) 294 { 295 assert(0); 296 } 297 298 // assume resolved 299 override void visit(TypeIdentifier t) 300 { 301 assert(0); 302 } 303 304 override void visit(TypeInstance t) 305 { 306 assert(0); 307 } 308 309 override void visit(TypeTypeof t) 310 { 311 assert(0); 312 } 313 314 override void visit(TypeReturn t) 315 { 316 assert(0); 317 } 318 319 override void visit(TypeEnum t) 320 { 321 visit(cast(Type)t); 322 } 323 324 override void visit(TypeTuple t) 325 { 326 visit(cast(Type)t); 327 } 328 329 override void visit(TypeSlice t) 330 { 331 assert(0); 332 } 333 334 override void visit(TypeNull t) 335 { 336 // always a null pointer 337 } 338 339 override void visit(TypeStruct t) 340 { 341 d_uns64 structoff = offset; 342 foreach (v; t.sym.fields) 343 { 344 offset = structoff + v.offset; 345 if (v.type.ty == Tclass) 346 setpointer(offset); 347 else 348 v.type.accept(this); 349 } 350 offset = structoff; 351 } 352 353 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references 354 void visitClass(TypeClass t) 355 { 356 d_uns64 classoff = offset; 357 // skip vtable-ptr and monitor 358 if (t.sym.baseClass) 359 visitClass(cast(TypeClass)t.sym.baseClass.type); 360 foreach (v; t.sym.fields) 361 { 362 offset = classoff + v.offset; 363 v.type.accept(this); 364 } 365 offset = classoff; 366 } 367 368 Array!(d_uns64)* data; 369 d_uns64 offset; 370 d_uns64 sz_size_t; 371 bool error; 372 } 373 374 scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t); 375 if (t.ty == Tclass) 376 pbv.visitClass(cast(TypeClass)t); 377 else 378 t.accept(pbv); 379 return pbv.error ? d_uns64.max : sz; 380 } 381 382 /** 383 * get an array of size_t values that indicate possible pointer words in memory 384 * if interpreted as the type given as argument 385 * the first array element is the size of the type for independent interpretation 386 * of the array 387 * following elements bits represent one word (4/8 bytes depending on the target 388 * architecture). If set the corresponding memory might contain a pointer/reference. 389 * 390 * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] 391 */ 392 private Expression pointerBitmap(TraitsExp e) 393 { 394 if (!e.args || e.args.dim != 1) 395 { 396 error(e.loc, "a single type expected for trait pointerBitmap"); 397 return ErrorExp.get(); 398 } 399 400 Type t = getType((*e.args)[0]); 401 if (!t) 402 { 403 error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); 404 return ErrorExp.get(); 405 } 406 407 Array!(d_uns64) data; 408 d_uns64 sz = getTypePointerBitmap(e.loc, t, &data); 409 if (sz == d_uns64.max) 410 return ErrorExp.get(); 411 412 auto exps = new Expressions(data.dim + 1); 413 (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); 414 foreach (size_t i; 1 .. exps.dim) 415 (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t); 416 417 auto ale = new ArrayLiteralExp(e.loc, Type.tsize_t.sarrayOf(data.dim + 1), exps); 418 return ale; 419 } 420 421 Expression semanticTraits(TraitsExp e, Scope* sc) 422 { 423 static if (LOGSEMANTIC) 424 { 425 printf("TraitsExp::semantic() %s\n", e.toChars()); 426 } 427 428 if (e.ident != Id.compiles && 429 e.ident != Id.isSame && 430 e.ident != Id.identifier && 431 e.ident != Id.getProtection && e.ident != Id.getVisibility && 432 e.ident != Id.getAttributes) 433 { 434 // Pretend we're in a deprecated scope so that deprecation messages 435 // aren't triggered when checking if a symbol is deprecated 436 const save = sc.stc; 437 if (e.ident == Id.isDeprecated) 438 sc.stc |= STC.deprecated_; 439 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1)) 440 { 441 sc.stc = save; 442 return ErrorExp.get(); 443 } 444 sc.stc = save; 445 } 446 size_t dim = e.args ? e.args.dim : 0; 447 448 Expression dimError(int expected) 449 { 450 e.error("expected %d arguments for `%s` but had %d", expected, e.ident.toChars(), cast(int)dim); 451 return ErrorExp.get(); 452 } 453 454 static IntegerExp True() 455 { 456 return IntegerExp.createBool(true); 457 } 458 459 static IntegerExp False() 460 { 461 return IntegerExp.createBool(false); 462 } 463 464 /******** 465 * Gets the function type from a given AST node 466 * if the node is a function of some sort. 467 * Params: 468 * o = an AST node to check for a `TypeFunction` 469 * fdp = if `o` is a FuncDeclaration then fdp is set to that, otherwise `null` 470 * Returns: 471 * a type node if `o` is a declaration of 472 * a delegate, function, function-pointer or a variable of the former. 473 * Otherwise, `null`. 474 */ 475 static TypeFunction toTypeFunction(RootObject o, out FuncDeclaration fdp) 476 { 477 Type t; 478 if (auto s = getDsymbolWithoutExpCtx(o)) 479 { 480 if (auto fd = s.isFuncDeclaration()) 481 { 482 t = fd.type; 483 fdp = fd; 484 } 485 else if (auto vd = s.isVarDeclaration()) 486 t = vd.type; 487 else 488 t = isType(o); 489 } 490 else 491 t = isType(o); 492 493 if (t) 494 { 495 if (t.ty == Tfunction) 496 return cast(TypeFunction)t; 497 else if (t.ty == Tdelegate) 498 return cast(TypeFunction)t.nextOf(); 499 else if (t.ty == Tpointer && t.nextOf().ty == Tfunction) 500 return cast(TypeFunction)t.nextOf(); 501 } 502 503 return null; 504 } 505 506 IntegerExp isX(T)(bool delegate(T) fp) 507 { 508 if (!dim) 509 return False(); 510 foreach (o; *e.args) 511 { 512 static if (is(T == Type)) 513 auto y = getType(o); 514 515 static if (is(T : Dsymbol)) 516 { 517 auto s = getDsymbolWithoutExpCtx(o); 518 if (!s) 519 return False(); 520 } 521 static if (is(T == Dsymbol)) 522 alias y = s; 523 static if (is(T == Declaration)) 524 auto y = s.isDeclaration(); 525 static if (is(T == FuncDeclaration)) 526 auto y = s.isFuncDeclaration(); 527 static if (is(T == EnumMember)) 528 auto y = s.isEnumMember(); 529 530 if (!y || !fp(y)) 531 return False(); 532 } 533 return True(); 534 } 535 536 alias isTypeX = isX!Type; 537 alias isDsymX = isX!Dsymbol; 538 alias isDeclX = isX!Declaration; 539 alias isFuncX = isX!FuncDeclaration; 540 alias isEnumMemX = isX!EnumMember; 541 542 Expression isPkgX(bool function(Package) fp) 543 { 544 return isDsymX((Dsymbol sym) { 545 Package p = resolveIsPackage(sym); 546 return (p !is null) && fp(p); 547 }); 548 } 549 550 if (e.ident == Id.isArithmetic) 551 { 552 return isTypeX(t => t.isintegral() || t.isfloating()); 553 } 554 if (e.ident == Id.isFloating) 555 { 556 return isTypeX(t => t.isfloating()); 557 } 558 if (e.ident == Id.isIntegral) 559 { 560 return isTypeX(t => t.isintegral()); 561 } 562 if (e.ident == Id.isScalar) 563 { 564 return isTypeX(t => t.isscalar()); 565 } 566 if (e.ident == Id.isUnsigned) 567 { 568 return isTypeX(t => t.isunsigned()); 569 } 570 if (e.ident == Id.isAssociativeArray) 571 { 572 return isTypeX(t => t.toBasetype().ty == Taarray); 573 } 574 if (e.ident == Id.isDeprecated) 575 { 576 if (global.params.vcomplex) 577 { 578 if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true)) 579 return True(); 580 } 581 return isDsymX(t => t.isDeprecated()); 582 } 583 if (e.ident == Id.isFuture) 584 { 585 return isDeclX(t => t.isFuture()); 586 } 587 if (e.ident == Id.isStaticArray) 588 { 589 return isTypeX(t => t.toBasetype().ty == Tsarray); 590 } 591 if (e.ident == Id.isAbstractClass) 592 { 593 return isTypeX(t => t.toBasetype().ty == Tclass && 594 (cast(TypeClass)t.toBasetype()).sym.isAbstract()); 595 } 596 if (e.ident == Id.isFinalClass) 597 { 598 return isTypeX(t => t.toBasetype().ty == Tclass && 599 ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0); 600 } 601 if (e.ident == Id.isTemplate) 602 { 603 if (dim != 1) 604 return dimError(1); 605 606 return isDsymX((s) 607 { 608 if (!s.toAlias().isOverloadable()) 609 return false; 610 return overloadApply(s, 611 sm => sm.isTemplateDeclaration() !is null) != 0; 612 }); 613 } 614 if (e.ident == Id.isPOD) 615 { 616 if (dim != 1) 617 return dimError(1); 618 619 auto o = (*e.args)[0]; 620 auto t = isType(o); 621 if (!t) 622 { 623 e.error("type expected as second argument of __traits `%s` instead of `%s`", 624 e.ident.toChars(), o.toChars()); 625 return ErrorExp.get(); 626 } 627 628 Type tb = t.baseElemOf(); 629 if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) 630 { 631 return sd.isPOD() ? True() : False(); 632 } 633 return True(); 634 } 635 if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit) 636 { 637 if (dim != 1) 638 return dimError(1); 639 640 auto o = (*e.args)[0]; 641 auto t = isType(o); 642 if (!t) 643 { 644 e.error("type expected as second argument of __traits `%s` instead of `%s`", 645 e.ident.toChars(), o.toChars()); 646 return ErrorExp.get(); 647 } 648 649 Type tb = t.baseElemOf(); 650 if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) 651 { 652 return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False()) 653 : (sd.hasCopyCtor ? True() : False()); 654 } 655 return False(); 656 } 657 if (e.ident == Id.isCopyable) 658 { 659 if (dim != 1) 660 return dimError(1); 661 662 auto o = (*e.args)[0]; 663 auto t = isType(o); 664 if (!t) 665 { 666 e.error("type expected as second argument of __traits `%s` instead of `%s`", 667 e.ident.toChars(), o.toChars()); 668 return ErrorExp.get(); 669 } 670 671 t = t.toBasetype(); // get the base in case `t` is an `enum` 672 673 if (auto ts = t.isTypeStruct()) 674 { 675 ts.sym.dsymbolSemantic(sc); 676 } 677 678 return isCopyable(t) ? True() : False(); 679 } 680 681 if (e.ident == Id.isNested) 682 { 683 if (dim != 1) 684 return dimError(1); 685 686 auto o = (*e.args)[0]; 687 auto s = getDsymbolWithoutExpCtx(o); 688 if (!s) 689 { 690 } 691 else if (auto ad = s.isAggregateDeclaration()) 692 { 693 return ad.isNested() ? True() : False(); 694 } 695 else if (auto fd = s.isFuncDeclaration()) 696 { 697 return fd.isNested() ? True() : False(); 698 } 699 700 e.error("aggregate or function expected instead of `%s`", o.toChars()); 701 return ErrorExp.get(); 702 } 703 if (e.ident == Id.isDisabled) 704 { 705 if (dim != 1) 706 return dimError(1); 707 708 return isDeclX(f => f.isDisabled()); 709 } 710 if (e.ident == Id.isAbstractFunction) 711 { 712 if (dim != 1) 713 return dimError(1); 714 715 return isFuncX(f => f.isAbstract()); 716 } 717 if (e.ident == Id.isVirtualFunction) 718 { 719 if (dim != 1) 720 return dimError(1); 721 722 return isFuncX(f => f.isVirtual()); 723 } 724 if (e.ident == Id.isVirtualMethod) 725 { 726 if (dim != 1) 727 return dimError(1); 728 729 return isFuncX(f => f.isVirtualMethod()); 730 } 731 if (e.ident == Id.isFinalFunction) 732 { 733 if (dim != 1) 734 return dimError(1); 735 736 return isFuncX(f => f.isFinalFunc()); 737 } 738 if (e.ident == Id.isOverrideFunction) 739 { 740 if (dim != 1) 741 return dimError(1); 742 743 return isFuncX(f => f.isOverride()); 744 } 745 if (e.ident == Id.isStaticFunction) 746 { 747 if (dim != 1) 748 return dimError(1); 749 750 return isFuncX(f => !f.needThis() && !f.isNested()); 751 } 752 if (e.ident == Id.isModule) 753 { 754 if (dim != 1) 755 return dimError(1); 756 757 return isPkgX(p => p.isModule() || p.isPackageMod()); 758 } 759 if (e.ident == Id.isPackage) 760 { 761 if (dim != 1) 762 return dimError(1); 763 764 return isPkgX(p => p.isModule() is null); 765 } 766 if (e.ident == Id.isRef) 767 { 768 if (dim != 1) 769 return dimError(1); 770 771 return isDeclX(d => d.isRef()); 772 } 773 if (e.ident == Id.isOut) 774 { 775 if (dim != 1) 776 return dimError(1); 777 778 return isDeclX(d => d.isOut()); 779 } 780 if (e.ident == Id.isLazy) 781 { 782 if (dim != 1) 783 return dimError(1); 784 785 return isDeclX(d => (d.storage_class & STC.lazy_) != 0); 786 } 787 if (e.ident == Id.identifier) 788 { 789 // Get identifier for symbol as a string literal 790 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that 791 * a symbol should not be folded to a constant. 792 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier 793 */ 794 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 2)) 795 return ErrorExp.get(); 796 if (dim != 1) 797 return dimError(1); 798 799 auto o = (*e.args)[0]; 800 Identifier id; 801 if (auto po = isParameter(o)) 802 { 803 if (!po.ident) 804 { 805 e.error("argument `%s` has no identifier", po.type.toChars()); 806 return ErrorExp.get(); 807 } 808 id = po.ident; 809 } 810 else 811 { 812 Dsymbol s = getDsymbolWithoutExpCtx(o); 813 if (!s || !s.ident) 814 { 815 e.error("argument `%s` has no identifier", o.toChars()); 816 return ErrorExp.get(); 817 } 818 id = s.ident; 819 } 820 821 auto se = new StringExp(e.loc, id.toString()); 822 return se.expressionSemantic(sc); 823 } 824 if (e.ident == Id.getProtection || e.ident == Id.getVisibility) 825 { 826 if (dim != 1) 827 return dimError(1); 828 829 Scope* sc2 = sc.push(); 830 sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility; 831 bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1); 832 sc2.pop(); 833 if (!ok) 834 return ErrorExp.get(); 835 836 auto o = (*e.args)[0]; 837 auto s = getDsymbolWithoutExpCtx(o); 838 if (!s) 839 { 840 if (!isError(o)) 841 e.error("argument `%s` has no visibility", o.toChars()); 842 return ErrorExp.get(); 843 } 844 if (s.semanticRun == PASS.init) 845 s.dsymbolSemantic(null); 846 847 auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names) 848 assert(protName); 849 auto se = new StringExp(e.loc, protName); 850 return se.expressionSemantic(sc); 851 } 852 if (e.ident == Id.parent) 853 { 854 if (dim != 1) 855 return dimError(1); 856 857 auto o = (*e.args)[0]; 858 auto s = getDsymbolWithoutExpCtx(o); 859 if (s) 860 { 861 // https://issues.dlang.org/show_bug.cgi?id=12496 862 // Consider: 863 // class T1 864 // { 865 // class C(uint value) { } 866 // } 867 // __traits(parent, T1.C!2) 868 if (auto ad = s.isAggregateDeclaration()) // `s` is `C` 869 { 870 if (ad.isNested()) // `C` is nested 871 { 872 if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not 873 { 874 if (p.isTemplateInstance()) // `C!2` is a template instance 875 { 876 s = p; // `C!2`'s parent is `T1` 877 auto td = (cast(TemplateInstance)p).tempdecl; 878 if (td) 879 s = td; // get the declaration context just in case there's two contexts 880 } 881 } 882 } 883 } 884 885 if (auto fd = s.isFuncDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=8943 886 s = fd.toAliasFunc(); 887 if (!s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=8922 888 s = s.toParent(); 889 } 890 if (!s || s.isImport()) 891 { 892 e.error("argument `%s` has no parent", o.toChars()); 893 return ErrorExp.get(); 894 } 895 896 if (auto f = s.isFuncDeclaration()) 897 { 898 if (auto td = getFuncTemplateDecl(f)) 899 { 900 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 901 td = td.overroot; // then get the start 902 Expression ex = new TemplateExp(e.loc, td, f); 903 ex = ex.expressionSemantic(sc); 904 return ex; 905 } 906 if (auto fld = f.isFuncLiteralDeclaration()) 907 { 908 // Directly translate to VarExp instead of FuncExp 909 Expression ex = new VarExp(e.loc, fld, true); 910 return ex.expressionSemantic(sc); 911 } 912 } 913 return symbolToExp(s, e.loc, sc, false); 914 } 915 if (e.ident == Id.child) 916 { 917 if (dim != 2) 918 return dimError(2); 919 920 Expression ex; 921 auto op = (*e.args)[0]; 922 if (auto symp = getDsymbol(op)) 923 ex = new DsymbolExp(e.loc, symp); 924 else if (auto exp = op.isExpression()) 925 ex = exp; 926 else 927 { 928 e.error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op.toChars()); 929 return ErrorExp.get(); 930 } 931 932 ex = ex.expressionSemantic(sc); 933 auto oc = (*e.args)[1]; 934 auto symc = getDsymbol(oc); 935 if (!symc) 936 { 937 e.error("symbol expected as second argument of __traits `child` instead of `%s`", oc.toChars()); 938 return ErrorExp.get(); 939 } 940 941 if (auto d = symc.isDeclaration()) 942 ex = new DotVarExp(e.loc, ex, d); 943 else if (auto td = symc.isTemplateDeclaration()) 944 ex = new DotExp(e.loc, ex, new TemplateExp(e.loc, td)); 945 else if (auto ti = symc.isScopeDsymbol()) 946 ex = new DotExp(e.loc, ex, new ScopeExp(e.loc, ti)); 947 else 948 assert(0); 949 950 ex = ex.expressionSemantic(sc); 951 return ex; 952 } 953 if (e.ident == Id.hasMember || 954 e.ident == Id.getMember || 955 e.ident == Id.getOverloads || 956 e.ident == Id.getVirtualMethods || 957 e.ident == Id.getVirtualFunctions) 958 { 959 if (dim != 2 && !(dim == 3 && e.ident == Id.getOverloads)) 960 return dimError(2); 961 962 auto o = (*e.args)[0]; 963 auto ex = isExpression((*e.args)[1]); 964 if (!ex) 965 { 966 e.error("expression expected as second argument of __traits `%s`", e.ident.toChars()); 967 return ErrorExp.get(); 968 } 969 ex = ex.ctfeInterpret(); 970 971 bool includeTemplates = false; 972 if (dim == 3 && e.ident == Id.getOverloads) 973 { 974 auto b = isExpression((*e.args)[2]); 975 b = b.ctfeInterpret(); 976 if (!b.type.equals(Type.tbool)) 977 { 978 e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars()); 979 return ErrorExp.get(); 980 } 981 includeTemplates = b.isBool(true); 982 } 983 984 StringExp se = ex.toStringExp(); 985 if (!se || se.len == 0) 986 { 987 e.error("string expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); 988 return ErrorExp.get(); 989 } 990 se = se.toUTF8(sc); 991 992 if (se.sz != 1) 993 { 994 e.error("string must be chars"); 995 return ErrorExp.get(); 996 } 997 auto id = Identifier.idPool(se.peekString()); 998 999 /* Prefer a Type, because getDsymbol(Type) can lose type modifiers. 1000 Then a Dsymbol, because it might need some runtime contexts. 1001 */ 1002 1003 Dsymbol sym = getDsymbol(o); 1004 if (auto t = isType(o)) 1005 ex = typeDotIdExp(e.loc, t, id); 1006 else if (sym) 1007 { 1008 if (e.ident == Id.hasMember) 1009 { 1010 if (auto sm = sym.search(e.loc, id)) 1011 return True(); 1012 } 1013 ex = new DsymbolExp(e.loc, sym); 1014 ex = new DotIdExp(e.loc, ex, id); 1015 } 1016 else if (auto ex2 = isExpression(o)) 1017 ex = new DotIdExp(e.loc, ex2, id); 1018 else 1019 { 1020 e.error("invalid first argument"); 1021 return ErrorExp.get(); 1022 } 1023 1024 // ignore symbol visibility and disable access checks for these traits 1025 Scope* scx = sc.push(); 1026 scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck; 1027 scope (exit) scx.pop(); 1028 1029 if (e.ident == Id.hasMember) 1030 { 1031 /* Take any errors as meaning it wasn't found 1032 */ 1033 ex = ex.trySemantic(scx); 1034 return ex ? True() : False(); 1035 } 1036 else if (e.ident == Id.getMember) 1037 { 1038 if (ex.op == TOK.dotIdentifier) 1039 // Prevent semantic() from replacing Symbol with its initializer 1040 (cast(DotIdExp)ex).wantsym = true; 1041 ex = ex.expressionSemantic(scx); 1042 return ex; 1043 } 1044 else if (e.ident == Id.getVirtualFunctions || 1045 e.ident == Id.getVirtualMethods || 1046 e.ident == Id.getOverloads) 1047 { 1048 uint errors = global.errors; 1049 Expression eorig = ex; 1050 ex = ex.expressionSemantic(scx); 1051 if (errors < global.errors) 1052 e.error("`%s` cannot be resolved", eorig.toChars()); 1053 1054 /* Create tuple of functions of ex 1055 */ 1056 auto exps = new Expressions(); 1057 Dsymbol f; 1058 if (auto ve = ex.isVarExp) 1059 { 1060 if (ve.var.isFuncDeclaration() || ve.var.isOverDeclaration()) 1061 f = ve.var; 1062 ex = null; 1063 } 1064 else if (auto dve = ex.isDotVarExp) 1065 { 1066 if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration()) 1067 f = dve.var; 1068 if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_) 1069 ex = null; 1070 else 1071 ex = dve.e1; 1072 } 1073 else if (auto te = ex.isTemplateExp) 1074 { 1075 auto td = te.td; 1076 f = td; 1077 if (td && td.funcroot) 1078 f = td.funcroot; 1079 ex = null; 1080 } 1081 else if (auto dte = ex.isDotTemplateExp) 1082 { 1083 auto td = dte.td; 1084 f = td; 1085 if (td && td.funcroot) 1086 f = td.funcroot; 1087 ex = null; 1088 if (dte.e1.op != TOK.dotType && dte.e1.op != TOK.this_) 1089 ex = dte.e1; 1090 } 1091 bool[string] funcTypeHash; 1092 1093 /* Compute the function signature and insert it in the 1094 * hashtable, if not present. This is needed so that 1095 * traits(getOverlods, F3, "visit") does not count `int visit(int)` 1096 * twice in the following example: 1097 * 1098 * ============================================= 1099 * interface F1 { int visit(int);} 1100 * interface F2 { int visit(int); void visit(); } 1101 * interface F3 : F2, F1 {} 1102 *============================================== 1103 */ 1104 void insertInterfaceInheritedFunction(FuncDeclaration fd, Expression e) 1105 { 1106 auto signature = fd.type.toString(); 1107 //printf("%s - %s\n", fd.toChars, signature); 1108 if (signature !in funcTypeHash) 1109 { 1110 funcTypeHash[signature] = true; 1111 exps.push(e); 1112 } 1113 } 1114 1115 int dg(Dsymbol s) 1116 { 1117 auto fd = s.isFuncDeclaration(); 1118 if (!fd) 1119 { 1120 if (includeTemplates) 1121 { 1122 if (auto td = s.isTemplateDeclaration()) 1123 { 1124 // if td is part of an overload set we must take a copy 1125 // which shares the same `instances` cache but without 1126 // `overroot` and `overnext` set to avoid overload 1127 // behaviour in the result. 1128 if (td.overnext !is null) 1129 { 1130 if (td.instances is null) 1131 { 1132 // create an empty AA just to copy it 1133 scope ti = new TemplateInstance(Loc.initial, Id.empty, null); 1134 auto tib = TemplateInstanceBox(ti); 1135 td.instances[tib] = null; 1136 td.instances.clear(); 1137 } 1138 td = td.syntaxCopy(null); 1139 import core.stdc.string : memcpy; 1140 memcpy(cast(void*) td, cast(void*) s, 1141 __traits(classInstanceSize, TemplateDeclaration)); 1142 td.overroot = null; 1143 td.overnext = null; 1144 } 1145 exps.push(new DsymbolExp(Loc.initial, td, false)); 1146 } 1147 } 1148 return 0; 1149 } 1150 if (e.ident == Id.getVirtualFunctions && !fd.isVirtual()) 1151 return 0; 1152 if (e.ident == Id.getVirtualMethods && !fd.isVirtualMethod()) 1153 return 0; 1154 1155 auto fa = new FuncAliasDeclaration(fd.ident, fd, false); 1156 fa.visibility = fd.visibility; 1157 1158 auto e = ex ? new DotVarExp(Loc.initial, ex, fa, false) 1159 : new DsymbolExp(Loc.initial, fa, false); 1160 1161 // if the parent is an interface declaration 1162 // we must check for functions with the same signature 1163 // in different inherited interfaces 1164 if (sym && sym.isInterfaceDeclaration()) 1165 insertInterfaceInheritedFunction(fd, e); 1166 else 1167 exps.push(e); 1168 return 0; 1169 } 1170 1171 InterfaceDeclaration ifd = null; 1172 if (sym) 1173 ifd = sym.isInterfaceDeclaration(); 1174 // If the symbol passed as a parameter is an 1175 // interface that inherits other interfaces 1176 overloadApply(f, &dg); 1177 if (ifd && ifd.interfaces && f) 1178 { 1179 // check the overloads of each inherited interface individually 1180 foreach (bc; ifd.interfaces) 1181 { 1182 if (auto fd = bc.sym.search(e.loc, f.ident)) 1183 overloadApply(fd, &dg); 1184 } 1185 } 1186 1187 auto tup = new TupleExp(e.loc, exps); 1188 return tup.expressionSemantic(scx); 1189 } 1190 else 1191 assert(0); 1192 } 1193 if (e.ident == Id.classInstanceSize) 1194 { 1195 if (dim != 1) 1196 return dimError(1); 1197 1198 auto o = (*e.args)[0]; 1199 auto s = getDsymbol(o); 1200 auto cd = s ? s.isClassDeclaration() : null; 1201 if (!cd) 1202 { 1203 e.error("first argument is not a class"); 1204 return ErrorExp.get(); 1205 } 1206 if (cd.sizeok != Sizeok.done) 1207 { 1208 cd.size(e.loc); 1209 } 1210 if (cd.sizeok != Sizeok.done) 1211 { 1212 e.error("%s `%s` is forward referenced", cd.kind(), cd.toChars()); 1213 return ErrorExp.get(); 1214 } 1215 1216 return new IntegerExp(e.loc, cd.structsize, Type.tsize_t); 1217 } 1218 if (e.ident == Id.getAliasThis) 1219 { 1220 if (dim != 1) 1221 return dimError(1); 1222 1223 auto o = (*e.args)[0]; 1224 auto s = getDsymbol(o); 1225 auto ad = s ? s.isAggregateDeclaration() : null; 1226 1227 auto exps = new Expressions(); 1228 if (ad && ad.aliasthis) 1229 exps.push(new StringExp(e.loc, ad.aliasthis.ident.toString())); 1230 Expression ex = new TupleExp(e.loc, exps); 1231 ex = ex.expressionSemantic(sc); 1232 return ex; 1233 } 1234 if (e.ident == Id.getAttributes) 1235 { 1236 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that 1237 * a symbol should not be folded to a constant. 1238 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier 1239 */ 1240 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 3)) 1241 return ErrorExp.get(); 1242 1243 if (dim != 1) 1244 return dimError(1); 1245 1246 auto o = (*e.args)[0]; 1247 auto po = isParameter(o); 1248 auto s = getDsymbolWithoutExpCtx(o); 1249 UserAttributeDeclaration udad = null; 1250 if (po) 1251 { 1252 udad = po.userAttribDecl; 1253 } 1254 else if (s) 1255 { 1256 if (s.isImport()) 1257 { 1258 s = s.isImport().mod; 1259 } 1260 //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope); 1261 udad = s.userAttribDecl; 1262 } 1263 else 1264 { 1265 version (none) 1266 { 1267 Expression x = isExpression(o); 1268 Type t = isType(o); 1269 if (x) 1270 printf("e = %s %s\n", Token.toChars(x.op), x.toChars()); 1271 if (t) 1272 printf("t = %d %s\n", t.ty, t.toChars()); 1273 } 1274 e.error("first argument is not a symbol"); 1275 return ErrorExp.get(); 1276 } 1277 1278 auto exps = udad ? udad.getAttributes() : new Expressions(); 1279 auto tup = new TupleExp(e.loc, exps); 1280 return tup.expressionSemantic(sc); 1281 } 1282 if (e.ident == Id.getFunctionAttributes) 1283 { 1284 /* Extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. 1285 * https://dlang.org/spec/traits.html#getFunctionAttributes 1286 */ 1287 if (dim != 1) 1288 return dimError(1); 1289 1290 FuncDeclaration fd; 1291 TypeFunction tf = toTypeFunction((*e.args)[0], fd); 1292 1293 if (!tf) 1294 { 1295 e.error("first argument is not a function"); 1296 return ErrorExp.get(); 1297 } 1298 1299 auto mods = new Expressions(); 1300 1301 void addToMods(string str) 1302 { 1303 mods.push(new StringExp(Loc.initial, str)); 1304 } 1305 tf.modifiersApply(&addToMods); 1306 tf.attributesApply(&addToMods, TRUSTformatSystem); 1307 1308 auto tup = new TupleExp(e.loc, mods); 1309 return tup.expressionSemantic(sc); 1310 } 1311 if (e.ident == Id.isReturnOnStack) 1312 { 1313 /* Extract as a boolean if function return value is on the stack 1314 * https://dlang.org/spec/traits.html#isReturnOnStack 1315 */ 1316 if (dim != 1) 1317 return dimError(1); 1318 1319 RootObject o = (*e.args)[0]; 1320 FuncDeclaration fd; 1321 TypeFunction tf = toTypeFunction(o, fd); 1322 1323 if (!tf) 1324 { 1325 e.error("argument to `__traits(isReturnOnStack, %s)` is not a function", o.toChars()); 1326 return ErrorExp.get(); 1327 } 1328 1329 bool value = target.isReturnOnStack(tf, fd && fd.needThis()); 1330 return IntegerExp.createBool(value); 1331 } 1332 if (e.ident == Id.getFunctionVariadicStyle) 1333 { 1334 /* Accept a symbol or a type. Returns one of the following: 1335 * "none" not a variadic function 1336 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments` 1337 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg 1338 * "typesafe" void typesafe(T[] ...) 1339 */ 1340 // get symbol linkage as a string 1341 if (dim != 1) 1342 return dimError(1); 1343 1344 LINK link; 1345 VarArg varargs; 1346 auto o = (*e.args)[0]; 1347 1348 FuncDeclaration fd; 1349 TypeFunction tf = toTypeFunction(o, fd); 1350 1351 if (tf) 1352 { 1353 link = tf.linkage; 1354 varargs = tf.parameterList.varargs; 1355 } 1356 else 1357 { 1358 if (!fd) 1359 { 1360 e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars()); 1361 return ErrorExp.get(); 1362 } 1363 link = fd.linkage; 1364 varargs = fd.getParameterList().varargs; 1365 } 1366 string style; 1367 final switch (varargs) 1368 { 1369 case VarArg.none: style = "none"; break; 1370 case VarArg.variadic: style = (link == LINK.d) 1371 ? "argptr" 1372 : "stdarg"; break; 1373 case VarArg.typesafe: style = "typesafe"; break; 1374 } 1375 auto se = new StringExp(e.loc, style); 1376 return se.expressionSemantic(sc); 1377 } 1378 if (e.ident == Id.getParameterStorageClasses) 1379 { 1380 /* Accept a function symbol or a type, followed by a parameter index. 1381 * Returns a tuple of strings of the parameter's storage classes. 1382 */ 1383 // get symbol linkage as a string 1384 if (dim != 2) 1385 return dimError(2); 1386 1387 auto o = (*e.args)[0]; 1388 auto o1 = (*e.args)[1]; 1389 1390 FuncDeclaration fd; 1391 TypeFunction tf = toTypeFunction(o, fd); 1392 1393 ParameterList fparams; 1394 if (tf) 1395 fparams = tf.parameterList; 1396 else if (fd) 1397 fparams = fd.getParameterList(); 1398 else 1399 { 1400 e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", 1401 o.toChars(), o1.toChars()); 1402 return ErrorExp.get(); 1403 } 1404 1405 StorageClass stc; 1406 1407 // Set stc to storage class of the ith parameter 1408 auto ex = isExpression((*e.args)[1]); 1409 if (!ex) 1410 { 1411 e.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`", 1412 o.toChars(), o1.toChars()); 1413 return ErrorExp.get(); 1414 } 1415 ex = ex.ctfeInterpret(); 1416 auto ii = ex.toUInteger(); 1417 if (ii >= fparams.length) 1418 { 1419 e.error("parameter index must be in range 0..%u not %s", cast(uint)fparams.length, ex.toChars()); 1420 return ErrorExp.get(); 1421 } 1422 1423 uint n = cast(uint)ii; 1424 Parameter p = fparams[n]; 1425 stc = p.storageClass; 1426 1427 // This mirrors hdrgen.visit(Parameter p) 1428 if (p.type && p.type.mod & MODFlags.shared_) 1429 stc &= ~STC.shared_; 1430 1431 auto exps = new Expressions; 1432 1433 void push(string s) 1434 { 1435 exps.push(new StringExp(e.loc, s)); 1436 } 1437 1438 if (stc & STC.auto_) 1439 push("auto"); 1440 if (stc & STC.return_) 1441 push("return"); 1442 1443 if (stc & STC.out_) 1444 push("out"); 1445 else if (stc & STC.ref_) 1446 push("ref"); 1447 else if (stc & STC.in_) 1448 push("in"); 1449 else if (stc & STC.lazy_) 1450 push("lazy"); 1451 else if (stc & STC.alias_) 1452 push("alias"); 1453 1454 if (stc & STC.const_) 1455 push("const"); 1456 if (stc & STC.immutable_) 1457 push("immutable"); 1458 if (stc & STC.wild) 1459 push("inout"); 1460 if (stc & STC.shared_) 1461 push("shared"); 1462 if (stc & STC.scope_ && !(stc & STC.scopeinferred)) 1463 push("scope"); 1464 1465 auto tup = new TupleExp(e.loc, exps); 1466 return tup.expressionSemantic(sc); 1467 } 1468 if (e.ident == Id.getLinkage) 1469 { 1470 // get symbol linkage as a string 1471 if (dim != 1) 1472 return dimError(1); 1473 1474 LINK link; 1475 auto o = (*e.args)[0]; 1476 1477 FuncDeclaration fd; 1478 TypeFunction tf = toTypeFunction(o, fd); 1479 1480 if (tf) 1481 link = tf.linkage; 1482 else 1483 { 1484 auto s = getDsymbol(o); 1485 Declaration d; 1486 AggregateDeclaration agg; 1487 if (!s || ((d = s.isDeclaration()) is null && (agg = s.isAggregateDeclaration()) is null)) 1488 { 1489 e.error("argument to `__traits(getLinkage, %s)` is not a declaration", o.toChars()); 1490 return ErrorExp.get(); 1491 } 1492 1493 if (d !is null) 1494 link = d.linkage; 1495 else 1496 { 1497 // Resolves forward references 1498 if (agg.sizeok != Sizeok.done) 1499 { 1500 agg.size(e.loc); 1501 if (agg.sizeok != Sizeok.done) 1502 { 1503 e.error("%s `%s` is forward referenced", agg.kind(), agg.toChars()); 1504 return ErrorExp.get(); 1505 } 1506 } 1507 1508 final switch (agg.classKind) 1509 { 1510 case ClassKind.d: 1511 link = LINK.d; 1512 break; 1513 case ClassKind.cpp: 1514 link = LINK.cpp; 1515 break; 1516 case ClassKind.objc: 1517 link = LINK.objc; 1518 break; 1519 } 1520 } 1521 } 1522 auto linkage = linkageToChars(link); 1523 auto se = new StringExp(e.loc, linkage.toDString()); 1524 return se.expressionSemantic(sc); 1525 } 1526 if (e.ident == Id.allMembers || 1527 e.ident == Id.derivedMembers) 1528 { 1529 if (dim != 1) 1530 return dimError(1); 1531 1532 auto o = (*e.args)[0]; 1533 auto s = getDsymbol(o); 1534 if (!s) 1535 { 1536 e.error("In expression `%s` `%s` can't have members", e.toChars(), o.toChars()); 1537 e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", o.toChars()); 1538 1539 return ErrorExp.get(); 1540 } 1541 if (auto imp = s.isImport()) 1542 { 1543 // https://issues.dlang.org/show_bug.cgi?id=9692 1544 s = imp.mod; 1545 } 1546 1547 // https://issues.dlang.org/show_bug.cgi?id=16044 1548 if (auto p = s.isPackage()) 1549 { 1550 if (auto pm = p.isPackageMod()) 1551 s = pm; 1552 } 1553 1554 auto sds = s.isScopeDsymbol(); 1555 if (!sds || sds.isTemplateDeclaration()) 1556 { 1557 e.error("In expression `%s` %s `%s` has no members", e.toChars(), s.kind(), s.toChars()); 1558 e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", s.toChars()); 1559 return ErrorExp.get(); 1560 } 1561 1562 auto idents = new Identifiers(); 1563 1564 int pushIdentsDg(size_t n, Dsymbol sm) 1565 { 1566 if (!sm) 1567 return 1; 1568 1569 // skip local symbols, such as static foreach loop variables 1570 if (auto decl = sm.isDeclaration()) 1571 { 1572 if (decl.storage_class & STC.local) 1573 { 1574 return 0; 1575 } 1576 } 1577 1578 // https://issues.dlang.org/show_bug.cgi?id=20915 1579 // skip version and debug identifiers 1580 if (sm.isVersionSymbol() || sm.isDebugSymbol()) 1581 return 0; 1582 1583 //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars()); 1584 if (sm.ident) 1585 { 1586 // https://issues.dlang.org/show_bug.cgi?id=10096 1587 // https://issues.dlang.org/show_bug.cgi?id=10100 1588 // Skip over internal members in __traits(allMembers) 1589 if ((sm.isCtorDeclaration() && sm.ident != Id.ctor) || 1590 (sm.isDtorDeclaration() && sm.ident != Id.dtor) || 1591 (sm.isPostBlitDeclaration() && sm.ident != Id.postblit) || 1592 sm.isInvariantDeclaration() || 1593 sm.isUnitTestDeclaration()) 1594 1595 { 1596 return 0; 1597 } 1598 if (sm.ident == Id.empty) 1599 { 1600 return 0; 1601 } 1602 if (sm.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177 1603 return 0; 1604 if ((!sds.isModule() && !sds.isPackage()) && sm.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057 1605 return 0; 1606 1607 //printf("\t%s\n", sm.ident.toChars()); 1608 1609 /* Skip if already present in idents[] 1610 */ 1611 foreach (id; *idents) 1612 { 1613 if (id == sm.ident) 1614 return 0; 1615 1616 // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. 1617 debug 1618 { 1619 import core.stdc.string : strcmp; 1620 assert(strcmp(id.toChars(), sm.ident.toChars()) != 0); 1621 } 1622 } 1623 idents.push(sm.ident); 1624 } 1625 else if (auto ed = sm.isEnumDeclaration()) 1626 { 1627 ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg); 1628 } 1629 return 0; 1630 } 1631 1632 ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg); 1633 auto cd = sds.isClassDeclaration(); 1634 if (cd && e.ident == Id.allMembers) 1635 { 1636 if (cd.semanticRun < PASS.semanticdone) 1637 cd.dsymbolSemantic(null); // https://issues.dlang.org/show_bug.cgi?id=13668 1638 // Try to resolve forward reference 1639 1640 void pushBaseMembersDg(ClassDeclaration cd) 1641 { 1642 for (size_t i = 0; i < cd.baseclasses.dim; i++) 1643 { 1644 auto cb = (*cd.baseclasses)[i].sym; 1645 assert(cb); 1646 ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg); 1647 if (cb.baseclasses.dim) 1648 pushBaseMembersDg(cb); 1649 } 1650 } 1651 1652 pushBaseMembersDg(cd); 1653 } 1654 1655 // Turn Identifiers into StringExps reusing the allocated array 1656 assert(Expressions.sizeof == Identifiers.sizeof); 1657 auto exps = cast(Expressions*)idents; 1658 foreach (i, id; *idents) 1659 { 1660 auto se = new StringExp(e.loc, id.toString()); 1661 (*exps)[i] = se; 1662 } 1663 1664 /* Making this a tuple is more flexible, as it can be statically unrolled. 1665 * To make an array literal, enclose __traits in [ ]: 1666 * [ __traits(allMembers, ...) ] 1667 */ 1668 Expression ex = new TupleExp(e.loc, exps); 1669 ex = ex.expressionSemantic(sc); 1670 return ex; 1671 } 1672 if (e.ident == Id.compiles) 1673 { 1674 /* Determine if all the objects - types, expressions, or symbols - 1675 * compile without error 1676 */ 1677 if (!dim) 1678 return False(); 1679 1680 foreach (o; *e.args) 1681 { 1682 uint errors = global.startGagging(); 1683 Scope* sc2 = sc.push(); 1684 sc2.tinst = null; 1685 sc2.minst = null; 1686 sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst; 1687 1688 bool err = false; 1689 1690 auto t = isType(o); 1691 while (t) 1692 { 1693 if (auto tm = t.isTypeMixin()) 1694 { 1695 /* The mixin string could be a type or an expression. 1696 * Have to try compiling it to see. 1697 */ 1698 OutBuffer buf; 1699 if (expressionsToString(buf, sc, tm.exps)) 1700 { 1701 err = true; 1702 break; 1703 } 1704 const olderrors = global.errors; 1705 const len = buf.length; 1706 buf.writeByte(0); 1707 const str = buf.extractSlice()[0 .. len]; 1708 scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false); 1709 p.nextToken(); 1710 //printf("p.loc.linnum = %d\n", p.loc.linnum); 1711 1712 o = p.parseTypeOrAssignExp(TOK.endOfFile); 1713 p.reportDiagnostics(); 1714 if (olderrors != global.errors || p.token.value != TOK.endOfFile) 1715 { 1716 err = true; 1717 break; 1718 } 1719 t = o.isType(); 1720 } 1721 else 1722 break; 1723 } 1724 1725 if (!err) 1726 { 1727 auto ex = t ? t.typeToExpression() : isExpression(o); 1728 if (!ex && t) 1729 { 1730 Dsymbol s; 1731 t.resolve(e.loc, sc2, ex, t, s); 1732 if (t) 1733 { 1734 t.typeSemantic(e.loc, sc2); 1735 if (t.ty == Terror) 1736 err = true; 1737 } 1738 else if (s && s.errors) 1739 err = true; 1740 } 1741 if (ex) 1742 { 1743 ex = ex.expressionSemantic(sc2); 1744 ex = resolvePropertiesOnly(sc2, ex); 1745 ex = ex.optimize(WANTvalue); 1746 if (sc2.func && sc2.func.type.ty == Tfunction) 1747 { 1748 const tf = cast(TypeFunction)sc2.func.type; 1749 err |= tf.isnothrow && canThrow(ex, sc2.func, false); 1750 } 1751 ex = checkGC(sc2, ex); 1752 if (ex.op == TOK.error) 1753 err = true; 1754 } 1755 } 1756 1757 // Carefully detach the scope from the parent and throw it away as 1758 // we only need it to evaluate the expression 1759 // https://issues.dlang.org/show_bug.cgi?id=15428 1760 sc2.detach(); 1761 1762 if (global.endGagging(errors) || err) 1763 { 1764 return False(); 1765 } 1766 } 1767 return True(); 1768 } 1769 if (e.ident == Id.isSame) 1770 { 1771 /* Determine if two symbols are the same 1772 */ 1773 if (dim != 2) 1774 return dimError(2); 1775 1776 // https://issues.dlang.org/show_bug.cgi?id=20761 1777 // tiarg semantic may expand in place the list of arguments, for example: 1778 // 1779 // before tiarg sema: __traits(isSame, seq!(0,0), seq!(1,1)) 1780 // after : __traits(isSame, 0, 0, 1, 1) 1781 // 1782 // so we split in two lists 1783 Objects ob1; 1784 ob1.push((*e.args)[0]); 1785 Objects ob2; 1786 ob2.push((*e.args)[1]); 1787 if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob1, 0)) 1788 return ErrorExp.get(); 1789 if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob2, 0)) 1790 return ErrorExp.get(); 1791 if (ob1.dim != ob2.dim) 1792 return False(); 1793 foreach (immutable i; 0 .. ob1.dim) 1794 if (!ob1[i].isSame(ob2[i], sc)) 1795 return False(); 1796 return True(); 1797 } 1798 if (e.ident == Id.getUnitTests) 1799 { 1800 if (dim != 1) 1801 return dimError(1); 1802 1803 auto o = (*e.args)[0]; 1804 auto s = getDsymbolWithoutExpCtx(o); 1805 if (!s) 1806 { 1807 e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate", 1808 o.toChars()); 1809 return ErrorExp.get(); 1810 } 1811 if (auto imp = s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990 1812 s = imp.mod; 1813 1814 auto sds = s.isScopeDsymbol(); 1815 if (!sds || sds.isTemplateDeclaration()) 1816 { 1817 e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate, not a %s", 1818 s.toChars(), s.kind()); 1819 return ErrorExp.get(); 1820 } 1821 1822 auto exps = new Expressions(); 1823 if (global.params.useUnitTests) 1824 { 1825 bool[void*] uniqueUnitTests; 1826 1827 void symbolDg(Dsymbol s) 1828 { 1829 if (auto ad = s.isAttribDeclaration()) 1830 { 1831 ad.include(null).foreachDsymbol(&symbolDg); 1832 } 1833 else if (auto tm = s.isTemplateMixin()) 1834 { 1835 tm.members.foreachDsymbol(&symbolDg); 1836 } 1837 else if (auto ud = s.isUnitTestDeclaration()) 1838 { 1839 if (cast(void*)ud in uniqueUnitTests) 1840 return; 1841 1842 uniqueUnitTests[cast(void*)ud] = true; 1843 1844 auto ad = new FuncAliasDeclaration(ud.ident, ud, false); 1845 ad.visibility = ud.visibility; 1846 1847 auto e = new DsymbolExp(Loc.initial, ad, false); 1848 exps.push(e); 1849 } 1850 } 1851 1852 sds.members.foreachDsymbol(&symbolDg); 1853 } 1854 auto te = new TupleExp(e.loc, exps); 1855 return te.expressionSemantic(sc); 1856 } 1857 if (e.ident == Id.getVirtualIndex) 1858 { 1859 if (dim != 1) 1860 return dimError(1); 1861 1862 auto o = (*e.args)[0]; 1863 auto s = getDsymbolWithoutExpCtx(o); 1864 1865 auto fd = s ? s.isFuncDeclaration() : null; 1866 if (!fd) 1867 { 1868 e.error("first argument to __traits(getVirtualIndex) must be a function"); 1869 return ErrorExp.get(); 1870 } 1871 1872 fd = fd.toAliasFunc(); // Necessary to support multiple overloads. 1873 return new IntegerExp(e.loc, fd.vtblIndex, Type.tptrdiff_t); 1874 } 1875 if (e.ident == Id.getPointerBitmap) 1876 { 1877 return pointerBitmap(e); 1878 } 1879 if (e.ident == Id.isZeroInit) 1880 { 1881 if (dim != 1) 1882 return dimError(1); 1883 1884 auto o = (*e.args)[0]; 1885 Type t = isType(o); 1886 if (!t) 1887 { 1888 e.error("type expected as second argument of __traits `%s` instead of `%s`", 1889 e.ident.toChars(), o.toChars()); 1890 return ErrorExp.get(); 1891 } 1892 1893 Type tb = t.baseElemOf(); 1894 return tb.isZeroInit(e.loc) ? True() : False(); 1895 } 1896 if (e.ident == Id.getTargetInfo) 1897 { 1898 if (dim != 1) 1899 return dimError(1); 1900 1901 auto ex = isExpression((*e.args)[0]); 1902 StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null; 1903 if (!ex || !se || se.len == 0) 1904 { 1905 e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars()); 1906 return ErrorExp.get(); 1907 } 1908 se = se.toUTF8(sc); 1909 1910 const slice = se.peekString(); 1911 Expression r = target.getTargetInfo(slice.ptr, e.loc); // BUG: reliance on terminating 0 1912 if (!r) 1913 { 1914 e.error("`getTargetInfo` key `\"%.*s\"` not supported by this implementation", 1915 cast(int)slice.length, slice.ptr); 1916 return ErrorExp.get(); 1917 } 1918 return r.expressionSemantic(sc); 1919 } 1920 if (e.ident == Id.getLocation) 1921 { 1922 if (dim != 1) 1923 return dimError(1); 1924 auto arg0 = (*e.args)[0]; 1925 Dsymbol s = getDsymbolWithoutExpCtx(arg0); 1926 if (!s || !s.loc.isValid()) 1927 { 1928 e.error("can only get the location of a symbol, not `%s`", arg0.toChars()); 1929 return ErrorExp.get(); 1930 } 1931 1932 const fd = s.isFuncDeclaration(); 1933 // FIXME:td.overnext is always set, even when using an index on it 1934 //const td = s.isTemplateDeclaration(); 1935 if ((fd && fd.overnext) /*|| (td && td.overnext)*/) 1936 { 1937 e.error("cannot get location of an overload set, " ~ 1938 "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " ~ 1939 "to get the Nth overload", 1940 arg0.toChars(), /*td ? ", true".ptr :*/ "".ptr); 1941 return ErrorExp.get(); 1942 } 1943 1944 auto exps = new Expressions(3); 1945 (*exps)[0] = new StringExp(e.loc, s.loc.filename.toDString()); 1946 (*exps)[1] = new IntegerExp(e.loc, s.loc.linnum,Type.tint32); 1947 (*exps)[2] = new IntegerExp(e.loc, s.loc.charnum,Type.tint32); 1948 auto tup = new TupleExp(e.loc, exps); 1949 return tup.expressionSemantic(sc); 1950 } 1951 if (e.ident == Id.getCppNamespaces) 1952 { 1953 auto o = (*e.args)[0]; 1954 auto s = getDsymbolWithoutExpCtx(o); 1955 auto exps = new Expressions(0); 1956 if (auto d = s.isDeclaration()) 1957 { 1958 if (d.inuse) 1959 { 1960 d.error("circular reference in `__traits(GetCppNamespaces,...)`"); 1961 return ErrorExp.get(); 1962 } 1963 d.inuse = 1; 1964 } 1965 1966 /** 1967 Prepend the namespaces in the linked list `ns` to `es`. 1968 1969 Returns: true if `ns` contains an `ErrorExp`. 1970 */ 1971 bool prependNamespaces(Expressions* es, CPPNamespaceDeclaration ns) 1972 { 1973 // Semantic processing will convert `extern(C++, "a", "b", "c")` 1974 // into `extern(C++, "a") extern(C++, "b") extern(C++, "c")`, 1975 // creating a linked list what `a`'s `cppnamespace` points to `b`, 1976 // and `b`'s points to `c`. Our entry point is `a`. 1977 for (; ns !is null; ns = ns.cppnamespace) 1978 { 1979 ns.dsymbolSemantic(sc); 1980 1981 if (ns.exp.isErrorExp()) 1982 return true; 1983 1984 auto se = ns.exp.toStringExp(); 1985 // extern(C++, (emptyTuple)) 1986 // struct D {} 1987 // will produce a blank ident 1988 if (!se.len) 1989 continue; 1990 es.insert(0, se); 1991 } 1992 return false; 1993 } 1994 for (auto p = s; !p.isModule(); p = p.toParent()) 1995 { 1996 p.dsymbolSemantic(sc); 1997 auto pp = p.toParent(); 1998 if (pp.isTemplateInstance()) 1999 { 2000 if (!p.cppnamespace) 2001 continue; 2002 //if (!p.toParent().cppnamespace) 2003 // continue; 2004 auto inner = new Expressions(0); 2005 auto outer = new Expressions(0); 2006 if (prependNamespaces(inner, p.cppnamespace)) return ErrorExp.get(); 2007 if (prependNamespaces(outer, pp.cppnamespace)) return ErrorExp.get(); 2008 2009 size_t i = 0; 2010 while(i < outer.dim && ((*inner)[i]) == (*outer)[i]) 2011 i++; 2012 2013 foreach_reverse (ns; (*inner)[][i .. $]) 2014 exps.insert(0, ns); 2015 continue; 2016 } 2017 2018 if (p.isNspace()) 2019 exps.insert(0, new StringExp(p.loc, p.ident.toString())); 2020 2021 if (prependNamespaces(exps, p.cppnamespace)) 2022 return ErrorExp.get(); 2023 } 2024 if (auto d = s.isDeclaration()) 2025 d.inuse = 0; 2026 auto tup = new TupleExp(e.loc, exps); 2027 return tup.expressionSemantic(sc); 2028 } 2029 2030 static const(char)[] trait_search_fp(const(char)[] seed, out int cost) 2031 { 2032 //printf("trait_search_fp('%s')\n", seed); 2033 if (!seed.length) 2034 return null; 2035 cost = 0; // all the same cost 2036 const sv = traitsStringTable.lookup(seed); 2037 return sv ? sv.toString() : null; 2038 } 2039 2040 if (auto sub = speller!trait_search_fp(e.ident.toString())) 2041 e.error("unrecognized trait `%s`, did you mean `%.*s`?", e.ident.toChars(), cast(int) sub.length, sub.ptr); 2042 else 2043 e.error("unrecognized trait `%s`", e.ident.toChars()); 2044 return ErrorExp.get(); 2045 } 2046 2047 /// compare arguments of __traits(isSame) 2048 private bool isSame(RootObject o1, RootObject o2, Scope* sc) 2049 { 2050 static FuncLiteralDeclaration isLambda(RootObject oarg) 2051 { 2052 if (auto t = isDsymbol(oarg)) 2053 { 2054 if (auto td = t.isTemplateDeclaration()) 2055 { 2056 if (td.members && td.members.dim == 1) 2057 { 2058 if (auto fd = (*td.members)[0].isFuncLiteralDeclaration()) 2059 return fd; 2060 } 2061 } 2062 } 2063 else if (auto ea = isExpression(oarg)) 2064 { 2065 if (ea.op == TOK.function_) 2066 { 2067 if (auto fe = cast(FuncExp)ea) 2068 return fe.fd; 2069 } 2070 } 2071 return null; 2072 } 2073 2074 auto l1 = isLambda(o1); 2075 auto l2 = isLambda(o2); 2076 2077 if (l1 && l2) 2078 { 2079 import dmd.lambdacomp : isSameFuncLiteral; 2080 if (isSameFuncLiteral(l1, l2, sc)) 2081 return true; 2082 } 2083 2084 // issue 12001, allow isSame, <BasicType>, <BasicType> 2085 Type t1 = isType(o1); 2086 Type t2 = isType(o2); 2087 if (t1 && t2 && t1.equals(t2)) 2088 return true; 2089 2090 auto s1 = getDsymbol(o1); 2091 auto s2 = getDsymbol(o2); 2092 //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars()); 2093 version (none) 2094 { 2095 printf("o1: %p\n", o1); 2096 printf("o2: %p\n", o2); 2097 if (!s1) 2098 { 2099 if (auto ea = isExpression(o1)) 2100 printf("%s\n", ea.toChars()); 2101 if (auto ta = isType(o1)) 2102 printf("%s\n", ta.toChars()); 2103 return false; 2104 } 2105 else 2106 printf("%s %s\n", s1.kind(), s1.toChars()); 2107 } 2108 if (!s1 && !s2) 2109 { 2110 auto ea1 = isExpression(o1); 2111 auto ea2 = isExpression(o2); 2112 if (ea1 && ea2) 2113 { 2114 if (ea1.equals(ea2)) 2115 return true; 2116 } 2117 } 2118 if (!s1 || !s2) 2119 return false; 2120 2121 s1 = s1.toAlias(); 2122 s2 = s2.toAlias(); 2123 2124 if (auto fa1 = s1.isFuncAliasDeclaration()) 2125 s1 = fa1.toAliasFunc(); 2126 if (auto fa2 = s2.isFuncAliasDeclaration()) 2127 s2 = fa2.toAliasFunc(); 2128 2129 // https://issues.dlang.org/show_bug.cgi?id=11259 2130 // compare import symbol to a package symbol 2131 static bool cmp(Dsymbol s1, Dsymbol s2) 2132 { 2133 auto imp = s1.isImport(); 2134 return imp && imp.pkg && imp.pkg == s2.isPackage(); 2135 } 2136 2137 if (cmp(s1,s2) || cmp(s2,s1)) 2138 return true; 2139 2140 if (s1 == s2) 2141 return true; 2142 2143 // https://issues.dlang.org/show_bug.cgi?id=18771 2144 // OverloadSets are equal if they contain the same functions 2145 auto overSet1 = s1.isOverloadSet(); 2146 if (!overSet1) 2147 return false; 2148 2149 auto overSet2 = s2.isOverloadSet(); 2150 if (!overSet2) 2151 return false; 2152 2153 if (overSet1.a.dim != overSet2.a.dim) 2154 return false; 2155 2156 // OverloadSets contain array of Dsymbols => O(n*n) 2157 // to compare for equality as the order of overloads 2158 // might not be the same 2159 Lnext: 2160 foreach(overload1; overSet1.a) 2161 { 2162 foreach(overload2; overSet2.a) 2163 { 2164 if (overload1 == overload2) 2165 continue Lnext; 2166 } 2167 return false; 2168 } 2169 return true; 2170 }