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
36 typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s);
37 int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL);
38 void freeFieldinit(Scope *sc);
39 Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
40 Expression *trySemantic(Expression *e, Scope *sc);
41 Expression *semantic(Expression *e, Scope *sc);
42 Expression *typeToExpression(Type *t);
43
44
45 /************************************************
46 * Delegate to be passed to overloadApply() that looks
47 * for functions matching a trait.
48 */
49
50 struct Ptrait
51 {
52 Expression *e1;
53 Expressions *exps; // collected results
54 Identifier *ident; // which trait we're looking for
55 };
56
fptraits(void * param,Dsymbol * s)57 static 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 */
collectUnitTests(Dsymbols * symbols,AA * uniqueUnitTests,Expressions * unitTests)96 static 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
True(TraitsExp * e)131 static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); }
False(TraitsExp * e)132 static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); }
133
isTypeArithmetic(Type * t)134 bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); }
isTypeFloating(Type * t)135 bool isTypeFloating(Type *t) { return t->isfloating(); }
isTypeIntegral(Type * t)136 bool isTypeIntegral(Type *t) { return t->isintegral(); }
isTypeScalar(Type * t)137 bool isTypeScalar(Type *t) { return t->isscalar(); }
isTypeUnsigned(Type * t)138 bool isTypeUnsigned(Type *t) { return t->isunsigned(); }
isTypeAssociativeArray(Type * t)139 bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; }
isTypeStaticArray(Type * t)140 bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; }
isTypeAbstractClass(Type * t)141 bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); }
isTypeFinalClass(Type * t)142 bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; }
143
isTypeX(TraitsExp * e,bool (* fp)(Type * t))144 Expression *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
isFuncAbstractFunction(FuncDeclaration * f)157 bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); }
isFuncVirtualFunction(FuncDeclaration * f)158 bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); }
isFuncVirtualMethod(FuncDeclaration * f)159 bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); }
isFuncFinalFunction(FuncDeclaration * f)160 bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); }
isFuncStaticFunction(FuncDeclaration * f)161 bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); }
isFuncOverrideFunction(FuncDeclaration * f)162 bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); }
163
isFuncX(TraitsExp * e,bool (* fp)(FuncDeclaration * f))164 Expression *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
isDeclRef(Declaration * d)180 bool isDeclRef(Declaration *d) { return d->isRef(); }
isDeclOut(Declaration * d)181 bool isDeclOut(Declaration *d) { return d->isOut(); }
isDeclLazy(Declaration * d)182 bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; }
183
isDeclX(TraitsExp * e,bool (* fp)(Declaration * d))184 Expression *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
201 struct PushAttributes
202 {
203 Expressions *mods;
204
fpPushAttributes205 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
213 StringTable traitsStringTable;
214
215 struct TraitsInitializer
216 {
217 TraitsInitializer();
218 };
219
220 static TraitsInitializer traitsinitializer;
221
TraitsInitializer()222 TraitsInitializer::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
trait_search_fp(void *,const char * seed,int * cost)282 void *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
fpisTemplate(void *,Dsymbol * s)294 static int fpisTemplate(void *, Dsymbol *s)
295 {
296 if (s->isTemplateDeclaration())
297 return 1;
298
299 return 0;
300 }
301
isTemplate(Dsymbol * s)302 bool isTemplate(Dsymbol *s)
303 {
304 if (!s->toAlias()->isOverloadable())
305 return false;
306
307 return overloadApply(s, NULL, &fpisTemplate) != 0;
308 }
309
isSymbolX(TraitsExp * e,bool (* fp)(Dsymbol * s))310 Expression *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 */
pointerBitmap(TraitsExp * e)333 Expression *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
dimError(TraitsExp * e,int expected,int dim)486 static 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
semanticTraits(TraitsExp * e,Scope * sc)492 Expression *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->_scope)
675 s->semantic(s->_scope);
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 if (!s || (d = s->isDeclaration()) == NULL)
1139 {
1140 e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
1141 return new ErrorExp();
1142 }
1143 link = d->linkage;
1144 }
1145 const char *linkage = linkageToChars(link);
1146 StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
1147 return semantic(se, sc);
1148 }
1149 else if (e->ident == Id::allMembers ||
1150 e->ident == Id::derivedMembers)
1151 {
1152 if (dim != 1)
1153 return dimError(e, 1, dim);
1154
1155 RootObject *o = (*e->args)[0];
1156 Dsymbol *s = getDsymbol(o);
1157 if (!s)
1158 {
1159 e->error("argument has no members");
1160 return new ErrorExp();
1161 }
1162 if (Import *imp = s->isImport())
1163 {
1164 // Bugzilla 9692
1165 s = imp->mod;
1166 }
1167
1168 ScopeDsymbol *sds = s->isScopeDsymbol();
1169 if (!sds || sds->isTemplateDeclaration())
1170 {
1171 e->error("%s %s has no members", s->kind(), s->toChars());
1172 return new ErrorExp();
1173 }
1174
1175 // use a struct as local function
1176 struct PushIdentsDg
1177 {
1178 ScopeDsymbol *sds;
1179 Identifiers *idents;
1180
1181 static int dg(void *ctx, size_t, Dsymbol *sm)
1182 {
1183 if (!sm)
1184 return 1;
1185 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
1186 if (sm->ident)
1187 {
1188 const char *idx = sm->ident->toChars();
1189 if (idx[0] == '_' && idx[1] == '_' &&
1190 sm->ident != Id::ctor &&
1191 sm->ident != Id::dtor &&
1192 sm->ident != Id::__xdtor &&
1193 sm->ident != Id::postblit &&
1194 sm->ident != Id::__xpostblit)
1195 {
1196 return 0;
1197 }
1198
1199 if (sm->ident == Id::empty)
1200 {
1201 return 0;
1202 }
1203 if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
1204 return 0;
1205 PushIdentsDg *pid = (PushIdentsDg *)ctx;
1206 if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057
1207 return 0;
1208
1209 //printf("\t%s\n", sm->ident->toChars());
1210 Identifiers *idents = pid->idents;
1211
1212 /* Skip if already present in idents[]
1213 */
1214 for (size_t j = 0; j < idents->dim; j++)
1215 {
1216 Identifier *id = (*idents)[j];
1217 if (id == sm->ident)
1218 return 0;
1219 }
1220
1221 idents->push(sm->ident);
1222 }
1223 else
1224 {
1225 EnumDeclaration *ed = sm->isEnumDeclaration();
1226 if (ed)
1227 {
1228 ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx);
1229 }
1230 }
1231 return 0;
1232 }
1233 };
1234
1235 Identifiers *idents = new Identifiers;
1236 PushIdentsDg ctx;
1237 ctx.sds = sds;
1238 ctx.idents = idents;
1239 ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx);
1240 ClassDeclaration *cd = sds->isClassDeclaration();
1241 if (cd && e->ident == Id::allMembers)
1242 {
1243 if (cd->_scope)
1244 cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference
1245
1246 struct PushBaseMembers
1247 {
1248 static void dg(ClassDeclaration *cd, PushIdentsDg *ctx)
1249 {
1250 for (size_t i = 0; i < cd->baseclasses->dim; i++)
1251 {
1252 ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
1253 assert(cb);
1254 ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx);
1255 if (cb->baseclasses->dim)
1256 dg(cb, ctx);
1257 }
1258 }
1259 };
1260 PushBaseMembers::dg(cd, &ctx);
1261 }
1262
1263 // Turn Identifiers into StringExps reusing the allocated array
1264 assert(sizeof(Expressions) == sizeof(Identifiers));
1265 Expressions *exps = (Expressions *)idents;
1266 for (size_t i = 0; i < idents->dim; i++)
1267 {
1268 Identifier *id = (*idents)[i];
1269 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
1270 (*exps)[i] = se;
1271 }
1272
1273 /* Making this a tuple is more flexible, as it can be statically unrolled.
1274 * To make an array literal, enclose __traits in [ ]:
1275 * [ __traits(allMembers, ...) ]
1276 */
1277 Expression *ex = new TupleExp(e->loc, exps);
1278 ex = semantic(ex, sc);
1279 return ex;
1280 }
1281 else if (e->ident == Id::compiles)
1282 {
1283 /* Determine if all the objects - types, expressions, or symbols -
1284 * compile without error
1285 */
1286 if (!dim)
1287 return False(e);
1288
1289 for (size_t i = 0; i < dim; i++)
1290 {
1291 unsigned errors = global.startGagging();
1292 Scope *sc2 = sc->push();
1293 sc2->tinst = NULL;
1294 sc2->minst = NULL;
1295 sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
1296 bool err = false;
1297
1298 RootObject *o = (*e->args)[i];
1299 Type *t = isType(o);
1300 Expression *ex = t ? typeToExpression(t) : isExpression(o);
1301 if (!ex && t)
1302 {
1303 Dsymbol *s;
1304 t->resolve(e->loc, sc2, &ex, &t, &s);
1305 if (t)
1306 {
1307 t->semantic(e->loc, sc2);
1308 if (t->ty == Terror)
1309 err = true;
1310 }
1311 else if (s && s->errors)
1312 err = true;
1313 }
1314 if (ex)
1315 {
1316 ex = semantic(ex, sc2);
1317 ex = resolvePropertiesOnly(sc2, ex);
1318 ex = ex->optimize(WANTvalue);
1319 if (sc2->func && sc2->func->type->ty == Tfunction)
1320 {
1321 TypeFunction *tf = (TypeFunction *)sc2->func->type;
1322 canThrow(ex, sc2->func, tf->isnothrow);
1323 }
1324 ex = checkGC(sc2, ex);
1325 if (ex->op == TOKerror)
1326 err = true;
1327 }
1328
1329 // Carefully detach the scope from the parent and throw it away as
1330 // we only need it to evaluate the expression
1331 // https://issues.dlang.org/show_bug.cgi?id=15428
1332 freeFieldinit(sc2);
1333 sc2->enclosing = NULL;
1334 sc2->pop();
1335
1336 if (global.endGagging(errors) || err)
1337 {
1338 return False(e);
1339 }
1340 }
1341 return True(e);
1342 }
1343 else if (e->ident == Id::isSame)
1344 {
1345 /* Determine if two symbols are the same
1346 */
1347 if (dim != 2)
1348 return dimError(e, 2, dim);
1349
1350 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
1351 return new ErrorExp();
1352
1353 RootObject *o1 = (*e->args)[0];
1354 RootObject *o2 = (*e->args)[1];
1355 Dsymbol *s1 = getDsymbol(o1);
1356 Dsymbol *s2 = getDsymbol(o2);
1357 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
1358 if (!s1 && !s2)
1359 {
1360 Expression *ea1 = isExpression(o1);
1361 Expression *ea2 = isExpression(o2);
1362 if (ea1 && ea2)
1363 {
1364 if (ea1->equals(ea2))
1365 return True(e);
1366 }
1367 }
1368 if (!s1 || !s2)
1369 return False(e);
1370 s1 = s1->toAlias();
1371 s2 = s2->toAlias();
1372
1373 if (s1->isFuncAliasDeclaration())
1374 s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
1375 if (s2->isFuncAliasDeclaration())
1376 s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
1377
1378 return (s1 == s2) ? True(e) : False(e);
1379 }
1380 else if (e->ident == Id::getUnitTests)
1381 {
1382 if (dim != 1)
1383 return dimError(e, 1, dim);
1384
1385 RootObject *o = (*e->args)[0];
1386 Dsymbol *s = getDsymbol(o);
1387 if (!s)
1388 {
1389 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1390 o->toChars());
1391 return new ErrorExp();
1392 }
1393 if (Import *imp = s->isImport()) // Bugzilla 10990
1394 s = imp->mod;
1395
1396 ScopeDsymbol* sds = s->isScopeDsymbol();
1397 if (!sds)
1398 {
1399 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
1400 s->toChars(), s->kind());
1401 return new ErrorExp();
1402 }
1403
1404 Expressions *exps = new Expressions();
1405 if (global.params.useUnitTests)
1406 {
1407 // Should actually be a set
1408 AA* uniqueUnitTests = NULL;
1409 collectUnitTests(sds->members, uniqueUnitTests, exps);
1410 }
1411 TupleExp *te= new TupleExp(e->loc, exps);
1412 return semantic(te, sc);
1413 }
1414 else if(e->ident == Id::getVirtualIndex)
1415 {
1416 if (dim != 1)
1417 return dimError(e, 1, dim);
1418
1419 RootObject *o = (*e->args)[0];
1420 Dsymbol *s = getDsymbol(o);
1421
1422 FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
1423 if (!fd)
1424 {
1425 e->error("first argument to __traits(getVirtualIndex) must be a function");
1426 return new ErrorExp();
1427 }
1428
1429 fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
1430 return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
1431 }
1432 else if (e->ident == Id::getPointerBitmap)
1433 {
1434 return pointerBitmap(e);
1435 }
1436
1437 if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
1438 e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
1439 else
1440 e->error("unrecognized trait '%s'", e->ident->toChars());
1441 return new ErrorExp();
1442
1443 e->error("wrong number of arguments %d", (int)dim);
1444 return new ErrorExp();
1445 }
1446