]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/traits.c
d: Merge upstream dmd 47ed0330f
[thirdparty/gcc.git] / gcc / d / dmd / traits.c
1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2020 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
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 */
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
131 static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); }
132 static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); }
133
134 bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); }
135 bool isTypeFloating(Type *t) { return t->isfloating(); }
136 bool isTypeIntegral(Type *t) { return t->isintegral(); }
137 bool isTypeScalar(Type *t) { return t->isscalar(); }
138 bool isTypeUnsigned(Type *t) { return t->isunsigned(); }
139 bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; }
140 bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; }
141 bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); }
142 bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; }
143
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
157 bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); }
158 bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); }
159 bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); }
160 bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); }
161 bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); }
162 bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); }
163
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
180 bool isDeclRef(Declaration *d) { return d->isRef(); }
181 bool isDeclOut(Declaration *d) { return d->isOut(); }
182 bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; }
183
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
205 static int fp(void *param, const char *str)
206 {
207 PushAttributes *p = (PushAttributes *)param;
208 p->mods->push(new StringExp(Loc(), const_cast<char *>(str)));
209 return 0;
210 }
211 };
212
213 StringTable traitsStringTable;
214
215 struct TraitsInitializer
216 {
217 TraitsInitializer();
218 };
219
220 static TraitsInitializer traitsinitializer;
221
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
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
294 static int fpisTemplate(void *, Dsymbol *s)
295 {
296 if (s->isTemplateDeclaration())
297 return 1;
298
299 return 0;
300 }
301
302 bool isTemplate(Dsymbol *s)
303 {
304 if (!s->toAlias()->isOverloadable())
305 return false;
306
307 return overloadApply(s, NULL, &fpisTemplate) != 0;
308 }
309
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 */
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
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
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->semanticRun == PASSinit)
675 s->semantic(NULL);
676
677 const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names)
678 assert(protName);
679 StringExp *se = new StringExp(e->loc, const_cast<char *>(protName));
680 return semantic(se, sc);
681 }
682 else if (e->ident == Id::parent)
683 {
684 if (dim != 1)
685 return dimError(e, 1, dim);
686
687 RootObject *o = (*e->args)[0];
688 Dsymbol *s = getDsymbol(o);
689 if (s)
690 {
691 if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943
692 s = fd->toAliasFunc();
693 if (!s->isImport()) // Bugzilla 8922
694 s = s->toParent();
695 }
696 if (!s || s->isImport())
697 {
698 e->error("argument %s has no parent", o->toChars());
699 return new ErrorExp();
700 }
701
702 if (FuncDeclaration *f = s->isFuncDeclaration())
703 {
704 if (TemplateDeclaration *td = getFuncTemplateDecl(f))
705 {
706 if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
707 td = td->overroot; // then get the start
708 Expression *ex = new TemplateExp(e->loc, td, f);
709 ex = semantic(ex, sc);
710 return ex;
711 }
712
713 if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
714 {
715 // Directly translate to VarExp instead of FuncExp
716 Expression *ex = new VarExp(e->loc, fld, true);
717 return semantic(ex, sc);
718 }
719 }
720
721 return resolve(e->loc, sc, s, false);
722 }
723 else if (e->ident == Id::hasMember ||
724 e->ident == Id::getMember ||
725 e->ident == Id::getOverloads ||
726 e->ident == Id::getVirtualMethods ||
727 e->ident == Id::getVirtualFunctions)
728 {
729 if (dim != 2)
730 return dimError(e, 2, dim);
731
732 RootObject *o = (*e->args)[0];
733 Expression *ex = isExpression((*e->args)[1]);
734 if (!ex)
735 {
736 e->error("expression expected as second argument of __traits %s", e->ident->toChars());
737 return new ErrorExp();
738 }
739 ex = ex->ctfeInterpret();
740
741 StringExp *se = ex->toStringExp();
742 if (!se || se->len == 0)
743 {
744 e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
745 return new ErrorExp();
746 }
747 se = se->toUTF8(sc);
748
749 if (se->sz != 1)
750 {
751 e->error("string must be chars");
752 return new ErrorExp();
753 }
754 Identifier *id = Identifier::idPool((char *)se->string, se->len);
755
756 /* Prefer dsymbol, because it might need some runtime contexts.
757 */
758 Dsymbol *sym = getDsymbol(o);
759 if (sym)
760 {
761 ex = new DsymbolExp(e->loc, sym);
762 ex = new DotIdExp(e->loc, ex, id);
763 }
764 else if (Type *t = isType(o))
765 ex = typeDotIdExp(e->loc, t, id);
766 else if (Expression *ex2 = isExpression(o))
767 ex = new DotIdExp(e->loc, ex2, id);
768 else
769 {
770 e->error("invalid first argument");
771 return new ErrorExp();
772 }
773
774 if (e->ident == Id::hasMember)
775 {
776 if (sym)
777 {
778 if (sym->search(e->loc, id))
779 return True(e);
780 }
781
782 /* Take any errors as meaning it wasn't found
783 */
784 Scope *scx = sc->push();
785 scx->flags |= SCOPEignoresymbolvisibility;
786 ex = trySemantic(ex, scx);
787 scx->pop();
788 return ex ? True(e) : False(e);
789 }
790 else if (e->ident == Id::getMember)
791 {
792 if (ex->op == TOKdotid)
793 // Prevent semantic() from replacing Symbol with its initializer
794 ((DotIdExp *)ex)->wantsym = true;
795 Scope *scx = sc->push();
796 scx->flags |= SCOPEignoresymbolvisibility;
797 ex = semantic(ex, scx);
798 scx->pop();
799 return ex;
800 }
801 else if (e->ident == Id::getVirtualFunctions ||
802 e->ident == Id::getVirtualMethods ||
803 e->ident == Id::getOverloads)
804 {
805 unsigned errors = global.errors;
806 Expression *eorig = ex;
807 Scope *scx = sc->push();
808 scx->flags |= SCOPEignoresymbolvisibility;
809 ex = semantic(ex, scx);
810 if (errors < global.errors)
811 e->error("%s cannot be resolved", eorig->toChars());
812 //ex->print();
813
814 /* Create tuple of functions of ex
815 */
816 Expressions *exps = new Expressions();
817 FuncDeclaration *f;
818 if (ex->op == TOKvar)
819 {
820 VarExp *ve = (VarExp *)ex;
821 f = ve->var->isFuncDeclaration();
822 ex = NULL;
823 }
824 else if (ex->op == TOKdotvar)
825 {
826 DotVarExp *dve = (DotVarExp *)ex;
827 f = dve->var->isFuncDeclaration();
828 if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
829 ex = NULL;
830 else
831 ex = dve->e1;
832 }
833 else
834 f = NULL;
835 Ptrait p;
836 p.exps = exps;
837 p.e1 = ex;
838 p.ident = e->ident;
839 overloadApply(f, &p, &fptraits);
840
841 ex = new TupleExp(e->loc, exps);
842 ex = semantic(ex, scx);
843 scx->pop();
844 return ex;
845 }
846 else
847 assert(0);
848 }
849 else if (e->ident == Id::classInstanceSize)
850 {
851 if (dim != 1)
852 return dimError(e, 1, dim);
853
854 RootObject *o = (*e->args)[0];
855 Dsymbol *s = getDsymbol(o);
856 ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL;
857 if (!cd)
858 {
859 e->error("first argument is not a class");
860 return new ErrorExp();
861 }
862 if (cd->sizeok != SIZEOKdone)
863 {
864 cd->size(cd->loc);
865 }
866 if (cd->sizeok != SIZEOKdone)
867 {
868 e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
869 return new ErrorExp();
870 }
871
872 return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
873 }
874 else if (e->ident == Id::getAliasThis)
875 {
876 if (dim != 1)
877 return dimError(e, 1, dim);
878
879 RootObject *o = (*e->args)[0];
880 Dsymbol *s = getDsymbol(o);
881 AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
882 if (!ad)
883 {
884 e->error("argument is not an aggregate type");
885 return new ErrorExp();
886 }
887
888 Expressions *exps = new Expressions();
889 if (ad->aliasthis)
890 exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars())));
891 Expression *ex = new TupleExp(e->loc, exps);
892 ex = semantic(ex, sc);
893 return ex;
894 }
895 else if (e->ident == Id::getAttributes)
896 {
897 if (dim != 1)
898 return dimError(e, 1, dim);
899
900 RootObject *o = (*e->args)[0];
901 Dsymbol *s = getDsymbol(o);
902 if (!s)
903 {
904 e->error("first argument is not a symbol");
905 return new ErrorExp();
906 }
907 if (Import *imp = s->isImport())
908 {
909 s = imp->mod;
910 }
911
912 //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
913 UserAttributeDeclaration *udad = s->userAttribDecl;
914 Expressions *exps = udad ? udad->getAttributes() : new Expressions();
915 TupleExp *tup = new TupleExp(e->loc, exps);
916 return semantic(tup, sc);
917 }
918 else if (e->ident == Id::getFunctionAttributes)
919 {
920 /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
921 if (dim != 1)
922 return dimError(e, 1, dim);
923
924 RootObject *o = (*e->args)[0];
925 Dsymbol *s = getDsymbol(o);
926 Type *t = isType(o);
927 TypeFunction *tf = NULL;
928 if (s)
929 {
930 if (FuncDeclaration *f = s->isFuncDeclaration())
931 t = f->type;
932 else if (VarDeclaration *v = s->isVarDeclaration())
933 t = v->type;
934 }
935 if (t)
936 {
937 if (t->ty == Tfunction)
938 tf = (TypeFunction *)t;
939 else if (t->ty == Tdelegate)
940 tf = (TypeFunction *)t->nextOf();
941 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
942 tf = (TypeFunction *)t->nextOf();
943 }
944 if (!tf)
945 {
946 e->error("first argument is not a function");
947 return new ErrorExp();
948 }
949
950 Expressions *mods = new Expressions();
951 PushAttributes pa;
952 pa.mods = mods;
953 tf->modifiersApply(&pa, &PushAttributes::fp);
954 tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
955
956 TupleExp *tup = new TupleExp(e->loc, mods);
957 return semantic(tup, sc);
958 }
959 else if (e->ident == Id::getFunctionVariadicStyle)
960 {
961 /* Accept a symbol or a type. Returns one of the following:
962 * "none" not a variadic function
963 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
964 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
965 * "typesafe" void typesafe(T[] ...)
966 */
967 // get symbol linkage as a string
968 if (dim != 1)
969 return dimError(e, 1, dim);
970
971 LINK link;
972 int varargs;
973 RootObject *o = (*e->args)[0];
974 Type *t = isType(o);
975 TypeFunction *tf = NULL;
976 if (t)
977 {
978 if (t->ty == Tfunction)
979 tf = (TypeFunction *)t;
980 else if (t->ty == Tdelegate)
981 tf = (TypeFunction *)t->nextOf();
982 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
983 tf = (TypeFunction *)t->nextOf();
984 }
985 if (tf)
986 {
987 link = tf->linkage;
988 varargs = tf->varargs;
989 }
990 else
991 {
992 Dsymbol *s = getDsymbol(o);
993 FuncDeclaration *fd = NULL;
994 if (!s || (fd = s->isFuncDeclaration()) == NULL)
995 {
996 e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars());
997 return new ErrorExp();
998 }
999 link = fd->linkage;
1000 fd->getParameters(&varargs);
1001 }
1002 const char *style;
1003 switch (varargs)
1004 {
1005 case 0: style = "none"; break;
1006 case 1: style = (link == LINKd) ? "argptr"
1007 : "stdarg"; break;
1008 case 2: style = "typesafe"; break;
1009 default:
1010 assert(0);
1011 }
1012 StringExp *se = new StringExp(e->loc, const_cast<char*>(style));
1013 return semantic(se, sc);
1014 }
1015 else if (e->ident == Id::getParameterStorageClasses)
1016 {
1017 /* Accept a function symbol or a type, followed by a parameter index.
1018 * Returns a tuple of strings of the parameter's storage classes.
1019 */
1020 // get symbol linkage as a string
1021 if (dim != 2)
1022 return dimError(e, 2, dim);
1023
1024 RootObject *o1 = (*e->args)[1];
1025 RootObject *o = (*e->args)[0];
1026 Type *t = isType(o);
1027 TypeFunction *tf = NULL;
1028 if (t)
1029 {
1030 if (t->ty == Tfunction)
1031 tf = (TypeFunction *)t;
1032 else if (t->ty == Tdelegate)
1033 tf = (TypeFunction *)t->nextOf();
1034 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
1035 tf = (TypeFunction *)t->nextOf();
1036 }
1037 Parameters* fparams;
1038 if (tf)
1039 {
1040 fparams = tf->parameters;
1041 }
1042 else
1043 {
1044 Dsymbol *s = getDsymbol(o);
1045 FuncDeclaration *fd = NULL;
1046 if (!s || (fd = s->isFuncDeclaration()) == NULL)
1047 {
1048 e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
1049 o->toChars(), o1->toChars());
1050 return new ErrorExp();
1051 }
1052 fparams = fd->getParameters(NULL);
1053 }
1054
1055 StorageClass stc;
1056
1057 // Set stc to storage class of the ith parameter
1058 Expression *ex = isExpression((*e->args)[1]);
1059 if (!ex)
1060 {
1061 e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1062 o->toChars(), o1->toChars());
1063 return new ErrorExp();
1064 }
1065 ex = ex->ctfeInterpret();
1066 uinteger_t ii = ex->toUInteger();
1067 if (ii >= Parameter::dim(fparams))
1068 {
1069 e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars());
1070 return new ErrorExp();
1071 }
1072
1073 unsigned n = (unsigned)ii;
1074 Parameter *p = Parameter::getNth(fparams, n);
1075 stc = p->storageClass;
1076
1077 // This mirrors hdrgen.visit(Parameter p)
1078 if (p->type && p->type->mod & MODshared)
1079 stc &= ~STCshared;
1080
1081 Expressions *exps = new Expressions;
1082
1083 if (stc & STCauto)
1084 exps->push(new StringExp(e->loc, const_cast<char *>("auto")));
1085 if (stc & STCreturn)
1086 exps->push(new StringExp(e->loc, const_cast<char *>("return")));
1087
1088 if (stc & STCout)
1089 exps->push(new StringExp(e->loc, const_cast<char *>("out")));
1090 else if (stc & STCref)
1091 exps->push(new StringExp(e->loc, const_cast<char *>("ref")));
1092 else if (stc & STCin)
1093 exps->push(new StringExp(e->loc, const_cast<char *>("in")));
1094 else if (stc & STClazy)
1095 exps->push(new StringExp(e->loc, const_cast<char *>("lazy")));
1096 else if (stc & STCalias)
1097 exps->push(new StringExp(e->loc, const_cast<char *>("alias")));
1098
1099 if (stc & STCconst)
1100 exps->push(new StringExp(e->loc, const_cast<char *>("const")));
1101 if (stc & STCimmutable)
1102 exps->push(new StringExp(e->loc, const_cast<char *>("immutable")));
1103 if (stc & STCwild)
1104 exps->push(new StringExp(e->loc, const_cast<char *>("inout")));
1105 if (stc & STCshared)
1106 exps->push(new StringExp(e->loc, const_cast<char *>("shared")));
1107 if (stc & STCscope && !(stc & STCscopeinferred))
1108 exps->push(new StringExp(e->loc, const_cast<char *>("scope")));
1109
1110 TupleExp *tup = new TupleExp(e->loc, exps);
1111 return semantic(tup, sc);
1112 }
1113 else if (e->ident == Id::getLinkage)
1114 {
1115 // get symbol linkage as a string
1116 if (dim != 1)
1117 return dimError(e, 1, dim);
1118
1119 LINK link;
1120 RootObject *o = (*e->args)[0];
1121 Type *t = isType(o);
1122 TypeFunction *tf = NULL;
1123 if (t)
1124 {
1125 if (t->ty == Tfunction)
1126 tf = (TypeFunction *)t;
1127 else if (t->ty == Tdelegate)
1128 tf = (TypeFunction *)t->nextOf();
1129 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
1130 tf = (TypeFunction *)t->nextOf();
1131 }
1132 if (tf)
1133 link = tf->linkage;
1134 else
1135 {
1136 Dsymbol *s = getDsymbol(o);
1137 Declaration *d = NULL;
1138 AggregateDeclaration *ad = NULL;
1139 if (!s || ((d = s->isDeclaration()) == NULL
1140 && (ad = s->isAggregateDeclaration()) == NULL))
1141 {
1142 e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
1143 return new ErrorExp();
1144 }
1145 if (d != NULL)
1146 link = d->linkage;
1147 else
1148 {
1149 switch (ad->classKind)
1150 {
1151 case ClassKind::d:
1152 link = LINKd;
1153 break;
1154 case ClassKind::cpp:
1155 link = LINKcpp;
1156 break;
1157 case ClassKind::objc:
1158 link = LINKobjc;
1159 break;
1160 default:
1161 assert(0);
1162 }
1163 }
1164 }
1165 const char *linkage = linkageToChars(link);
1166 StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
1167 return semantic(se, sc);
1168 }
1169 else if (e->ident == Id::allMembers ||
1170 e->ident == Id::derivedMembers)
1171 {
1172 if (dim != 1)
1173 return dimError(e, 1, dim);
1174
1175 RootObject *o = (*e->args)[0];
1176 Dsymbol *s = getDsymbol(o);
1177 if (!s)
1178 {
1179 e->error("argument has no members");
1180 return new ErrorExp();
1181 }
1182 if (Import *imp = s->isImport())
1183 {
1184 // Bugzilla 9692
1185 s = imp->mod;
1186 }
1187
1188 ScopeDsymbol *sds = s->isScopeDsymbol();
1189 if (!sds || sds->isTemplateDeclaration())
1190 {
1191 e->error("%s %s has no members", s->kind(), s->toChars());
1192 return new ErrorExp();
1193 }
1194
1195 // use a struct as local function
1196 struct PushIdentsDg
1197 {
1198 ScopeDsymbol *sds;
1199 Identifiers *idents;
1200
1201 static int dg(void *ctx, size_t, Dsymbol *sm)
1202 {
1203 if (!sm)
1204 return 1;
1205
1206 // skip local symbols, such as static foreach loop variables
1207 if (Declaration *decl = sm->isDeclaration())
1208 {
1209 if (decl->storage_class & STClocal)
1210 {
1211 return 0;
1212 }
1213 }
1214
1215 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
1216 if (sm->ident)
1217 {
1218 // https://issues.dlang.org/show_bug.cgi?id=10096
1219 // https://issues.dlang.org/show_bug.cgi?id=10100
1220 // Skip over internal members in __traits(allMembers)
1221 if ((sm->isCtorDeclaration() && sm->ident != Id::ctor) ||
1222 (sm->isDtorDeclaration() && sm->ident != Id::dtor) ||
1223 (sm->isPostBlitDeclaration() && sm->ident != Id::postblit) ||
1224 sm->isInvariantDeclaration() ||
1225 sm->isUnitTestDeclaration())
1226 {
1227 return 0;
1228 }
1229
1230 if (sm->ident == Id::empty)
1231 {
1232 return 0;
1233 }
1234 if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
1235 return 0;
1236 PushIdentsDg *pid = (PushIdentsDg *)ctx;
1237 if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057
1238 return 0;
1239
1240 //printf("\t%s\n", sm->ident->toChars());
1241 Identifiers *idents = pid->idents;
1242
1243 /* Skip if already present in idents[]
1244 */
1245 for (size_t j = 0; j < idents->dim; j++)
1246 {
1247 Identifier *id = (*idents)[j];
1248 if (id == sm->ident)
1249 return 0;
1250 }
1251
1252 idents->push(sm->ident);
1253 }
1254 else
1255 {
1256 EnumDeclaration *ed = sm->isEnumDeclaration();
1257 if (ed)
1258 {
1259 ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx);
1260 }
1261 }
1262 return 0;
1263 }
1264 };
1265
1266 Identifiers *idents = new Identifiers;
1267 PushIdentsDg ctx;
1268 ctx.sds = sds;
1269 ctx.idents = idents;
1270 ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx);
1271 ClassDeclaration *cd = sds->isClassDeclaration();
1272 if (cd && e->ident == Id::allMembers)
1273 {
1274 if (cd->semanticRun < PASSsemanticdone)
1275 cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference
1276
1277 struct PushBaseMembers
1278 {
1279 static void dg(ClassDeclaration *cd, PushIdentsDg *ctx)
1280 {
1281 for (size_t i = 0; i < cd->baseclasses->dim; i++)
1282 {
1283 ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
1284 assert(cb);
1285 ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx);
1286 if (cb->baseclasses->dim)
1287 dg(cb, ctx);
1288 }
1289 }
1290 };
1291 PushBaseMembers::dg(cd, &ctx);
1292 }
1293
1294 // Turn Identifiers into StringExps reusing the allocated array
1295 assert(sizeof(Expressions) == sizeof(Identifiers));
1296 Expressions *exps = (Expressions *)idents;
1297 for (size_t i = 0; i < idents->dim; i++)
1298 {
1299 Identifier *id = (*idents)[i];
1300 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
1301 (*exps)[i] = se;
1302 }
1303
1304 /* Making this a tuple is more flexible, as it can be statically unrolled.
1305 * To make an array literal, enclose __traits in [ ]:
1306 * [ __traits(allMembers, ...) ]
1307 */
1308 Expression *ex = new TupleExp(e->loc, exps);
1309 ex = semantic(ex, sc);
1310 return ex;
1311 }
1312 else if (e->ident == Id::compiles)
1313 {
1314 /* Determine if all the objects - types, expressions, or symbols -
1315 * compile without error
1316 */
1317 if (!dim)
1318 return False(e);
1319
1320 for (size_t i = 0; i < dim; i++)
1321 {
1322 unsigned errors = global.startGagging();
1323 Scope *sc2 = sc->push();
1324 sc2->tinst = NULL;
1325 sc2->minst = NULL;
1326 sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
1327 bool err = false;
1328
1329 RootObject *o = (*e->args)[i];
1330 Type *t = isType(o);
1331 Expression *ex = t ? typeToExpression(t) : isExpression(o);
1332 if (!ex && t)
1333 {
1334 Dsymbol *s;
1335 t->resolve(e->loc, sc2, &ex, &t, &s);
1336 if (t)
1337 {
1338 t->semantic(e->loc, sc2);
1339 if (t->ty == Terror)
1340 err = true;
1341 }
1342 else if (s && s->errors)
1343 err = true;
1344 }
1345 if (ex)
1346 {
1347 ex = semantic(ex, sc2);
1348 ex = resolvePropertiesOnly(sc2, ex);
1349 ex = ex->optimize(WANTvalue);
1350 if (sc2->func && sc2->func->type->ty == Tfunction)
1351 {
1352 TypeFunction *tf = (TypeFunction *)sc2->func->type;
1353 canThrow(ex, sc2->func, tf->isnothrow);
1354 }
1355 ex = checkGC(sc2, ex);
1356 if (ex->op == TOKerror)
1357 err = true;
1358 }
1359
1360 // Carefully detach the scope from the parent and throw it away as
1361 // we only need it to evaluate the expression
1362 // https://issues.dlang.org/show_bug.cgi?id=15428
1363 freeFieldinit(sc2);
1364 sc2->enclosing = NULL;
1365 sc2->pop();
1366
1367 if (global.endGagging(errors) || err)
1368 {
1369 return False(e);
1370 }
1371 }
1372 return True(e);
1373 }
1374 else if (e->ident == Id::isSame)
1375 {
1376 /* Determine if two symbols are the same
1377 */
1378 if (dim != 2)
1379 return dimError(e, 2, dim);
1380
1381 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
1382 return new ErrorExp();
1383
1384 RootObject *o1 = (*e->args)[0];
1385 RootObject *o2 = (*e->args)[1];
1386
1387 // issue 12001, allow isSame, <BasicType>, <BasicType>
1388 Type *t1 = isType(o1);
1389 Type *t2 = isType(o2);
1390 if (t1 && t2 && t1->equals(t2))
1391 return True(e);
1392
1393 Dsymbol *s1 = getDsymbol(o1);
1394 Dsymbol *s2 = getDsymbol(o2);
1395 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
1396 if (!s1 && !s2)
1397 {
1398 Expression *ea1 = isExpression(o1);
1399 Expression *ea2 = isExpression(o2);
1400 if (ea1 && ea2)
1401 {
1402 if (ea1->equals(ea2))
1403 return True(e);
1404 }
1405 }
1406 if (!s1 || !s2)
1407 return False(e);
1408 s1 = s1->toAlias();
1409 s2 = s2->toAlias();
1410
1411 if (s1->isFuncAliasDeclaration())
1412 s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
1413 if (s2->isFuncAliasDeclaration())
1414 s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
1415
1416 return (s1 == s2) ? True(e) : False(e);
1417 }
1418 else if (e->ident == Id::getUnitTests)
1419 {
1420 if (dim != 1)
1421 return dimError(e, 1, dim);
1422
1423 RootObject *o = (*e->args)[0];
1424 Dsymbol *s = getDsymbol(o);
1425 if (!s)
1426 {
1427 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1428 o->toChars());
1429 return new ErrorExp();
1430 }
1431 if (Import *imp = s->isImport()) // Bugzilla 10990
1432 s = imp->mod;
1433
1434 ScopeDsymbol* sds = s->isScopeDsymbol();
1435 if (!sds)
1436 {
1437 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
1438 s->toChars(), s->kind());
1439 return new ErrorExp();
1440 }
1441
1442 Expressions *exps = new Expressions();
1443 if (global.params.useUnitTests)
1444 {
1445 // Should actually be a set
1446 AA* uniqueUnitTests = NULL;
1447 collectUnitTests(sds->members, uniqueUnitTests, exps);
1448 }
1449 TupleExp *te= new TupleExp(e->loc, exps);
1450 return semantic(te, sc);
1451 }
1452 else if (e->ident == Id::getVirtualIndex)
1453 {
1454 if (dim != 1)
1455 return dimError(e, 1, dim);
1456
1457 RootObject *o = (*e->args)[0];
1458 Dsymbol *s = getDsymbol(o);
1459
1460 FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
1461 if (!fd)
1462 {
1463 e->error("first argument to __traits(getVirtualIndex) must be a function");
1464 return new ErrorExp();
1465 }
1466
1467 fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
1468 return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
1469 }
1470 else if (e->ident == Id::getPointerBitmap)
1471 {
1472 return pointerBitmap(e);
1473 }
1474
1475 if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
1476 e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
1477 else
1478 e->error("unrecognized trait '%s'", e->ident->toChars());
1479 return new ErrorExp();
1480
1481 e->error("wrong number of arguments %d", (int)dim);
1482 return new ErrorExp();
1483 }