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