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