1 2/* Compiler implementation of the D programming language 3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved 4 * written by Walter Bright 5 * http://www.digitalmars.com 6 * Distributed under the Boost Software License, Version 1.0. 7 * http://www.boost.org/LICENSE_1_0.txt 8 * https://github.com/D-Programming-Language/dmd/blob/master/src/traits.c 9 */ 10 11#include "root/dsystem.h" 12#include "root/rmem.h" 13#include "root/aav.h" 14#include "root/checkedint.h" 15 16#include "errors.h" 17#include "mtype.h" 18#include "init.h" 19#include "expression.h" 20#include "template.h" 21#include "utf.h" 22#include "enum.h" 23#include "scope.h" 24#include "hdrgen.h" 25#include "statement.h" 26#include "declaration.h" 27#include "aggregate.h" 28#include "import.h" 29#include "id.h" 30#include "dsymbol.h" 31#include "module.h" 32#include "attrib.h" 33#include "parse.h" 34#include "root/speller.h" 35 36typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); 37int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL); 38void freeFieldinit(Scope *sc); 39Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads); 40Expression *trySemantic(Expression *e, Scope *sc); 41Expression *semantic(Expression *e, Scope *sc); 42Expression *typeToExpression(Type *t); 43 44 45/************************************************ 46 * Delegate to be passed to overloadApply() that looks 47 * for functions matching a trait. 48 */ 49 50struct Ptrait 51{ 52 Expression *e1; 53 Expressions *exps; // collected results 54 Identifier *ident; // which trait we're looking for 55}; 56 57static int fptraits(void *param, Dsymbol *s) 58{ 59 FuncDeclaration *f = s->isFuncDeclaration(); 60 if (!f) 61 return 0; 62 63 Ptrait *p = (Ptrait *)param; 64 if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) 65 return 0; 66 67 if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) 68 return 0; 69 70 Expression *e; 71 FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false); 72 ad->protection = f->protection; 73 if (p->e1) 74 e = new DotVarExp(Loc(), p->e1, ad, false); 75 else 76 e = new DsymbolExp(Loc(), ad, false); 77 p->exps->push(e); 78 return 0; 79} 80 81/** 82 * Collects all unit test functions from the given array of symbols. 83 * 84 * This is a helper function used by the implementation of __traits(getUnitTests). 85 * 86 * Input: 87 * symbols array of symbols to collect the functions from 88 * uniqueUnitTests an associative array (should actually be a set) to 89 * keep track of already collected functions. We're 90 * using an AA here to avoid doing a linear search of unitTests 91 * 92 * Output: 93 * unitTests array of DsymbolExp's of the collected unit test functions 94 * uniqueUnitTests updated with symbols from unitTests[ ] 95 */ 96static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests) 97{ 98 if (!symbols) 99 return; 100 for (size_t i = 0; i < symbols->dim; i++) 101 { 102 Dsymbol *symbol = (*symbols)[i]; 103 UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration(); 104 if (unitTest) 105 { 106 if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest)) 107 { 108 FuncAliasDeclaration* ad = new FuncAliasDeclaration(unitTest->ident, unitTest, false); 109 ad->protection = unitTest->protection; 110 Expression* e = new DsymbolExp(Loc(), ad, false); 111 unitTests->push(e); 112 bool* value = (bool*) dmd_aaGet(&uniqueUnitTests, (void *)unitTest); 113 *value = true; 114 } 115 } 116 else 117 { 118 AttribDeclaration *attrDecl = symbol->isAttribDeclaration(); 119 120 if (attrDecl) 121 { 122 Dsymbols *decl = attrDecl->include(NULL, NULL); 123 collectUnitTests(decl, uniqueUnitTests, unitTests); 124 } 125 } 126 } 127} 128 129/************************ TraitsExp ************************************/ 130 131static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); } 132static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); } 133 134bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } 135bool isTypeFloating(Type *t) { return t->isfloating(); } 136bool isTypeIntegral(Type *t) { return t->isintegral(); } 137bool isTypeScalar(Type *t) { return t->isscalar(); } 138bool isTypeUnsigned(Type *t) { return t->isunsigned(); } 139bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } 140bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } 141bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } 142bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } 143 144Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) 145{ 146 if (!e->args || !e->args->dim) 147 return False(e); 148 for (size_t i = 0; i < e->args->dim; i++) 149 { 150 Type *t = getType((*e->args)[i]); 151 if (!t || !fp(t)) 152 return False(e); 153 } 154 return True(e); 155} 156 157bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } 158bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } 159bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } 160bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } 161bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } 162bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } 163 164Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) 165{ 166 if (!e->args || !e->args->dim) 167 return False(e); 168 for (size_t i = 0; i < e->args->dim; i++) 169 { 170 Dsymbol *s = getDsymbol((*e->args)[i]); 171 if (!s) 172 return False(e); 173 FuncDeclaration *f = s->isFuncDeclaration(); 174 if (!f || !fp(f)) 175 return False(e); 176 } 177 return True(e); 178} 179 180bool isDeclRef(Declaration *d) { return d->isRef(); } 181bool isDeclOut(Declaration *d) { return d->isOut(); } 182bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } 183 184Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) 185{ 186 if (!e->args || !e->args->dim) 187 return False(e); 188 for (size_t i = 0; i < e->args->dim; i++) 189 { 190 Dsymbol *s = getDsymbol((*e->args)[i]); 191 if (!s) 192 return False(e); 193 Declaration *d = s->isDeclaration(); 194 if (!d || !fp(d)) 195 return False(e); 196 } 197 return True(e); 198} 199 200// callback for TypeFunction::attributesApply 201struct PushAttributes 202{ 203 Expressions *mods; 204 205 static int fp(void *param, const char *str) 206 { 207 PushAttributes *p = (PushAttributes *)param; 208 p->mods->push(new StringExp(Loc(), const_cast<char *>(str))); 209 return 0; 210 } 211}; 212 213StringTable traitsStringTable; 214 215struct TraitsInitializer 216{ 217 TraitsInitializer(); 218}; 219 220static TraitsInitializer traitsinitializer; 221 222TraitsInitializer::TraitsInitializer() 223{ 224 const char* traits[] = { 225 "isAbstractClass", 226 "isArithmetic", 227 "isAssociativeArray", 228 "isFinalClass", 229 "isPOD", 230 "isNested", 231 "isFloating", 232 "isIntegral", 233 "isScalar", 234 "isStaticArray", 235 "isUnsigned", 236 "isVirtualFunction", 237 "isVirtualMethod", 238 "isAbstractFunction", 239 "isFinalFunction", 240 "isOverrideFunction", 241 "isStaticFunction", 242 "isRef", 243 "isOut", 244 "isLazy", 245 "hasMember", 246 "identifier", 247 "getProtection", 248 "parent", 249 "getLinkage", 250 "getMember", 251 "getOverloads", 252 "getVirtualFunctions", 253 "getVirtualMethods", 254 "classInstanceSize", 255 "allMembers", 256 "derivedMembers", 257 "isSame", 258 "compiles", 259 "parameters", 260 "getAliasThis", 261 "getAttributes", 262 "getFunctionAttributes", 263 "getFunctionVariadicStyle", 264 "getParameterStorageClasses", 265 "getUnitTests", 266 "getVirtualIndex", 267 "getPointerBitmap", 268 NULL 269 }; 270 271 traitsStringTable._init(40); 272 273 for (size_t idx = 0;; idx++) 274 { 275 const char *s = traits[idx]; 276 if (!s) break; 277 StringValue *sv = traitsStringTable.insert(s, strlen(s), const_cast<char *>(s)); 278 assert(sv); 279 } 280} 281 282void *trait_search_fp(void *, const char *seed, int* cost) 283{ 284 //printf("trait_search_fp('%s')\n", seed); 285 size_t len = strlen(seed); 286 if (!len) 287 return NULL; 288 289 *cost = 0; 290 StringValue *sv = traitsStringTable.lookup(seed, len); 291 return sv ? (void*)sv->ptrvalue : NULL; 292} 293 294static int fpisTemplate(void *, Dsymbol *s) 295{ 296 if (s->isTemplateDeclaration()) 297 return 1; 298 299 return 0; 300} 301 302bool isTemplate(Dsymbol *s) 303{ 304 if (!s->toAlias()->isOverloadable()) 305 return false; 306 307 return overloadApply(s, NULL, &fpisTemplate) != 0; 308} 309 310Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s)) 311{ 312 if (!e->args || !e->args->dim) 313 return False(e); 314 for (size_t i = 0; i < e->args->dim; i++) 315 { 316 Dsymbol *s = getDsymbol((*e->args)[i]); 317 if (!s || !fp(s)) 318 return False(e); 319 } 320 return True(e); 321} 322 323/** 324 * get an array of size_t values that indicate possible pointer words in memory 325 * if interpreted as the type given as argument 326 * the first array element is the size of the type for independent interpretation 327 * of the array 328 * following elements bits represent one word (4/8 bytes depending on the target 329 * architecture). If set the corresponding memory might contain a pointer/reference. 330 * 331 * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] 332 */ 333Expression *pointerBitmap(TraitsExp *e) 334{ 335 if (!e->args || e->args->dim != 1) 336 { 337 error(e->loc, "a single type expected for trait pointerBitmap"); 338 return new ErrorExp(); 339 } 340 Type *t = getType((*e->args)[0]); 341 if (!t) 342 { 343 error(e->loc, "%s is not a type", (*e->args)[0]->toChars()); 344 return new ErrorExp(); 345 } 346 d_uns64 sz; 347 if (t->ty == Tclass && !((TypeClass*)t)->sym->isInterfaceDeclaration()) 348 sz = ((TypeClass*)t)->sym->AggregateDeclaration::size(e->loc); 349 else 350 sz = t->size(e->loc); 351 if (sz == SIZE_INVALID) 352 return new ErrorExp(); 353 354 const d_uns64 sz_size_t = Type::tsize_t->size(e->loc); 355 if (sz > UINT64_MAX - sz_size_t) 356 { 357 error(e->loc, "size overflow for type %s", t->toChars()); 358 return new ErrorExp(); 359 } 360 361 d_uns64 bitsPerWord = sz_size_t * 8; 362 d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t; 363 d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; 364 Array<d_uns64> data; 365 data.setDim((size_t)cntdata); 366 data.zero(); 367 368 class PointerBitmapVisitor : public Visitor 369 { 370 public: 371 PointerBitmapVisitor(Array<d_uns64>* _data, d_uns64 _sz_size_t) 372 : data(_data), offset(0), sz_size_t(_sz_size_t), error(false) 373 {} 374 375 void setpointer(d_uns64 off) 376 { 377 d_uns64 ptroff = off / sz_size_t; 378 (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t)); 379 } 380 virtual void visit(Type *t) 381 { 382 Type *tb = t->toBasetype(); 383 if (tb != t) 384 tb->accept(this); 385 } 386 virtual void visit(TypeError *t) { visit((Type *)t); } 387 virtual void visit(TypeNext *) { assert(0); } 388 virtual void visit(TypeBasic *t) 389 { 390 if (t->ty == Tvoid) 391 setpointer(offset); 392 } 393 virtual void visit(TypeVector *) { } 394 virtual void visit(TypeArray *) { assert(0); } 395 virtual void visit(TypeSArray *t) 396 { 397 d_uns64 arrayoff = offset; 398 d_uns64 nextsize = t->next->size(); 399 if (nextsize == SIZE_INVALID) 400 error = true; 401 d_uns64 dim = t->dim->toInteger(); 402 for (d_uns64 i = 0; i < dim; i++) 403 { 404 offset = arrayoff + i * nextsize; 405 t->next->accept(this); 406 } 407 offset = arrayoff; 408 } 409 virtual void visit(TypeDArray *) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr} 410 virtual void visit(TypeAArray *) { setpointer(offset); } 411 virtual void visit(TypePointer *t) 412 { 413 if (t->nextOf()->ty != Tfunction) // don't mark function pointers 414 setpointer(offset); 415 } 416 virtual void visit(TypeReference *) { setpointer(offset); } 417 virtual void visit(TypeClass *) { setpointer(offset); } 418 virtual void visit(TypeFunction *) { } 419 virtual void visit(TypeDelegate *) { setpointer(offset); } // delegate is {context, function} 420 virtual void visit(TypeQualified *) { assert(0); } // assume resolved 421 virtual void visit(TypeIdentifier *) { assert(0); } 422 virtual void visit(TypeInstance *) { assert(0); } 423 virtual void visit(TypeTypeof *) { assert(0); } 424 virtual void visit(TypeReturn *) { assert(0); } 425 virtual void visit(TypeEnum *t) { visit((Type *)t); } 426 virtual void visit(TypeTuple *t) { visit((Type *)t); } 427 virtual void visit(TypeSlice *) { assert(0); } 428 virtual void visit(TypeNull *) { } // always a null pointer 429 430 virtual void visit(TypeStruct *t) 431 { 432 d_uns64 structoff = offset; 433 for (size_t i = 0; i < t->sym->fields.dim; i++) 434 { 435 VarDeclaration *v = t->sym->fields[i]; 436 offset = structoff + v->offset; 437 if (v->type->ty == Tclass) 438 setpointer(offset); 439 else 440 v->type->accept(this); 441 } 442 offset = structoff; 443 } 444 445 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references 446 void visitClass(TypeClass* t) 447 { 448 d_uns64 classoff = offset; 449 450 // skip vtable-ptr and monitor 451 if (t->sym->baseClass) 452 visitClass((TypeClass*)t->sym->baseClass->type); 453 454 for (size_t i = 0; i < t->sym->fields.dim; i++) 455 { 456 VarDeclaration *v = t->sym->fields[i]; 457 offset = classoff + v->offset; 458 v->type->accept(this); 459 } 460 offset = classoff; 461 } 462 463 Array<d_uns64>* data; 464 d_uns64 offset; 465 d_uns64 sz_size_t; 466 bool error; 467 }; 468 469 PointerBitmapVisitor pbv(&data, sz_size_t); 470 if (t->ty == Tclass) 471 pbv.visitClass((TypeClass*)t); 472 else 473 t->accept(&pbv); 474 if (pbv.error) 475 return new ErrorExp(); 476 477 Expressions* exps = new Expressions; 478 exps->push(new IntegerExp(e->loc, sz, Type::tsize_t)); 479 for (d_uns64 i = 0; i < cntdata; i++) 480 exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t)); 481 482 ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, Type::tsize_t->sarrayOf(cntdata + 1), exps); 483 return ale; 484} 485 486static Expression *dimError(TraitsExp *e, int expected, int dim) 487{ 488 e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim); 489 return new ErrorExp(); 490} 491 492Expression *semanticTraits(TraitsExp *e, Scope *sc) 493{ 494 if (e->ident != Id::compiles && e->ident != Id::isSame && 495 e->ident != Id::identifier && e->ident != Id::getProtection) 496 { 497 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) 498 return new ErrorExp(); 499 } 500 size_t dim = e->args ? e->args->dim : 0; 501 502 if (e->ident == Id::isArithmetic) 503 { 504 return isTypeX(e, &isTypeArithmetic); 505 } 506 else if (e->ident == Id::isFloating) 507 { 508 return isTypeX(e, &isTypeFloating); 509 } 510 else if (e->ident == Id::isIntegral) 511 { 512 return isTypeX(e, &isTypeIntegral); 513 } 514 else if (e->ident == Id::isScalar) 515 { 516 return isTypeX(e, &isTypeScalar); 517 } 518 else if (e->ident == Id::isUnsigned) 519 { 520 return isTypeX(e, &isTypeUnsigned); 521 } 522 else if (e->ident == Id::isAssociativeArray) 523 { 524 return isTypeX(e, &isTypeAssociativeArray); 525 } 526 else if (e->ident == Id::isStaticArray) 527 { 528 return isTypeX(e, &isTypeStaticArray); 529 } 530 else if (e->ident == Id::isAbstractClass) 531 { 532 return isTypeX(e, &isTypeAbstractClass); 533 } 534 else if (e->ident == Id::isFinalClass) 535 { 536 return isTypeX(e, &isTypeFinalClass); 537 } 538 else if (e->ident == Id::isTemplate) 539 { 540 return isSymbolX(e, &isTemplate); 541 } 542 else if (e->ident == Id::isPOD) 543 { 544 if (dim != 1) 545 return dimError(e, 1, dim); 546 547 RootObject *o = (*e->args)[0]; 548 Type *t = isType(o); 549 if (!t) 550 { 551 e->error("type expected as second argument of __traits %s instead of %s", 552 e->ident->toChars(), o->toChars()); 553 return new ErrorExp(); 554 } 555 556 Type *tb = t->baseElemOf(); 557 if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL) 558 { 559 return (sd->isPOD()) ? True(e) : False(e); 560 } 561 return True(e); 562 } 563 else if (e->ident == Id::isNested) 564 { 565 if (dim != 1) 566 return dimError(e, 1, dim); 567 568 RootObject *o = (*e->args)[0]; 569 Dsymbol *s = getDsymbol(o); 570 if (!s) 571 { 572 } 573 else if (AggregateDeclaration *a = s->isAggregateDeclaration()) 574 { 575 return a->isNested() ? True(e) : False(e); 576 } 577 else if (FuncDeclaration *f = s->isFuncDeclaration()) 578 { 579 return f->isNested() ? True(e) : False(e); 580 } 581 582 e->error("aggregate or function expected instead of '%s'", o->toChars()); 583 return new ErrorExp(); 584 } 585 else if (e->ident == Id::isAbstractFunction) 586 { 587 return isFuncX(e, &isFuncAbstractFunction); 588 } 589 else if (e->ident == Id::isVirtualFunction) 590 { 591 return isFuncX(e, &isFuncVirtualFunction); 592 } 593 else if (e->ident == Id::isVirtualMethod) 594 { 595 return isFuncX(e, &isFuncVirtualMethod); 596 } 597 else if (e->ident == Id::isFinalFunction) 598 { 599 return isFuncX(e, &isFuncFinalFunction); 600 } 601 else if (e->ident == Id::isOverrideFunction) 602 { 603 return isFuncX(e, &isFuncOverrideFunction); 604 } 605 else if (e->ident == Id::isStaticFunction) 606 { 607 return isFuncX(e, &isFuncStaticFunction); 608 } 609 else if (e->ident == Id::isRef) 610 { 611 return isDeclX(e, &isDeclRef); 612 } 613 else if (e->ident == Id::isOut) 614 { 615 return isDeclX(e, &isDeclOut); 616 } 617 else if (e->ident == Id::isLazy) 618 { 619 return isDeclX(e, &isDeclLazy); 620 } 621 else if (e->ident == Id::identifier) 622 { 623 // Get identifier for symbol as a string literal 624 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that 625 * a symbol should not be folded to a constant. 626 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier 627 */ 628 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2)) 629 return new ErrorExp(); 630 if (dim != 1) 631 return dimError(e, 1, dim); 632 633 RootObject *o = (*e->args)[0]; 634 Identifier *id = NULL; 635 if (Parameter *po = isParameter(o)) 636 { 637 id = po->ident; 638 assert(id); 639 } 640 else 641 { 642 Dsymbol *s = getDsymbol(o); 643 if (!s || !s->ident) 644 { 645 e->error("argument %s has no identifier", o->toChars()); 646 return new ErrorExp(); 647 } 648 id = s->ident; 649 } 650 651 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); 652 return semantic(se, sc); 653 } 654 else if (e->ident == Id::getProtection) 655 { 656 if (dim != 1) 657 return dimError(e, 1, dim); 658 659 Scope *sc2 = sc->push(); 660 sc2->flags = sc->flags | SCOPEnoaccesscheck; 661 bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1); 662 sc2->pop(); 663 if (!ok) 664 return new ErrorExp(); 665 666 RootObject *o = (*e->args)[0]; 667 Dsymbol *s = getDsymbol(o); 668 if (!s) 669 { 670 if (!isError(o)) 671 e->error("argument %s has no protection", o->toChars()); 672 return new ErrorExp(); 673 } 674 if (s->semanticRun == PASSinit) 675 s->semantic(NULL); 676 677 const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names) 678 assert(protName); 679 StringExp *se = new StringExp(e->loc, const_cast<char *>(protName)); 680 return semantic(se, sc); 681 } 682 else if (e->ident == Id::parent) 683 { 684 if (dim != 1) 685 return dimError(e, 1, dim); 686 687 RootObject *o = (*e->args)[0]; 688 Dsymbol *s = getDsymbol(o); 689 if (s) 690 { 691 if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 692 s = fd->toAliasFunc(); 693 if (!s->isImport()) // Bugzilla 8922 694 s = s->toParent(); 695 } 696 if (!s || s->isImport()) 697 { 698 e->error("argument %s has no parent", o->toChars()); 699 return new ErrorExp(); 700 } 701 702 if (FuncDeclaration *f = s->isFuncDeclaration()) 703 { 704 if (TemplateDeclaration *td = getFuncTemplateDecl(f)) 705 { 706 if (td->overroot) // if not start of overloaded list of TemplateDeclaration's 707 td = td->overroot; // then get the start 708 Expression *ex = new TemplateExp(e->loc, td, f); 709 ex = semantic(ex, sc); 710 return ex; 711 } 712 713 if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration()) 714 { 715 // Directly translate to VarExp instead of FuncExp 716 Expression *ex = new VarExp(e->loc, fld, true); 717 return semantic(ex, sc); 718 } 719 } 720 721 return resolve(e->loc, sc, s, false); 722 } 723 else if (e->ident == Id::hasMember || 724 e->ident == Id::getMember || 725 e->ident == Id::getOverloads || 726 e->ident == Id::getVirtualMethods || 727 e->ident == Id::getVirtualFunctions) 728 { 729 if (dim != 2) 730 return dimError(e, 2, dim); 731 732 RootObject *o = (*e->args)[0]; 733 Expression *ex = isExpression((*e->args)[1]); 734 if (!ex) 735 { 736 e->error("expression expected as second argument of __traits %s", e->ident->toChars()); 737 return new ErrorExp(); 738 } 739 ex = ex->ctfeInterpret(); 740 741 StringExp *se = ex->toStringExp(); 742 if (!se || se->len == 0) 743 { 744 e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars()); 745 return new ErrorExp(); 746 } 747 se = se->toUTF8(sc); 748 749 if (se->sz != 1) 750 { 751 e->error("string must be chars"); 752 return new ErrorExp(); 753 } 754 Identifier *id = Identifier::idPool((char *)se->string, se->len); 755 756 /* Prefer dsymbol, because it might need some runtime contexts. 757 */ 758 Dsymbol *sym = getDsymbol(o); 759 if (sym) 760 { 761 ex = new DsymbolExp(e->loc, sym); 762 ex = new DotIdExp(e->loc, ex, id); 763 } 764 else if (Type *t = isType(o)) 765 ex = typeDotIdExp(e->loc, t, id); 766 else if (Expression *ex2 = isExpression(o)) 767 ex = new DotIdExp(e->loc, ex2, id); 768 else 769 { 770 e->error("invalid first argument"); 771 return new ErrorExp(); 772 } 773 774 if (e->ident == Id::hasMember) 775 { 776 if (sym) 777 { 778 if (sym->search(e->loc, id)) 779 return True(e); 780 } 781 782 /* Take any errors as meaning it wasn't found 783 */ 784 Scope *scx = sc->push(); 785 scx->flags |= SCOPEignoresymbolvisibility; 786 ex = trySemantic(ex, scx); 787 scx->pop(); 788 return ex ? True(e) : False(e); 789 } 790 else if (e->ident == Id::getMember) 791 { 792 if (ex->op == TOKdotid) 793 // Prevent semantic() from replacing Symbol with its initializer 794 ((DotIdExp *)ex)->wantsym = true; 795 Scope *scx = sc->push(); 796 scx->flags |= SCOPEignoresymbolvisibility; 797 ex = semantic(ex, scx); 798 scx->pop(); 799 return ex; 800 } 801 else if (e->ident == Id::getVirtualFunctions || 802 e->ident == Id::getVirtualMethods || 803 e->ident == Id::getOverloads) 804 { 805 unsigned errors = global.errors; 806 Expression *eorig = ex; 807 Scope *scx = sc->push(); 808 scx->flags |= SCOPEignoresymbolvisibility; 809 ex = semantic(ex, scx); 810 if (errors < global.errors) 811 e->error("%s cannot be resolved", eorig->toChars()); 812 //ex->print(); 813 814 /* Create tuple of functions of ex 815 */ 816 Expressions *exps = new Expressions(); 817 FuncDeclaration *f; 818 if (ex->op == TOKvar) 819 { 820 VarExp *ve = (VarExp *)ex; 821 f = ve->var->isFuncDeclaration(); 822 ex = NULL; 823 } 824 else if (ex->op == TOKdotvar) 825 { 826 DotVarExp *dve = (DotVarExp *)ex; 827 f = dve->var->isFuncDeclaration(); 828 if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis) 829 ex = NULL; 830 else 831 ex = dve->e1; 832 } 833 else 834 f = NULL; 835 Ptrait p; 836 p.exps = exps; 837 p.e1 = ex; 838 p.ident = e->ident; 839 overloadApply(f, &p, &fptraits); 840 841 ex = new TupleExp(e->loc, exps); 842 ex = semantic(ex, scx); 843 scx->pop(); 844 return ex; 845 } 846 else 847 assert(0); 848 } 849 else if (e->ident == Id::classInstanceSize) 850 { 851 if (dim != 1) 852 return dimError(e, 1, dim); 853 854 RootObject *o = (*e->args)[0]; 855 Dsymbol *s = getDsymbol(o); 856 ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL; 857 if (!cd) 858 { 859 e->error("first argument is not a class"); 860 return new ErrorExp(); 861 } 862 if (cd->sizeok != SIZEOKdone) 863 { 864 cd->size(cd->loc); 865 } 866 if (cd->sizeok != SIZEOKdone) 867 { 868 e->error("%s %s is forward referenced", cd->kind(), cd->toChars()); 869 return new ErrorExp(); 870 } 871 872 return new IntegerExp(e->loc, cd->structsize, Type::tsize_t); 873 } 874 else if (e->ident == Id::getAliasThis) 875 { 876 if (dim != 1) 877 return dimError(e, 1, dim); 878 879 RootObject *o = (*e->args)[0]; 880 Dsymbol *s = getDsymbol(o); 881 AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL; 882 if (!ad) 883 { 884 e->error("argument is not an aggregate type"); 885 return new ErrorExp(); 886 } 887 888 Expressions *exps = new Expressions(); 889 if (ad->aliasthis) 890 exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars()))); 891 Expression *ex = new TupleExp(e->loc, exps); 892 ex = semantic(ex, sc); 893 return ex; 894 } 895 else if (e->ident == Id::getAttributes) 896 { 897 if (dim != 1) 898 return dimError(e, 1, dim); 899 900 RootObject *o = (*e->args)[0]; 901 Dsymbol *s = getDsymbol(o); 902 if (!s) 903 { 904 e->error("first argument is not a symbol"); 905 return new ErrorExp(); 906 } 907 if (Import *imp = s->isImport()) 908 { 909 s = imp->mod; 910 } 911 912 //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope); 913 UserAttributeDeclaration *udad = s->userAttribDecl; 914 Expressions *exps = udad ? udad->getAttributes() : new Expressions(); 915 TupleExp *tup = new TupleExp(e->loc, exps); 916 return semantic(tup, sc); 917 } 918 else if (e->ident == Id::getFunctionAttributes) 919 { 920 /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs. 921 if (dim != 1) 922 return dimError(e, 1, dim); 923 924 RootObject *o = (*e->args)[0]; 925 Dsymbol *s = getDsymbol(o); 926 Type *t = isType(o); 927 TypeFunction *tf = NULL; 928 if (s) 929 { 930 if (FuncDeclaration *f = s->isFuncDeclaration()) 931 t = f->type; 932 else if (VarDeclaration *v = s->isVarDeclaration()) 933 t = v->type; 934 } 935 if (t) 936 { 937 if (t->ty == Tfunction) 938 tf = (TypeFunction *)t; 939 else if (t->ty == Tdelegate) 940 tf = (TypeFunction *)t->nextOf(); 941 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) 942 tf = (TypeFunction *)t->nextOf(); 943 } 944 if (!tf) 945 { 946 e->error("first argument is not a function"); 947 return new ErrorExp(); 948 } 949 950 Expressions *mods = new Expressions(); 951 PushAttributes pa; 952 pa.mods = mods; 953 tf->modifiersApply(&pa, &PushAttributes::fp); 954 tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem); 955 956 TupleExp *tup = new TupleExp(e->loc, mods); 957 return semantic(tup, sc); 958 } 959 else if (e->ident == Id::getFunctionVariadicStyle) 960 { 961 /* Accept a symbol or a type. Returns one of the following: 962 * "none" not a variadic function 963 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments` 964 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg 965 * "typesafe" void typesafe(T[] ...) 966 */ 967 // get symbol linkage as a string 968 if (dim != 1) 969 return dimError(e, 1, dim); 970 971 LINK link; 972 int varargs; 973 RootObject *o = (*e->args)[0]; 974 Type *t = isType(o); 975 TypeFunction *tf = NULL; 976 if (t) 977 { 978 if (t->ty == Tfunction) 979 tf = (TypeFunction *)t; 980 else if (t->ty == Tdelegate) 981 tf = (TypeFunction *)t->nextOf(); 982 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) 983 tf = (TypeFunction *)t->nextOf(); 984 } 985 if (tf) 986 { 987 link = tf->linkage; 988 varargs = tf->varargs; 989 } 990 else 991 { 992 Dsymbol *s = getDsymbol(o); 993 FuncDeclaration *fd = NULL; 994 if (!s || (fd = s->isFuncDeclaration()) == NULL) 995 { 996 e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars()); 997 return new ErrorExp(); 998 } 999 link = fd->linkage; 1000 fd->getParameters(&varargs); 1001 } 1002 const char *style; 1003 switch (varargs) 1004 { 1005 case 0: style = "none"; break; 1006 case 1: style = (link == LINKd) ? "argptr" 1007 : "stdarg"; break; 1008 case 2: style = "typesafe"; break; 1009 default: 1010 assert(0); 1011 } 1012 StringExp *se = new StringExp(e->loc, const_cast<char*>(style)); 1013 return semantic(se, sc); 1014 } 1015 else if (e->ident == Id::getParameterStorageClasses) 1016 { 1017 /* Accept a function symbol or a type, followed by a parameter index. 1018 * Returns a tuple of strings of the parameter's storage classes. 1019 */ 1020 // get symbol linkage as a string 1021 if (dim != 2) 1022 return dimError(e, 2, dim); 1023 1024 RootObject *o1 = (*e->args)[1]; 1025 RootObject *o = (*e->args)[0]; 1026 Type *t = isType(o); 1027 TypeFunction *tf = NULL; 1028 if (t) 1029 { 1030 if (t->ty == Tfunction) 1031 tf = (TypeFunction *)t; 1032 else if (t->ty == Tdelegate) 1033 tf = (TypeFunction *)t->nextOf(); 1034 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) 1035 tf = (TypeFunction *)t->nextOf(); 1036 } 1037 Parameters* fparams; 1038 if (tf) 1039 { 1040 fparams = tf->parameters; 1041 } 1042 else 1043 { 1044 Dsymbol *s = getDsymbol(o); 1045 FuncDeclaration *fd = NULL; 1046 if (!s || (fd = s->isFuncDeclaration()) == NULL) 1047 { 1048 e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", 1049 o->toChars(), o1->toChars()); 1050 return new ErrorExp(); 1051 } 1052 fparams = fd->getParameters(NULL); 1053 } 1054 1055 StorageClass stc; 1056 1057 // Set stc to storage class of the ith parameter 1058 Expression *ex = isExpression((*e->args)[1]); 1059 if (!ex) 1060 { 1061 e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`", 1062 o->toChars(), o1->toChars()); 1063 return new ErrorExp(); 1064 } 1065 ex = ex->ctfeInterpret(); 1066 uinteger_t ii = ex->toUInteger(); 1067 if (ii >= Parameter::dim(fparams)) 1068 { 1069 e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars()); 1070 return new ErrorExp(); 1071 } 1072 1073 unsigned n = (unsigned)ii; 1074 Parameter *p = Parameter::getNth(fparams, n); 1075 stc = p->storageClass; 1076 1077 // This mirrors hdrgen.visit(Parameter p) 1078 if (p->type && p->type->mod & MODshared) 1079 stc &= ~STCshared; 1080 1081 Expressions *exps = new Expressions; 1082 1083 if (stc & STCauto) 1084 exps->push(new StringExp(e->loc, const_cast<char *>("auto"))); 1085 if (stc & STCreturn) 1086 exps->push(new StringExp(e->loc, const_cast<char *>("return"))); 1087 1088 if (stc & STCout) 1089 exps->push(new StringExp(e->loc, const_cast<char *>("out"))); 1090 else if (stc & STCref) 1091 exps->push(new StringExp(e->loc, const_cast<char *>("ref"))); 1092 else if (stc & STCin) 1093 exps->push(new StringExp(e->loc, const_cast<char *>("in"))); 1094 else if (stc & STClazy) 1095 exps->push(new StringExp(e->loc, const_cast<char *>("lazy"))); 1096 else if (stc & STCalias) 1097 exps->push(new StringExp(e->loc, const_cast<char *>("alias"))); 1098 1099 if (stc & STCconst) 1100 exps->push(new StringExp(e->loc, const_cast<char *>("const"))); 1101 if (stc & STCimmutable) 1102 exps->push(new StringExp(e->loc, const_cast<char *>("immutable"))); 1103 if (stc & STCwild) 1104 exps->push(new StringExp(e->loc, const_cast<char *>("inout"))); 1105 if (stc & STCshared) 1106 exps->push(new StringExp(e->loc, const_cast<char *>("shared"))); 1107 if (stc & STCscope && !(stc & STCscopeinferred)) 1108 exps->push(new StringExp(e->loc, const_cast<char *>("scope"))); 1109 1110 TupleExp *tup = new TupleExp(e->loc, exps); 1111 return semantic(tup, sc); 1112 } 1113 else if (e->ident == Id::getLinkage) 1114 { 1115 // get symbol linkage as a string 1116 if (dim != 1) 1117 return dimError(e, 1, dim); 1118 1119 LINK link; 1120 RootObject *o = (*e->args)[0]; 1121 Type *t = isType(o); 1122 TypeFunction *tf = NULL; 1123 if (t) 1124 { 1125 if (t->ty == Tfunction) 1126 tf = (TypeFunction *)t; 1127 else if (t->ty == Tdelegate) 1128 tf = (TypeFunction *)t->nextOf(); 1129 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction) 1130 tf = (TypeFunction *)t->nextOf(); 1131 } 1132 if (tf) 1133 link = tf->linkage; 1134 else 1135 { 1136 Dsymbol *s = getDsymbol(o); 1137 Declaration *d = NULL; 1138 AggregateDeclaration *ad = NULL; 1139 if (!s || ((d = s->isDeclaration()) == NULL 1140 && (ad = s->isAggregateDeclaration()) == NULL)) 1141 { 1142 e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars()); 1143 return new ErrorExp(); 1144 } 1145 if (d != NULL) 1146 link = d->linkage; 1147 else 1148 { 1149 switch (ad->classKind) 1150 { 1151 case ClassKind::d: 1152 link = LINKd; 1153 break; 1154 case ClassKind::cpp: 1155 link = LINKcpp; 1156 break; 1157 case ClassKind::objc: 1158 link = LINKobjc; 1159 break; 1160 default: 1161 assert(0); 1162 } 1163 } 1164 } 1165 const char *linkage = linkageToChars(link); 1166 StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage)); 1167 return semantic(se, sc); 1168 } 1169 else if (e->ident == Id::allMembers || 1170 e->ident == Id::derivedMembers) 1171 { 1172 if (dim != 1) 1173 return dimError(e, 1, dim); 1174 1175 RootObject *o = (*e->args)[0]; 1176 Dsymbol *s = getDsymbol(o); 1177 if (!s) 1178 { 1179 e->error("argument has no members"); 1180 return new ErrorExp(); 1181 } 1182 if (Import *imp = s->isImport()) 1183 { 1184 // Bugzilla 9692 1185 s = imp->mod; 1186 } 1187 1188 ScopeDsymbol *sds = s->isScopeDsymbol(); 1189 if (!sds || sds->isTemplateDeclaration()) 1190 { 1191 e->error("%s %s has no members", s->kind(), s->toChars()); 1192 return new ErrorExp(); 1193 } 1194 1195 // use a struct as local function 1196 struct PushIdentsDg 1197 { 1198 ScopeDsymbol *sds; 1199 Identifiers *idents; 1200 1201 static int dg(void *ctx, size_t, Dsymbol *sm) 1202 { 1203 if (!sm) 1204 return 1; 1205 1206 // skip local symbols, such as static foreach loop variables 1207 if (Declaration *decl = sm->isDeclaration()) 1208 { 1209 if (decl->storage_class & STClocal) 1210 { 1211 return 0; 1212 } 1213 } 1214 1215 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); 1216 if (sm->ident) 1217 { 1218 // https://issues.dlang.org/show_bug.cgi?id=10096 1219 // https://issues.dlang.org/show_bug.cgi?id=10100 1220 // Skip over internal members in __traits(allMembers) 1221 if ((sm->isCtorDeclaration() && sm->ident != Id::ctor) || 1222 (sm->isDtorDeclaration() && sm->ident != Id::dtor) || 1223 (sm->isPostBlitDeclaration() && sm->ident != Id::postblit) || 1224 sm->isInvariantDeclaration() || 1225 sm->isUnitTestDeclaration()) 1226 { 1227 return 0; 1228 } 1229 1230 if (sm->ident == Id::empty) 1231 { 1232 return 0; 1233 } 1234 if (sm->isTypeInfoDeclaration()) // Bugzilla 15177 1235 return 0; 1236 PushIdentsDg *pid = (PushIdentsDg *)ctx; 1237 if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057 1238 return 0; 1239 1240 //printf("\t%s\n", sm->ident->toChars()); 1241 Identifiers *idents = pid->idents; 1242 1243 /* Skip if already present in idents[] 1244 */ 1245 for (size_t j = 0; j < idents->dim; j++) 1246 { 1247 Identifier *id = (*idents)[j]; 1248 if (id == sm->ident) 1249 return 0; 1250 } 1251 1252 idents->push(sm->ident); 1253 } 1254 else 1255 { 1256 EnumDeclaration *ed = sm->isEnumDeclaration(); 1257 if (ed) 1258 { 1259 ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx); 1260 } 1261 } 1262 return 0; 1263 } 1264 }; 1265 1266 Identifiers *idents = new Identifiers; 1267 PushIdentsDg ctx; 1268 ctx.sds = sds; 1269 ctx.idents = idents; 1270 ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx); 1271 ClassDeclaration *cd = sds->isClassDeclaration(); 1272 if (cd && e->ident == Id::allMembers) 1273 { 1274 if (cd->semanticRun < PASSsemanticdone) 1275 cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference 1276 1277 struct PushBaseMembers 1278 { 1279 static void dg(ClassDeclaration *cd, PushIdentsDg *ctx) 1280 { 1281 for (size_t i = 0; i < cd->baseclasses->dim; i++) 1282 { 1283 ClassDeclaration *cb = (*cd->baseclasses)[i]->sym; 1284 assert(cb); 1285 ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx); 1286 if (cb->baseclasses->dim) 1287 dg(cb, ctx); 1288 } 1289 } 1290 }; 1291 PushBaseMembers::dg(cd, &ctx); 1292 } 1293 1294 // Turn Identifiers into StringExps reusing the allocated array 1295 assert(sizeof(Expressions) == sizeof(Identifiers)); 1296 Expressions *exps = (Expressions *)idents; 1297 for (size_t i = 0; i < idents->dim; i++) 1298 { 1299 Identifier *id = (*idents)[i]; 1300 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); 1301 (*exps)[i] = se; 1302 } 1303 1304 /* Making this a tuple is more flexible, as it can be statically unrolled. 1305 * To make an array literal, enclose __traits in [ ]: 1306 * [ __traits(allMembers, ...) ] 1307 */ 1308 Expression *ex = new TupleExp(e->loc, exps); 1309 ex = semantic(ex, sc); 1310 return ex; 1311 } 1312 else if (e->ident == Id::compiles) 1313 { 1314 /* Determine if all the objects - types, expressions, or symbols - 1315 * compile without error 1316 */ 1317 if (!dim) 1318 return False(e); 1319 1320 for (size_t i = 0; i < dim; i++) 1321 { 1322 unsigned errors = global.startGagging(); 1323 Scope *sc2 = sc->push(); 1324 sc2->tinst = NULL; 1325 sc2->minst = NULL; 1326 sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst; 1327 bool err = false; 1328 1329 RootObject *o = (*e->args)[i]; 1330 Type *t = isType(o); 1331 Expression *ex = t ? typeToExpression(t) : isExpression(o); 1332 if (!ex && t) 1333 { 1334 Dsymbol *s; 1335 t->resolve(e->loc, sc2, &ex, &t, &s); 1336 if (t) 1337 { 1338 t->semantic(e->loc, sc2); 1339 if (t->ty == Terror) 1340 err = true; 1341 } 1342 else if (s && s->errors) 1343 err = true; 1344 } 1345 if (ex) 1346 { 1347 ex = semantic(ex, sc2); 1348 ex = resolvePropertiesOnly(sc2, ex); 1349 ex = ex->optimize(WANTvalue); 1350 if (sc2->func && sc2->func->type->ty == Tfunction) 1351 { 1352 TypeFunction *tf = (TypeFunction *)sc2->func->type; 1353 canThrow(ex, sc2->func, tf->isnothrow); 1354 } 1355 ex = checkGC(sc2, ex); 1356 if (ex->op == TOKerror) 1357 err = true; 1358 } 1359 1360 // Carefully detach the scope from the parent and throw it away as 1361 // we only need it to evaluate the expression 1362 // https://issues.dlang.org/show_bug.cgi?id=15428 1363 freeFieldinit(sc2); 1364 sc2->enclosing = NULL; 1365 sc2->pop(); 1366 1367 if (global.endGagging(errors) || err) 1368 { 1369 return False(e); 1370 } 1371 } 1372 return True(e); 1373 } 1374 else if (e->ident == Id::isSame) 1375 { 1376 /* Determine if two symbols are the same 1377 */ 1378 if (dim != 2) 1379 return dimError(e, 2, dim); 1380 1381 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0)) 1382 return new ErrorExp(); 1383 1384 RootObject *o1 = (*e->args)[0]; 1385 RootObject *o2 = (*e->args)[1]; 1386 1387 // issue 12001, allow isSame, <BasicType>, <BasicType> 1388 Type *t1 = isType(o1); 1389 Type *t2 = isType(o2); 1390 if (t1 && t2 && t1->equals(t2)) 1391 return True(e); 1392 1393 Dsymbol *s1 = getDsymbol(o1); 1394 Dsymbol *s2 = getDsymbol(o2); 1395 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); 1396 if (!s1 && !s2) 1397 { 1398 Expression *ea1 = isExpression(o1); 1399 Expression *ea2 = isExpression(o2); 1400 if (ea1 && ea2) 1401 { 1402 if (ea1->equals(ea2)) 1403 return True(e); 1404 } 1405 } 1406 if (!s1 || !s2) 1407 return False(e); 1408 s1 = s1->toAlias(); 1409 s2 = s2->toAlias(); 1410 1411 if (s1->isFuncAliasDeclaration()) 1412 s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); 1413 if (s2->isFuncAliasDeclaration()) 1414 s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); 1415 1416 return (s1 == s2) ? True(e) : False(e); 1417 } 1418 else if (e->ident == Id::getUnitTests) 1419 { 1420 if (dim != 1) 1421 return dimError(e, 1, dim); 1422 1423 RootObject *o = (*e->args)[0]; 1424 Dsymbol *s = getDsymbol(o); 1425 if (!s) 1426 { 1427 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", 1428 o->toChars()); 1429 return new ErrorExp(); 1430 } 1431 if (Import *imp = s->isImport()) // Bugzilla 10990 1432 s = imp->mod; 1433 1434 ScopeDsymbol* sds = s->isScopeDsymbol(); 1435 if (!sds) 1436 { 1437 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s", 1438 s->toChars(), s->kind()); 1439 return new ErrorExp(); 1440 } 1441 1442 Expressions *exps = new Expressions(); 1443 if (global.params.useUnitTests) 1444 { 1445 // Should actually be a set 1446 AA* uniqueUnitTests = NULL; 1447 collectUnitTests(sds->members, uniqueUnitTests, exps); 1448 } 1449 TupleExp *te= new TupleExp(e->loc, exps); 1450 return semantic(te, sc); 1451 } 1452 else if (e->ident == Id::getVirtualIndex) 1453 { 1454 if (dim != 1) 1455 return dimError(e, 1, dim); 1456 1457 RootObject *o = (*e->args)[0]; 1458 Dsymbol *s = getDsymbol(o); 1459 1460 FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; 1461 if (!fd) 1462 { 1463 e->error("first argument to __traits(getVirtualIndex) must be a function"); 1464 return new ErrorExp(); 1465 } 1466 1467 fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. 1468 return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t); 1469 } 1470 else if (e->ident == Id::getPointerBitmap) 1471 { 1472 return pointerBitmap(e); 1473 } 1474 1475 if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars)) 1476 e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub); 1477 else 1478 e->error("unrecognized trait '%s'", e->ident->toChars()); 1479 return new ErrorExp(); 1480 1481 e->error("wrong number of arguments %d", (int)dim); 1482 return new ErrorExp(); 1483} 1484