Merge dmd upstream 6243fa6d2
[official-gcc.git] / gcc / d / dmd / traits.c
blobe4ebea683890cbde921d2c8860ebaf78f57b9f22
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2018 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 */
11 #include "root/dsystem.h"
12 #include "root/rmem.h"
13 #include "root/aav.h"
14 #include "root/checkedint.h"
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"
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);
45 /************************************************
46 * Delegate to be passed to overloadApply() that looks
47 * for functions matching a trait.
50 struct Ptrait
52 Expression *e1;
53 Expressions *exps; // collected results
54 Identifier *ident; // which trait we're looking for
57 static int fptraits(void *param, Dsymbol *s)
59 FuncDeclaration *f = s->isFuncDeclaration();
60 if (!f)
61 return 0;
63 Ptrait *p = (Ptrait *)param;
64 if (p->ident == Id::getVirtualFunctions && !f->isVirtual())
65 return 0;
67 if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod())
68 return 0;
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;
81 /**
82 * Collects all unit test functions from the given array of symbols.
84 * This is a helper function used by the implementation of __traits(getUnitTests).
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
92 * Output:
93 * unitTests array of DsymbolExp's of the collected unit test functions
94 * uniqueUnitTests updated with symbols from unitTests[ ]
96 static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests)
98 if (!symbols)
99 return;
100 for (size_t i = 0; i < symbols->dim; i++)
102 Dsymbol *symbol = (*symbols)[i];
103 UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration();
104 if (unitTest)
106 if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest))
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;
116 else
118 AttribDeclaration *attrDecl = symbol->isAttribDeclaration();
120 if (attrDecl)
122 Dsymbols *decl = attrDecl->include(NULL, NULL);
123 collectUnitTests(decl, uniqueUnitTests, unitTests);
129 /************************ TraitsExp ************************************/
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); }
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; }
144 Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t))
146 if (!e->args || !e->args->dim)
147 return False(e);
148 for (size_t i = 0; i < e->args->dim; i++)
150 Type *t = getType((*e->args)[i]);
151 if (!t || !fp(t))
152 return False(e);
154 return True(e);
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(); }
164 Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f))
166 if (!e->args || !e->args->dim)
167 return False(e);
168 for (size_t i = 0; i < e->args->dim; i++)
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);
177 return True(e);
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; }
184 Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d))
186 if (!e->args || !e->args->dim)
187 return False(e);
188 for (size_t i = 0; i < e->args->dim; i++)
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);
197 return True(e);
200 // callback for TypeFunction::attributesApply
201 struct PushAttributes
203 Expressions *mods;
205 static int fp(void *param, const char *str)
207 PushAttributes *p = (PushAttributes *)param;
208 p->mods->push(new StringExp(Loc(), const_cast<char *>(str)));
209 return 0;
213 StringTable traitsStringTable;
215 struct TraitsInitializer
217 TraitsInitializer();
220 static TraitsInitializer traitsinitializer;
222 TraitsInitializer::TraitsInitializer()
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
271 traitsStringTable._init(40);
273 for (size_t idx = 0;; idx++)
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);
282 void *trait_search_fp(void *, const char *seed, int* cost)
284 //printf("trait_search_fp('%s')\n", seed);
285 size_t len = strlen(seed);
286 if (!len)
287 return NULL;
289 *cost = 0;
290 StringValue *sv = traitsStringTable.lookup(seed, len);
291 return sv ? (void*)sv->ptrvalue : NULL;
294 static int fpisTemplate(void *, Dsymbol *s)
296 if (s->isTemplateDeclaration())
297 return 1;
299 return 0;
302 bool isTemplate(Dsymbol *s)
304 if (!s->toAlias()->isOverloadable())
305 return false;
307 return overloadApply(s, NULL, &fpisTemplate) != 0;
310 Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s))
312 if (!e->args || !e->args->dim)
313 return False(e);
314 for (size_t i = 0; i < e->args->dim; i++)
316 Dsymbol *s = getDsymbol((*e->args)[i]);
317 if (!s || !fp(s))
318 return False(e);
320 return True(e);
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.
331 * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
333 Expression *pointerBitmap(TraitsExp *e)
335 if (!e->args || e->args->dim != 1)
337 error(e->loc, "a single type expected for trait pointerBitmap");
338 return new ErrorExp();
340 Type *t = getType((*e->args)[0]);
341 if (!t)
343 error(e->loc, "%s is not a type", (*e->args)[0]->toChars());
344 return new ErrorExp();
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();
354 const d_uns64 sz_size_t = Type::tsize_t->size(e->loc);
355 if (sz > UINT64_MAX - sz_size_t)
357 error(e->loc, "size overflow for type %s", t->toChars());
358 return new ErrorExp();
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();
368 class PointerBitmapVisitor : public Visitor
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)
375 void setpointer(d_uns64 off)
377 d_uns64 ptroff = off / sz_size_t;
378 (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t));
380 virtual void visit(Type *t)
382 Type *tb = t->toBasetype();
383 if (tb != t)
384 tb->accept(this);
386 virtual void visit(TypeError *t) { visit((Type *)t); }
387 virtual void visit(TypeNext *) { assert(0); }
388 virtual void visit(TypeBasic *t)
390 if (t->ty == Tvoid)
391 setpointer(offset);
393 virtual void visit(TypeVector *) { }
394 virtual void visit(TypeArray *) { assert(0); }
395 virtual void visit(TypeSArray *t)
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++)
404 offset = arrayoff + i * nextsize;
405 t->next->accept(this);
407 offset = arrayoff;
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)
413 if (t->nextOf()->ty != Tfunction) // don't mark function pointers
414 setpointer(offset);
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
430 virtual void visit(TypeStruct *t)
432 d_uns64 structoff = offset;
433 for (size_t i = 0; i < t->sym->fields.dim; i++)
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);
442 offset = structoff;
445 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
446 void visitClass(TypeClass* t)
448 d_uns64 classoff = offset;
450 // skip vtable-ptr and monitor
451 if (t->sym->baseClass)
452 visitClass((TypeClass*)t->sym->baseClass->type);
454 for (size_t i = 0; i < t->sym->fields.dim; i++)
456 VarDeclaration *v = t->sym->fields[i];
457 offset = classoff + v->offset;
458 v->type->accept(this);
460 offset = classoff;
463 Array<d_uns64>* data;
464 d_uns64 offset;
465 d_uns64 sz_size_t;
466 bool error;
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();
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));
482 ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, exps);
483 ale->type = Type::tsize_t->sarrayOf(cntdata + 1);
484 return ale;
487 static Expression *dimError(TraitsExp *e, int expected, int dim)
489 e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim);
490 return new ErrorExp();
493 Expression *semanticTraits(TraitsExp *e, Scope *sc)
495 if (e->ident != Id::compiles && e->ident != Id::isSame &&
496 e->ident != Id::identifier && e->ident != Id::getProtection)
498 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1))
499 return new ErrorExp();
501 size_t dim = e->args ? e->args->dim : 0;
503 if (e->ident == Id::isArithmetic)
505 return isTypeX(e, &isTypeArithmetic);
507 else if (e->ident == Id::isFloating)
509 return isTypeX(e, &isTypeFloating);
511 else if (e->ident == Id::isIntegral)
513 return isTypeX(e, &isTypeIntegral);
515 else if (e->ident == Id::isScalar)
517 return isTypeX(e, &isTypeScalar);
519 else if (e->ident == Id::isUnsigned)
521 return isTypeX(e, &isTypeUnsigned);
523 else if (e->ident == Id::isAssociativeArray)
525 return isTypeX(e, &isTypeAssociativeArray);
527 else if (e->ident == Id::isStaticArray)
529 return isTypeX(e, &isTypeStaticArray);
531 else if (e->ident == Id::isAbstractClass)
533 return isTypeX(e, &isTypeAbstractClass);
535 else if (e->ident == Id::isFinalClass)
537 return isTypeX(e, &isTypeFinalClass);
539 else if (e->ident == Id::isTemplate)
541 return isSymbolX(e, &isTemplate);
543 else if (e->ident == Id::isPOD)
545 if (dim != 1)
546 return dimError(e, 1, dim);
548 RootObject *o = (*e->args)[0];
549 Type *t = isType(o);
550 if (!t)
552 e->error("type expected as second argument of __traits %s instead of %s",
553 e->ident->toChars(), o->toChars());
554 return new ErrorExp();
557 Type *tb = t->baseElemOf();
558 if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL)
560 return (sd->isPOD()) ? True(e) : False(e);
562 return True(e);
564 else if (e->ident == Id::isNested)
566 if (dim != 1)
567 return dimError(e, 1, dim);
569 RootObject *o = (*e->args)[0];
570 Dsymbol *s = getDsymbol(o);
571 if (!s)
574 else if (AggregateDeclaration *a = s->isAggregateDeclaration())
576 return a->isNested() ? True(e) : False(e);
578 else if (FuncDeclaration *f = s->isFuncDeclaration())
580 return f->isNested() ? True(e) : False(e);
583 e->error("aggregate or function expected instead of '%s'", o->toChars());
584 return new ErrorExp();
586 else if (e->ident == Id::isAbstractFunction)
588 return isFuncX(e, &isFuncAbstractFunction);
590 else if (e->ident == Id::isVirtualFunction)
592 return isFuncX(e, &isFuncVirtualFunction);
594 else if (e->ident == Id::isVirtualMethod)
596 return isFuncX(e, &isFuncVirtualMethod);
598 else if (e->ident == Id::isFinalFunction)
600 return isFuncX(e, &isFuncFinalFunction);
602 else if (e->ident == Id::isOverrideFunction)
604 return isFuncX(e, &isFuncOverrideFunction);
606 else if (e->ident == Id::isStaticFunction)
608 return isFuncX(e, &isFuncStaticFunction);
610 else if (e->ident == Id::isRef)
612 return isDeclX(e, &isDeclRef);
614 else if (e->ident == Id::isOut)
616 return isDeclX(e, &isDeclOut);
618 else if (e->ident == Id::isLazy)
620 return isDeclX(e, &isDeclLazy);
622 else if (e->ident == Id::identifier)
624 // Get identifier for symbol as a string literal
625 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
626 * a symbol should not be folded to a constant.
627 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
629 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2))
630 return new ErrorExp();
631 if (dim != 1)
632 return dimError(e, 1, dim);
634 RootObject *o = (*e->args)[0];
635 Identifier *id = NULL;
636 if (Parameter *po = isParameter(o))
638 id = po->ident;
639 assert(id);
641 else
643 Dsymbol *s = getDsymbol(o);
644 if (!s || !s->ident)
646 e->error("argument %s has no identifier", o->toChars());
647 return new ErrorExp();
649 id = s->ident;
652 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
653 return semantic(se, sc);
655 else if (e->ident == Id::getProtection)
657 if (dim != 1)
658 return dimError(e, 1, dim);
660 Scope *sc2 = sc->push();
661 sc2->flags = sc->flags | SCOPEnoaccesscheck;
662 bool ok = TemplateInstance::semanticTiargs(e->loc, sc2, e->args, 1);
663 sc2->pop();
664 if (!ok)
665 return new ErrorExp();
667 RootObject *o = (*e->args)[0];
668 Dsymbol *s = getDsymbol(o);
669 if (!s)
671 if (!isError(o))
672 e->error("argument %s has no protection", o->toChars());
673 return new ErrorExp();
675 if (s->_scope)
676 s->semantic(s->_scope);
678 const char *protName = protectionToChars(s->prot().kind); // TODO: How about package(names)
679 assert(protName);
680 StringExp *se = new StringExp(e->loc, const_cast<char *>(protName));
681 return semantic(se, sc);
683 else if (e->ident == Id::parent)
685 if (dim != 1)
686 return dimError(e, 1, dim);
688 RootObject *o = (*e->args)[0];
689 Dsymbol *s = getDsymbol(o);
690 if (s)
692 if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943
693 s = fd->toAliasFunc();
694 if (!s->isImport()) // Bugzilla 8922
695 s = s->toParent();
697 if (!s || s->isImport())
699 e->error("argument %s has no parent", o->toChars());
700 return new ErrorExp();
703 if (FuncDeclaration *f = s->isFuncDeclaration())
705 if (TemplateDeclaration *td = getFuncTemplateDecl(f))
707 if (td->overroot) // if not start of overloaded list of TemplateDeclaration's
708 td = td->overroot; // then get the start
709 Expression *ex = new TemplateExp(e->loc, td, f);
710 ex = semantic(ex, sc);
711 return ex;
714 if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration())
716 // Directly translate to VarExp instead of FuncExp
717 Expression *ex = new VarExp(e->loc, fld, true);
718 return semantic(ex, sc);
722 return resolve(e->loc, sc, s, false);
724 else if (e->ident == Id::hasMember ||
725 e->ident == Id::getMember ||
726 e->ident == Id::getOverloads ||
727 e->ident == Id::getVirtualMethods ||
728 e->ident == Id::getVirtualFunctions)
730 if (dim != 2)
731 return dimError(e, 2, dim);
733 RootObject *o = (*e->args)[0];
734 Expression *ex = isExpression((*e->args)[1]);
735 if (!ex)
737 e->error("expression expected as second argument of __traits %s", e->ident->toChars());
738 return new ErrorExp();
740 ex = ex->ctfeInterpret();
742 StringExp *se = ex->toStringExp();
743 if (!se || se->len == 0)
745 e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars());
746 return new ErrorExp();
748 se = se->toUTF8(sc);
750 if (se->sz != 1)
752 e->error("string must be chars");
753 return new ErrorExp();
755 Identifier *id = Identifier::idPool((char *)se->string, se->len);
757 /* Prefer dsymbol, because it might need some runtime contexts.
759 Dsymbol *sym = getDsymbol(o);
760 if (sym)
762 ex = new DsymbolExp(e->loc, sym);
763 ex = new DotIdExp(e->loc, ex, id);
765 else if (Type *t = isType(o))
766 ex = typeDotIdExp(e->loc, t, id);
767 else if (Expression *ex2 = isExpression(o))
768 ex = new DotIdExp(e->loc, ex2, id);
769 else
771 e->error("invalid first argument");
772 return new ErrorExp();
775 if (e->ident == Id::hasMember)
777 if (sym)
779 if (sym->search(e->loc, id))
780 return True(e);
783 /* Take any errors as meaning it wasn't found
785 Scope *scx = sc->push();
786 scx->flags |= SCOPEignoresymbolvisibility;
787 ex = trySemantic(ex, scx);
788 scx->pop();
789 return ex ? True(e) : False(e);
791 else if (e->ident == Id::getMember)
793 if (ex->op == TOKdotid)
794 // Prevent semantic() from replacing Symbol with its initializer
795 ((DotIdExp *)ex)->wantsym = true;
796 Scope *scx = sc->push();
797 scx->flags |= SCOPEignoresymbolvisibility;
798 ex = semantic(ex, scx);
799 scx->pop();
800 return ex;
802 else if (e->ident == Id::getVirtualFunctions ||
803 e->ident == Id::getVirtualMethods ||
804 e->ident == Id::getOverloads)
806 unsigned errors = global.errors;
807 Expression *eorig = ex;
808 Scope *scx = sc->push();
809 scx->flags |= SCOPEignoresymbolvisibility;
810 ex = semantic(ex, scx);
811 if (errors < global.errors)
812 e->error("%s cannot be resolved", eorig->toChars());
813 //ex->print();
815 /* Create tuple of functions of ex
817 Expressions *exps = new Expressions();
818 FuncDeclaration *f;
819 if (ex->op == TOKvar)
821 VarExp *ve = (VarExp *)ex;
822 f = ve->var->isFuncDeclaration();
823 ex = NULL;
825 else if (ex->op == TOKdotvar)
827 DotVarExp *dve = (DotVarExp *)ex;
828 f = dve->var->isFuncDeclaration();
829 if (dve->e1->op == TOKdottype || dve->e1->op == TOKthis)
830 ex = NULL;
831 else
832 ex = dve->e1;
834 else
835 f = NULL;
836 Ptrait p;
837 p.exps = exps;
838 p.e1 = ex;
839 p.ident = e->ident;
840 overloadApply(f, &p, &fptraits);
842 ex = new TupleExp(e->loc, exps);
843 ex = semantic(ex, scx);
844 scx->pop();
845 return ex;
847 else
848 assert(0);
850 else if (e->ident == Id::classInstanceSize)
852 if (dim != 1)
853 return dimError(e, 1, dim);
855 RootObject *o = (*e->args)[0];
856 Dsymbol *s = getDsymbol(o);
857 ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL;
858 if (!cd)
860 e->error("first argument is not a class");
861 return new ErrorExp();
863 if (cd->sizeok != SIZEOKdone)
865 cd->size(cd->loc);
867 if (cd->sizeok != SIZEOKdone)
869 e->error("%s %s is forward referenced", cd->kind(), cd->toChars());
870 return new ErrorExp();
873 return new IntegerExp(e->loc, cd->structsize, Type::tsize_t);
875 else if (e->ident == Id::getAliasThis)
877 if (dim != 1)
878 return dimError(e, 1, dim);
880 RootObject *o = (*e->args)[0];
881 Dsymbol *s = getDsymbol(o);
882 AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL;
883 if (!ad)
885 e->error("argument is not an aggregate type");
886 return new ErrorExp();
889 Expressions *exps = new Expressions();
890 if (ad->aliasthis)
891 exps->push(new StringExp(e->loc, const_cast<char *>(ad->aliasthis->ident->toChars())));
892 Expression *ex = new TupleExp(e->loc, exps);
893 ex = semantic(ex, sc);
894 return ex;
896 else if (e->ident == Id::getAttributes)
898 if (dim != 1)
899 return dimError(e, 1, dim);
901 RootObject *o = (*e->args)[0];
902 Dsymbol *s = getDsymbol(o);
903 if (!s)
905 e->error("first argument is not a symbol");
906 return new ErrorExp();
908 if (Import *imp = s->isImport())
910 s = imp->mod;
913 //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
914 UserAttributeDeclaration *udad = s->userAttribDecl;
915 Expressions *exps = udad ? udad->getAttributes() : new Expressions();
916 TupleExp *tup = new TupleExp(e->loc, exps);
917 return semantic(tup, sc);
919 else if (e->ident == Id::getFunctionAttributes)
921 /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
922 if (dim != 1)
923 return dimError(e, 1, dim);
925 RootObject *o = (*e->args)[0];
926 Dsymbol *s = getDsymbol(o);
927 Type *t = isType(o);
928 TypeFunction *tf = NULL;
929 if (s)
931 if (FuncDeclaration *f = s->isFuncDeclaration())
932 t = f->type;
933 else if (VarDeclaration *v = s->isVarDeclaration())
934 t = v->type;
936 if (t)
938 if (t->ty == Tfunction)
939 tf = (TypeFunction *)t;
940 else if (t->ty == Tdelegate)
941 tf = (TypeFunction *)t->nextOf();
942 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
943 tf = (TypeFunction *)t->nextOf();
945 if (!tf)
947 e->error("first argument is not a function");
948 return new ErrorExp();
951 Expressions *mods = new Expressions();
952 PushAttributes pa;
953 pa.mods = mods;
954 tf->modifiersApply(&pa, &PushAttributes::fp);
955 tf->attributesApply(&pa, &PushAttributes::fp, TRUSTformatSystem);
957 TupleExp *tup = new TupleExp(e->loc, mods);
958 return semantic(tup, sc);
960 else if (e->ident == Id::getFunctionVariadicStyle)
962 /* Accept a symbol or a type. Returns one of the following:
963 * "none" not a variadic function
964 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
965 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
966 * "typesafe" void typesafe(T[] ...)
968 // get symbol linkage as a string
969 if (dim != 1)
970 return dimError(e, 1, dim);
972 LINK link;
973 int varargs;
974 RootObject *o = (*e->args)[0];
975 Type *t = isType(o);
976 TypeFunction *tf = NULL;
977 if (t)
979 if (t->ty == Tfunction)
980 tf = (TypeFunction *)t;
981 else if (t->ty == Tdelegate)
982 tf = (TypeFunction *)t->nextOf();
983 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
984 tf = (TypeFunction *)t->nextOf();
986 if (tf)
988 link = tf->linkage;
989 varargs = tf->varargs;
991 else
993 Dsymbol *s = getDsymbol(o);
994 FuncDeclaration *fd = NULL;
995 if (!s || (fd = s->isFuncDeclaration()) == NULL)
997 e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars());
998 return new ErrorExp();
1000 link = fd->linkage;
1001 fd->getParameters(&varargs);
1003 const char *style;
1004 switch (varargs)
1006 case 0: style = "none"; break;
1007 case 1: style = (link == LINKd) ? "argptr"
1008 : "stdarg"; break;
1009 case 2: style = "typesafe"; break;
1010 default:
1011 assert(0);
1013 StringExp *se = new StringExp(e->loc, const_cast<char*>(style));
1014 return semantic(se, sc);
1016 else if (e->ident == Id::getParameterStorageClasses)
1018 /* Accept a function symbol or a type, followed by a parameter index.
1019 * Returns a tuple of strings of the parameter's storage classes.
1021 // get symbol linkage as a string
1022 if (dim != 2)
1023 return dimError(e, 2, dim);
1025 RootObject *o1 = (*e->args)[1];
1026 RootObject *o = (*e->args)[0];
1027 Type *t = isType(o);
1028 TypeFunction *tf = NULL;
1029 if (t)
1031 if (t->ty == Tfunction)
1032 tf = (TypeFunction *)t;
1033 else if (t->ty == Tdelegate)
1034 tf = (TypeFunction *)t->nextOf();
1035 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
1036 tf = (TypeFunction *)t->nextOf();
1038 Parameters* fparams;
1039 if (tf)
1041 fparams = tf->parameters;
1043 else
1045 Dsymbol *s = getDsymbol(o);
1046 FuncDeclaration *fd = NULL;
1047 if (!s || (fd = s->isFuncDeclaration()) == NULL)
1049 e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
1050 o->toChars(), o1->toChars());
1051 return new ErrorExp();
1053 fparams = fd->getParameters(NULL);
1056 StorageClass stc;
1058 // Set stc to storage class of the ith parameter
1059 Expression *ex = isExpression((*e->args)[1]);
1060 if (!ex)
1062 e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1063 o->toChars(), o1->toChars());
1064 return new ErrorExp();
1066 ex = ex->ctfeInterpret();
1067 uinteger_t ii = ex->toUInteger();
1068 if (ii >= Parameter::dim(fparams))
1070 e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars());
1071 return new ErrorExp();
1074 unsigned n = (unsigned)ii;
1075 Parameter *p = Parameter::getNth(fparams, n);
1076 stc = p->storageClass;
1078 // This mirrors hdrgen.visit(Parameter p)
1079 if (p->type && p->type->mod & MODshared)
1080 stc &= ~STCshared;
1082 Expressions *exps = new Expressions;
1084 if (stc & STCauto)
1085 exps->push(new StringExp(e->loc, const_cast<char *>("auto")));
1086 if (stc & STCreturn)
1087 exps->push(new StringExp(e->loc, const_cast<char *>("return")));
1089 if (stc & STCout)
1090 exps->push(new StringExp(e->loc, const_cast<char *>("out")));
1091 else if (stc & STCref)
1092 exps->push(new StringExp(e->loc, const_cast<char *>("ref")));
1093 else if (stc & STCin)
1094 exps->push(new StringExp(e->loc, const_cast<char *>("in")));
1095 else if (stc & STClazy)
1096 exps->push(new StringExp(e->loc, const_cast<char *>("lazy")));
1097 else if (stc & STCalias)
1098 exps->push(new StringExp(e->loc, const_cast<char *>("alias")));
1100 if (stc & STCconst)
1101 exps->push(new StringExp(e->loc, const_cast<char *>("const")));
1102 if (stc & STCimmutable)
1103 exps->push(new StringExp(e->loc, const_cast<char *>("immutable")));
1104 if (stc & STCwild)
1105 exps->push(new StringExp(e->loc, const_cast<char *>("inout")));
1106 if (stc & STCshared)
1107 exps->push(new StringExp(e->loc, const_cast<char *>("shared")));
1108 if (stc & STCscope && !(stc & STCscopeinferred))
1109 exps->push(new StringExp(e->loc, const_cast<char *>("scope")));
1111 TupleExp *tup = new TupleExp(e->loc, exps);
1112 return semantic(tup, sc);
1114 else if (e->ident == Id::getLinkage)
1116 // get symbol linkage as a string
1117 if (dim != 1)
1118 return dimError(e, 1, dim);
1120 LINK link;
1121 RootObject *o = (*e->args)[0];
1122 Type *t = isType(o);
1123 TypeFunction *tf = NULL;
1124 if (t)
1126 if (t->ty == Tfunction)
1127 tf = (TypeFunction *)t;
1128 else if (t->ty == Tdelegate)
1129 tf = (TypeFunction *)t->nextOf();
1130 else if (t->ty == Tpointer && t->nextOf()->ty == Tfunction)
1131 tf = (TypeFunction *)t->nextOf();
1133 if (tf)
1134 link = tf->linkage;
1135 else
1137 Dsymbol *s = getDsymbol(o);
1138 Declaration *d = NULL;
1139 if (!s || (d = s->isDeclaration()) == NULL)
1141 e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars());
1142 return new ErrorExp();
1144 link = d->linkage;
1146 const char *linkage = linkageToChars(link);
1147 StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage));
1148 return semantic(se, sc);
1150 else if (e->ident == Id::allMembers ||
1151 e->ident == Id::derivedMembers)
1153 if (dim != 1)
1154 return dimError(e, 1, dim);
1156 RootObject *o = (*e->args)[0];
1157 Dsymbol *s = getDsymbol(o);
1158 if (!s)
1160 e->error("argument has no members");
1161 return new ErrorExp();
1163 if (Import *imp = s->isImport())
1165 // Bugzilla 9692
1166 s = imp->mod;
1169 ScopeDsymbol *sds = s->isScopeDsymbol();
1170 if (!sds || sds->isTemplateDeclaration())
1172 e->error("%s %s has no members", s->kind(), s->toChars());
1173 return new ErrorExp();
1176 // use a struct as local function
1177 struct PushIdentsDg
1179 ScopeDsymbol *sds;
1180 Identifiers *idents;
1182 static int dg(void *ctx, size_t, Dsymbol *sm)
1184 if (!sm)
1185 return 1;
1186 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
1187 if (sm->ident)
1189 const char *idx = sm->ident->toChars();
1190 if (idx[0] == '_' && idx[1] == '_' &&
1191 sm->ident != Id::ctor &&
1192 sm->ident != Id::dtor &&
1193 sm->ident != Id::__xdtor &&
1194 sm->ident != Id::postblit &&
1195 sm->ident != Id::__xpostblit)
1197 return 0;
1200 if (sm->ident == Id::empty)
1202 return 0;
1204 if (sm->isTypeInfoDeclaration()) // Bugzilla 15177
1205 return 0;
1206 PushIdentsDg *pid = (PushIdentsDg *)ctx;
1207 if (!pid->sds->isModule() && sm->isImport()) // Bugzilla 17057
1208 return 0;
1210 //printf("\t%s\n", sm->ident->toChars());
1211 Identifiers *idents = pid->idents;
1213 /* Skip if already present in idents[]
1215 for (size_t j = 0; j < idents->dim; j++)
1217 Identifier *id = (*idents)[j];
1218 if (id == sm->ident)
1219 return 0;
1222 idents->push(sm->ident);
1224 else
1226 EnumDeclaration *ed = sm->isEnumDeclaration();
1227 if (ed)
1229 ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx);
1232 return 0;
1236 Identifiers *idents = new Identifiers;
1237 PushIdentsDg ctx;
1238 ctx.sds = sds;
1239 ctx.idents = idents;
1240 ScopeDsymbol_foreach(sc, sds->members, &PushIdentsDg::dg, &ctx);
1241 ClassDeclaration *cd = sds->isClassDeclaration();
1242 if (cd && e->ident == Id::allMembers)
1244 if (cd->_scope)
1245 cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference
1247 struct PushBaseMembers
1249 static void dg(ClassDeclaration *cd, PushIdentsDg *ctx)
1251 for (size_t i = 0; i < cd->baseclasses->dim; i++)
1253 ClassDeclaration *cb = (*cd->baseclasses)[i]->sym;
1254 assert(cb);
1255 ScopeDsymbol_foreach(NULL, cb->members, &PushIdentsDg::dg, ctx);
1256 if (cb->baseclasses->dim)
1257 dg(cb, ctx);
1261 PushBaseMembers::dg(cd, &ctx);
1264 // Turn Identifiers into StringExps reusing the allocated array
1265 assert(sizeof(Expressions) == sizeof(Identifiers));
1266 Expressions *exps = (Expressions *)idents;
1267 for (size_t i = 0; i < idents->dim; i++)
1269 Identifier *id = (*idents)[i];
1270 StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars()));
1271 (*exps)[i] = se;
1274 /* Making this a tuple is more flexible, as it can be statically unrolled.
1275 * To make an array literal, enclose __traits in [ ]:
1276 * [ __traits(allMembers, ...) ]
1278 Expression *ex = new TupleExp(e->loc, exps);
1279 ex = semantic(ex, sc);
1280 return ex;
1282 else if (e->ident == Id::compiles)
1284 /* Determine if all the objects - types, expressions, or symbols -
1285 * compile without error
1287 if (!dim)
1288 return False(e);
1290 for (size_t i = 0; i < dim; i++)
1292 unsigned errors = global.startGagging();
1293 Scope *sc2 = sc->push();
1294 sc2->tinst = NULL;
1295 sc2->minst = NULL;
1296 sc2->flags = (sc->flags & ~(SCOPEctfe | SCOPEcondition)) | SCOPEcompile | SCOPEfullinst;
1297 bool err = false;
1299 RootObject *o = (*e->args)[i];
1300 Type *t = isType(o);
1301 Expression *ex = t ? typeToExpression(t) : isExpression(o);
1302 if (!ex && t)
1304 Dsymbol *s;
1305 t->resolve(e->loc, sc2, &ex, &t, &s);
1306 if (t)
1308 t->semantic(e->loc, sc2);
1309 if (t->ty == Terror)
1310 err = true;
1312 else if (s && s->errors)
1313 err = true;
1315 if (ex)
1317 ex = semantic(ex, sc2);
1318 ex = resolvePropertiesOnly(sc2, ex);
1319 ex = ex->optimize(WANTvalue);
1320 if (sc2->func && sc2->func->type->ty == Tfunction)
1322 TypeFunction *tf = (TypeFunction *)sc2->func->type;
1323 canThrow(ex, sc2->func, tf->isnothrow);
1325 ex = checkGC(sc2, ex);
1326 if (ex->op == TOKerror)
1327 err = true;
1330 // Carefully detach the scope from the parent and throw it away as
1331 // we only need it to evaluate the expression
1332 // https://issues.dlang.org/show_bug.cgi?id=15428
1333 freeFieldinit(sc2);
1334 sc2->enclosing = NULL;
1335 sc2->pop();
1337 if (global.endGagging(errors) || err)
1339 return False(e);
1342 return True(e);
1344 else if (e->ident == Id::isSame)
1346 /* Determine if two symbols are the same
1348 if (dim != 2)
1349 return dimError(e, 2, dim);
1351 if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0))
1352 return new ErrorExp();
1354 RootObject *o1 = (*e->args)[0];
1355 RootObject *o2 = (*e->args)[1];
1356 Dsymbol *s1 = getDsymbol(o1);
1357 Dsymbol *s2 = getDsymbol(o2);
1358 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
1359 if (!s1 && !s2)
1361 Expression *ea1 = isExpression(o1);
1362 Expression *ea2 = isExpression(o2);
1363 if (ea1 && ea2)
1365 if (ea1->equals(ea2))
1366 return True(e);
1369 if (!s1 || !s2)
1370 return False(e);
1371 s1 = s1->toAlias();
1372 s2 = s2->toAlias();
1374 if (s1->isFuncAliasDeclaration())
1375 s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc();
1376 if (s2->isFuncAliasDeclaration())
1377 s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc();
1379 return (s1 == s2) ? True(e) : False(e);
1381 else if (e->ident == Id::getUnitTests)
1383 if (dim != 1)
1384 return dimError(e, 1, dim);
1386 RootObject *o = (*e->args)[0];
1387 Dsymbol *s = getDsymbol(o);
1388 if (!s)
1390 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1391 o->toChars());
1392 return new ErrorExp();
1394 if (Import *imp = s->isImport()) // Bugzilla 10990
1395 s = imp->mod;
1397 ScopeDsymbol* sds = s->isScopeDsymbol();
1398 if (!sds)
1400 e->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
1401 s->toChars(), s->kind());
1402 return new ErrorExp();
1405 Expressions *exps = new Expressions();
1406 if (global.params.useUnitTests)
1408 // Should actually be a set
1409 AA* uniqueUnitTests = NULL;
1410 collectUnitTests(sds->members, uniqueUnitTests, exps);
1412 TupleExp *te= new TupleExp(e->loc, exps);
1413 return semantic(te, sc);
1415 else if(e->ident == Id::getVirtualIndex)
1417 if (dim != 1)
1418 return dimError(e, 1, dim);
1420 RootObject *o = (*e->args)[0];
1421 Dsymbol *s = getDsymbol(o);
1423 FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL;
1424 if (!fd)
1426 e->error("first argument to __traits(getVirtualIndex) must be a function");
1427 return new ErrorExp();
1430 fd = fd->toAliasFunc(); // Neccessary to support multiple overloads.
1431 return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t);
1433 else if (e->ident == Id::getPointerBitmap)
1435 return pointerBitmap(e);
1438 if (const char *sub = (const char *)speller(e->ident->toChars(), &trait_search_fp, NULL, idchars))
1439 e->error("unrecognized trait '%s', did you mean '%s'?", e->ident->toChars(), sub);
1440 else
1441 e->error("unrecognized trait '%s'", e->ident->toChars());
1442 return new ErrorExp();
1444 e->error("wrong number of arguments %d", (int)dim);
1445 return new ErrorExp();