]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
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 | */ | |
10 | ||
f9ab59ff | 11 | #include "root/dsystem.h" |
b4c522fa IB |
12 | #include "root/rmem.h" |
13 | #include "root/aav.h" | |
f9ab59ff | 14 | #include "root/checkedint.h" |
b4c522fa | 15 | |
b4c522fa IB |
16 | #include "errors.h" |
17 | #include "mtype.h" | |
18 | #include "init.h" | |
19 | #include "expression.h" | |
20 | #include "template.h" | |
21 | #include "utf.h" | |
22 | #include "enum.h" | |
23 | #include "scope.h" | |
24 | #include "hdrgen.h" | |
25 | #include "statement.h" | |
26 | #include "declaration.h" | |
27 | #include "aggregate.h" | |
28 | #include "import.h" | |
29 | #include "id.h" | |
30 | #include "dsymbol.h" | |
31 | #include "module.h" | |
32 | #include "attrib.h" | |
33 | #include "parse.h" | |
34 | #include "root/speller.h" | |
35 | ||
36 | typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); | |
37 | int ScopeDsymbol_foreach(Scope *sc, Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn = NULL); | |
38 | void freeFieldinit(Scope *sc); | |
39 | Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads); | |
40 | Expression *trySemantic(Expression *e, Scope *sc); | |
41 | Expression *semantic(Expression *e, Scope *sc); | |
42 | Expression *typeToExpression(Type *t); | |
43 | ||
44 | ||
45 | /************************************************ | |
46 | * Delegate to be passed to overloadApply() that looks | |
47 | * for functions matching a trait. | |
48 | */ | |
49 | ||
50 | struct Ptrait | |
51 | { | |
52 | Expression *e1; | |
53 | Expressions *exps; // collected results | |
54 | Identifier *ident; // which trait we're looking for | |
55 | }; | |
56 | ||
57 | static int fptraits(void *param, Dsymbol *s) | |
58 | { | |
59 | FuncDeclaration *f = s->isFuncDeclaration(); | |
60 | if (!f) | |
61 | return 0; | |
62 | ||
63 | Ptrait *p = (Ptrait *)param; | |
64 | if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) | |
65 | return 0; | |
66 | ||
67 | if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) | |
68 | return 0; | |
69 | ||
70 | Expression *e; | |
71 | FuncAliasDeclaration* ad = new FuncAliasDeclaration(f->ident, f, false); | |
72 | ad->protection = f->protection; | |
73 | if (p->e1) | |
74 | e = new DotVarExp(Loc(), p->e1, ad, false); | |
75 | else | |
76 | e = new DsymbolExp(Loc(), ad, false); | |
77 | p->exps->push(e); | |
78 | return 0; | |
79 | } | |
80 | ||
81 | /** | |
82 | * Collects all unit test functions from the given array of symbols. | |
83 | * | |
84 | * This is a helper function used by the implementation of __traits(getUnitTests). | |
85 | * | |
86 | * Input: | |
87 | * symbols array of symbols to collect the functions from | |
88 | * uniqueUnitTests an associative array (should actually be a set) to | |
89 | * keep track of already collected functions. We're | |
90 | * using an AA here to avoid doing a linear search of unitTests | |
91 | * | |
92 | * Output: | |
93 | * unitTests array of DsymbolExp's of the collected unit test functions | |
94 | * uniqueUnitTests updated with symbols from unitTests[ ] | |
95 | */ | |
96 | static void collectUnitTests(Dsymbols *symbols, AA *uniqueUnitTests, Expressions *unitTests) | |
97 | { | |
98 | if (!symbols) | |
99 | return; | |
100 | for (size_t i = 0; i < symbols->dim; i++) | |
101 | { | |
102 | Dsymbol *symbol = (*symbols)[i]; | |
103 | UnitTestDeclaration *unitTest = symbol->isUnitTestDeclaration(); | |
104 | if (unitTest) | |
105 | { | |
106 | if (!dmd_aaGetRvalue(uniqueUnitTests, (void *)unitTest)) | |
107 | { | |
108 | FuncAliasDeclaration* ad = new FuncAliasDeclaration(unitTest->ident, unitTest, false); | |
109 | ad->protection = unitTest->protection; | |
110 | Expression* e = new DsymbolExp(Loc(), ad, false); | |
111 | unitTests->push(e); | |
112 | bool* value = (bool*) dmd_aaGet(&uniqueUnitTests, (void *)unitTest); | |
113 | *value = true; | |
114 | } | |
115 | } | |
116 | else | |
117 | { | |
118 | AttribDeclaration *attrDecl = symbol->isAttribDeclaration(); | |
119 | ||
120 | if (attrDecl) | |
121 | { | |
122 | Dsymbols *decl = attrDecl->include(NULL, NULL); | |
123 | collectUnitTests(decl, uniqueUnitTests, unitTests); | |
124 | } | |
125 | } | |
126 | } | |
127 | } | |
128 | ||
129 | /************************ TraitsExp ************************************/ | |
130 | ||
131 | static Expression *True(TraitsExp *e) { return new IntegerExp(e->loc, true, Type::tbool); } | |
132 | static Expression *False(TraitsExp *e) { return new IntegerExp(e->loc, false, Type::tbool); } | |
133 | ||
134 | bool isTypeArithmetic(Type *t) { return t->isintegral() || t->isfloating(); } | |
135 | bool isTypeFloating(Type *t) { return t->isfloating(); } | |
136 | bool isTypeIntegral(Type *t) { return t->isintegral(); } | |
137 | bool isTypeScalar(Type *t) { return t->isscalar(); } | |
138 | bool isTypeUnsigned(Type *t) { return t->isunsigned(); } | |
139 | bool isTypeAssociativeArray(Type *t) { return t->toBasetype()->ty == Taarray; } | |
140 | bool isTypeStaticArray(Type *t) { return t->toBasetype()->ty == Tsarray; } | |
141 | bool isTypeAbstractClass(Type *t) { return t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract(); } | |
142 | bool isTypeFinalClass(Type *t) { return t->toBasetype()->ty == Tclass && (((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) != 0; } | |
143 | ||
144 | Expression *isTypeX(TraitsExp *e, bool (*fp)(Type *t)) | |
145 | { | |
146 | if (!e->args || !e->args->dim) | |
147 | return False(e); | |
148 | for (size_t i = 0; i < e->args->dim; i++) | |
149 | { | |
150 | Type *t = getType((*e->args)[i]); | |
151 | if (!t || !fp(t)) | |
152 | return False(e); | |
153 | } | |
154 | return True(e); | |
155 | } | |
156 | ||
157 | bool isFuncAbstractFunction(FuncDeclaration *f) { return f->isAbstract(); } | |
158 | bool isFuncVirtualFunction(FuncDeclaration *f) { return f->isVirtual(); } | |
159 | bool isFuncVirtualMethod(FuncDeclaration *f) { return f->isVirtualMethod(); } | |
160 | bool isFuncFinalFunction(FuncDeclaration *f) { return f->isFinalFunc(); } | |
161 | bool isFuncStaticFunction(FuncDeclaration *f) { return !f->needThis() && !f->isNested(); } | |
162 | bool isFuncOverrideFunction(FuncDeclaration *f) { return f->isOverride(); } | |
163 | ||
164 | Expression *isFuncX(TraitsExp *e, bool (*fp)(FuncDeclaration *f)) | |
165 | { | |
166 | if (!e->args || !e->args->dim) | |
167 | return False(e); | |
168 | for (size_t i = 0; i < e->args->dim; i++) | |
169 | { | |
170 | Dsymbol *s = getDsymbol((*e->args)[i]); | |
171 | if (!s) | |
172 | return False(e); | |
173 | FuncDeclaration *f = s->isFuncDeclaration(); | |
174 | if (!f || !fp(f)) | |
175 | return False(e); | |
176 | } | |
177 | return True(e); | |
178 | } | |
179 | ||
180 | bool isDeclRef(Declaration *d) { return d->isRef(); } | |
181 | bool isDeclOut(Declaration *d) { return d->isOut(); } | |
182 | bool isDeclLazy(Declaration *d) { return (d->storage_class & STClazy) != 0; } | |
183 | ||
184 | Expression *isDeclX(TraitsExp *e, bool (*fp)(Declaration *d)) | |
185 | { | |
186 | if (!e->args || !e->args->dim) | |
187 | return False(e); | |
188 | for (size_t i = 0; i < e->args->dim; i++) | |
189 | { | |
190 | Dsymbol *s = getDsymbol((*e->args)[i]); | |
191 | if (!s) | |
192 | return False(e); | |
193 | Declaration *d = s->isDeclaration(); | |
194 | if (!d || !fp(d)) | |
195 | return False(e); | |
196 | } | |
197 | return True(e); | |
198 | } | |
199 | ||
200 | // callback for TypeFunction::attributesApply | |
201 | struct PushAttributes | |
202 | { | |
203 | Expressions *mods; | |
204 | ||
205 | static int fp(void *param, const char *str) | |
206 | { | |
207 | PushAttributes *p = (PushAttributes *)param; | |
208 | p->mods->push(new StringExp(Loc(), const_cast<char *>(str))); | |
209 | return 0; | |
210 | } | |
211 | }; | |
212 | ||
213 | StringTable traitsStringTable; | |
214 | ||
215 | struct TraitsInitializer | |
216 | { | |
217 | TraitsInitializer(); | |
218 | }; | |
219 | ||
220 | static TraitsInitializer traitsinitializer; | |
221 | ||
222 | TraitsInitializer::TraitsInitializer() | |
223 | { | |
224 | const char* traits[] = { | |
225 | "isAbstractClass", | |
226 | "isArithmetic", | |
227 | "isAssociativeArray", | |
228 | "isFinalClass", | |
229 | "isPOD", | |
230 | "isNested", | |
231 | "isFloating", | |
232 | "isIntegral", | |
233 | "isScalar", | |
234 | "isStaticArray", | |
235 | "isUnsigned", | |
236 | "isVirtualFunction", | |
237 | "isVirtualMethod", | |
238 | "isAbstractFunction", | |
239 | "isFinalFunction", | |
240 | "isOverrideFunction", | |
241 | "isStaticFunction", | |
242 | "isRef", | |
243 | "isOut", | |
244 | "isLazy", | |
245 | "hasMember", | |
246 | "identifier", | |
247 | "getProtection", | |
248 | "parent", | |
249 | "getLinkage", | |
250 | "getMember", | |
251 | "getOverloads", | |
252 | "getVirtualFunctions", | |
253 | "getVirtualMethods", | |
254 | "classInstanceSize", | |
255 | "allMembers", | |
256 | "derivedMembers", | |
257 | "isSame", | |
258 | "compiles", | |
259 | "parameters", | |
260 | "getAliasThis", | |
261 | "getAttributes", | |
262 | "getFunctionAttributes", | |
263 | "getFunctionVariadicStyle", | |
264 | "getParameterStorageClasses", | |
265 | "getUnitTests", | |
266 | "getVirtualIndex", | |
267 | "getPointerBitmap", | |
268 | NULL | |
269 | }; | |
270 | ||
271 | traitsStringTable._init(40); | |
272 | ||
273 | for (size_t idx = 0;; idx++) | |
274 | { | |
275 | const char *s = traits[idx]; | |
276 | if (!s) break; | |
277 | StringValue *sv = traitsStringTable.insert(s, strlen(s), const_cast<char *>(s)); | |
278 | assert(sv); | |
279 | } | |
280 | } | |
281 | ||
282 | void *trait_search_fp(void *, const char *seed, int* cost) | |
283 | { | |
284 | //printf("trait_search_fp('%s')\n", seed); | |
285 | size_t len = strlen(seed); | |
286 | if (!len) | |
287 | return NULL; | |
288 | ||
289 | *cost = 0; | |
290 | StringValue *sv = traitsStringTable.lookup(seed, len); | |
291 | return sv ? (void*)sv->ptrvalue : NULL; | |
292 | } | |
293 | ||
294 | static int fpisTemplate(void *, Dsymbol *s) | |
295 | { | |
296 | if (s->isTemplateDeclaration()) | |
297 | return 1; | |
298 | ||
299 | return 0; | |
300 | } | |
301 | ||
302 | bool isTemplate(Dsymbol *s) | |
303 | { | |
304 | if (!s->toAlias()->isOverloadable()) | |
305 | return false; | |
306 | ||
307 | return overloadApply(s, NULL, &fpisTemplate) != 0; | |
308 | } | |
309 | ||
310 | Expression *isSymbolX(TraitsExp *e, bool (*fp)(Dsymbol *s)) | |
311 | { | |
312 | if (!e->args || !e->args->dim) | |
313 | return False(e); | |
314 | for (size_t i = 0; i < e->args->dim; i++) | |
315 | { | |
316 | Dsymbol *s = getDsymbol((*e->args)[i]); | |
317 | if (!s || !fp(s)) | |
318 | return False(e); | |
319 | } | |
320 | return True(e); | |
321 | } | |
322 | ||
323 | /** | |
324 | * get an array of size_t values that indicate possible pointer words in memory | |
325 | * if interpreted as the type given as argument | |
326 | * the first array element is the size of the type for independent interpretation | |
327 | * of the array | |
328 | * following elements bits represent one word (4/8 bytes depending on the target | |
329 | * architecture). If set the corresponding memory might contain a pointer/reference. | |
330 | * | |
331 | * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] | |
332 | */ | |
333 | Expression *pointerBitmap(TraitsExp *e) | |
334 | { | |
335 | if (!e->args || e->args->dim != 1) | |
336 | { | |
337 | error(e->loc, "a single type expected for trait pointerBitmap"); | |
338 | return new ErrorExp(); | |
339 | } | |
340 | Type *t = getType((*e->args)[0]); | |
341 | if (!t) | |
342 | { | |
343 | error(e->loc, "%s is not a type", (*e->args)[0]->toChars()); | |
344 | return new ErrorExp(); | |
345 | } | |
346 | d_uns64 sz; | |
347 | if (t->ty == Tclass && !((TypeClass*)t)->sym->isInterfaceDeclaration()) | |
348 | sz = ((TypeClass*)t)->sym->AggregateDeclaration::size(e->loc); | |
349 | else | |
350 | sz = t->size(e->loc); | |
351 | if (sz == SIZE_INVALID) | |
352 | return new ErrorExp(); | |
353 | ||
354 | const d_uns64 sz_size_t = Type::tsize_t->size(e->loc); | |
355 | if (sz > UINT64_MAX - sz_size_t) | |
356 | { | |
357 | error(e->loc, "size overflow for type %s", t->toChars()); | |
358 | return new ErrorExp(); | |
359 | } | |
360 | ||
361 | d_uns64 bitsPerWord = sz_size_t * 8; | |
362 | d_uns64 cntptr = (sz + sz_size_t - 1) / sz_size_t; | |
363 | d_uns64 cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; | |
364 | Array<d_uns64> data; | |
365 | data.setDim((size_t)cntdata); | |
366 | data.zero(); | |
367 | ||
368 | class PointerBitmapVisitor : public Visitor | |
369 | { | |
370 | public: | |
371 | PointerBitmapVisitor(Array<d_uns64>* _data, d_uns64 _sz_size_t) | |
372 | : data(_data), offset(0), sz_size_t(_sz_size_t), error(false) | |
373 | {} | |
374 | ||
375 | void setpointer(d_uns64 off) | |
376 | { | |
377 | d_uns64 ptroff = off / sz_size_t; | |
378 | (*data)[(size_t)(ptroff / (8 * sz_size_t))] |= 1LL << (ptroff % (8 * sz_size_t)); | |
379 | } | |
380 | virtual void visit(Type *t) | |
381 | { | |
382 | Type *tb = t->toBasetype(); | |
383 | if (tb != t) | |
384 | tb->accept(this); | |
385 | } | |
386 | virtual void visit(TypeError *t) { visit((Type *)t); } | |
387 | virtual void visit(TypeNext *) { assert(0); } | |
388 | virtual void visit(TypeBasic *t) | |
389 | { | |
390 | if (t->ty == Tvoid) | |
391 | setpointer(offset); | |
392 | } | |
393 | virtual void visit(TypeVector *) { } | |
394 | virtual void visit(TypeArray *) { assert(0); } | |
395 | virtual void visit(TypeSArray *t) | |
396 | { | |
397 | d_uns64 arrayoff = offset; | |
398 | d_uns64 nextsize = t->next->size(); | |
399 | if (nextsize == SIZE_INVALID) | |
400 | error = true; | |
401 | d_uns64 dim = t->dim->toInteger(); | |
402 | for (d_uns64 i = 0; i < dim; i++) | |
403 | { | |
404 | offset = arrayoff + i * nextsize; | |
405 | t->next->accept(this); | |
406 | } | |
407 | offset = arrayoff; | |
408 | } | |
409 | virtual void visit(TypeDArray *) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr} | |
410 | virtual void visit(TypeAArray *) { setpointer(offset); } | |
411 | virtual void visit(TypePointer *t) | |
412 | { | |
413 | if (t->nextOf()->ty != Tfunction) // don't mark function pointers | |
414 | setpointer(offset); | |
415 | } | |
416 | virtual void visit(TypeReference *) { setpointer(offset); } | |
417 | virtual void visit(TypeClass *) { setpointer(offset); } | |
418 | virtual void visit(TypeFunction *) { } | |
419 | virtual void visit(TypeDelegate *) { setpointer(offset); } // delegate is {context, function} | |
420 | virtual void visit(TypeQualified *) { assert(0); } // assume resolved | |
421 | virtual void visit(TypeIdentifier *) { assert(0); } | |
422 | virtual void visit(TypeInstance *) { assert(0); } | |
423 | virtual void visit(TypeTypeof *) { assert(0); } | |
424 | virtual void visit(TypeReturn *) { assert(0); } | |
425 | virtual void visit(TypeEnum *t) { visit((Type *)t); } | |
426 | virtual void visit(TypeTuple *t) { visit((Type *)t); } | |
427 | virtual void visit(TypeSlice *) { assert(0); } | |
428 | virtual void visit(TypeNull *) { } // always a null pointer | |
429 | ||
430 | virtual void visit(TypeStruct *t) | |
431 | { | |
432 | d_uns64 structoff = offset; | |
433 | for (size_t i = 0; i < t->sym->fields.dim; i++) | |
434 | { | |
435 | VarDeclaration *v = t->sym->fields[i]; | |
436 | offset = structoff + v->offset; | |
437 | if (v->type->ty == Tclass) | |
438 | setpointer(offset); | |
439 | else | |
440 | v->type->accept(this); | |
441 | } | |
442 | offset = structoff; | |
443 | } | |
444 | ||
445 | // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references | |
446 | void visitClass(TypeClass* t) | |
447 | { | |
448 | d_uns64 classoff = offset; | |
449 | ||
450 | // skip vtable-ptr and monitor | |
451 | if (t->sym->baseClass) | |
452 | visitClass((TypeClass*)t->sym->baseClass->type); | |
453 | ||
454 | for (size_t i = 0; i < t->sym->fields.dim; i++) | |
455 | { | |
456 | VarDeclaration *v = t->sym->fields[i]; | |
457 | offset = classoff + v->offset; | |
458 | v->type->accept(this); | |
459 | } | |
460 | offset = classoff; | |
461 | } | |
462 | ||
463 | Array<d_uns64>* data; | |
464 | d_uns64 offset; | |
465 | d_uns64 sz_size_t; | |
466 | bool error; | |
467 | }; | |
468 | ||
469 | PointerBitmapVisitor pbv(&data, sz_size_t); | |
470 | if (t->ty == Tclass) | |
471 | pbv.visitClass((TypeClass*)t); | |
472 | else | |
473 | t->accept(&pbv); | |
474 | if (pbv.error) | |
475 | return new ErrorExp(); | |
476 | ||
477 | Expressions* exps = new Expressions; | |
478 | exps->push(new IntegerExp(e->loc, sz, Type::tsize_t)); | |
479 | for (d_uns64 i = 0; i < cntdata; i++) | |
480 | exps->push(new IntegerExp(e->loc, data[(size_t)i], Type::tsize_t)); | |
481 | ||
482 | ArrayLiteralExp* ale = new ArrayLiteralExp(e->loc, exps); | |
483 | ale->type = Type::tsize_t->sarrayOf(cntdata + 1); | |
484 | return ale; | |
485 | } | |
486 | ||
487 | static Expression *dimError(TraitsExp *e, int expected, int dim) | |
488 | { | |
489 | e->error("expected %d arguments for `%s` but had %d", expected, e->ident->toChars(), dim); | |
490 | return new ErrorExp(); | |
491 | } | |
492 | ||
493 | Expression *semanticTraits(TraitsExp *e, Scope *sc) | |
494 | { | |
495 | if (e->ident != Id::compiles && e->ident != Id::isSame && | |
496 | e->ident != Id::identifier && e->ident != Id::getProtection) | |
497 | { | |
498 | if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 1)) | |
499 | return new ErrorExp(); | |
500 | } | |
501 | size_t dim = e->args ? e->args->dim : 0; | |
502 | ||
503 | if (e->ident == Id::isArithmetic) | |
504 | { | |
505 | return isTypeX(e, &isTypeArithmetic); | |
506 | } | |
507 | else if (e->ident == Id::isFloating) | |
508 | { | |
509 | return isTypeX(e, &isTypeFloating); | |
510 | } | |
511 | else if (e->ident == Id::isIntegral) | |
512 | { | |
513 | return isTypeX(e, &isTypeIntegral); | |
514 | } | |
515 | else if (e->ident == Id::isScalar) | |
516 | { | |
517 | return isTypeX(e, &isTypeScalar); | |
518 | } | |
519 | else if (e->ident == Id::isUnsigned) | |
520 | { | |
521 | return isTypeX(e, &isTypeUnsigned); | |
522 | } | |
523 | else if (e->ident == Id::isAssociativeArray) | |
524 | { | |
525 | return isTypeX(e, &isTypeAssociativeArray); | |
526 | } | |
527 | else if (e->ident == Id::isStaticArray) | |
528 | { | |
529 | return isTypeX(e, &isTypeStaticArray); | |
530 | } | |
531 | else if (e->ident == Id::isAbstractClass) | |
532 | { | |
533 | return isTypeX(e, &isTypeAbstractClass); | |
534 | } | |
535 | else if (e->ident == Id::isFinalClass) | |
536 | { | |
537 | return isTypeX(e, &isTypeFinalClass); | |
538 | } | |
539 | else if (e->ident == Id::isTemplate) | |
540 | { | |
541 | return isSymbolX(e, &isTemplate); | |
542 | } | |
543 | else if (e->ident == Id::isPOD) | |
544 | { | |
545 | if (dim != 1) | |
546 | return dimError(e, 1, dim); | |
547 | ||
548 | RootObject *o = (*e->args)[0]; | |
549 | Type *t = isType(o); | |
550 | if (!t) | |
551 | { | |
552 | e->error("type expected as second argument of __traits %s instead of %s", | |
553 | e->ident->toChars(), o->toChars()); | |
554 | return new ErrorExp(); | |
555 | } | |
556 | ||
557 | Type *tb = t->baseElemOf(); | |
558 | if (StructDeclaration *sd = (tb->ty == Tstruct) ? ((TypeStruct *)tb)->sym : NULL) | |
559 | { | |
560 | return (sd->isPOD()) ? True(e) : False(e); | |
561 | } | |
562 | return True(e); | |
563 | } | |
564 | else if (e->ident == Id::isNested) | |
565 | { | |
566 | if (dim != 1) | |
567 | return dimError(e, 1, dim); | |
568 | ||
569 | RootObject *o = (*e->args)[0]; | |
570 | Dsymbol *s = getDsymbol(o); | |
571 | if (!s) | |
572 | { | |
573 | } | |
574 | else if (AggregateDeclaration *a = s->isAggregateDeclaration()) | |
575 | { | |
576 | return a->isNested() ? True(e) : False(e); | |
577 | } | |
578 | else if (FuncDeclaration *f = s->isFuncDeclaration()) | |
579 | { | |
580 | return f->isNested() ? True(e) : False(e); | |
581 | } | |
582 | ||
583 | e->error("aggregate or function expected instead of '%s'", o->toChars()); | |
584 | return new ErrorExp(); | |
585 | } | |
586 | else if (e->ident == Id::isAbstractFunction) | |
587 | { | |
588 | return isFuncX(e, &isFuncAbstractFunction); | |
589 | } | |
590 | else if (e->ident == Id::isVirtualFunction) | |
591 | { | |
592 | return isFuncX(e, &isFuncVirtualFunction); | |
593 | } | |
594 | else if (e->ident == Id::isVirtualMethod) | |
595 | { | |
596 | return isFuncX(e, &isFuncVirtualMethod); | |
597 | } | |
598 | else if (e->ident == Id::isFinalFunction) | |
599 | { | |
600 | return isFuncX(e, &isFuncFinalFunction); | |
601 | } | |
602 | else if (e->ident == Id::isOverrideFunction) | |
603 | { | |
604 | return isFuncX(e, &isFuncOverrideFunction); | |
605 | } | |
606 | else if (e->ident == Id::isStaticFunction) | |
607 | { | |
608 | return isFuncX(e, &isFuncStaticFunction); | |
609 | } | |
610 | else if (e->ident == Id::isRef) | |
611 | { | |
612 | return isDeclX(e, &isDeclRef); | |
613 | } | |
614 | else if (e->ident == Id::isOut) | |
615 | { | |
616 | return isDeclX(e, &isDeclOut); | |
617 | } | |
618 | else if (e->ident == Id::isLazy) | |
619 | { | |
620 | return isDeclX(e, &isDeclLazy); | |
621 | } | |
622 | else if (e->ident == Id::identifier) | |
623 | { | |
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 | |
628 | */ | |
629 | if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 2)) | |
630 | return new ErrorExp(); | |
631 | if (dim != 1) | |
632 | return dimError(e, 1, dim); | |
633 | ||
634 | RootObject *o = (*e->args)[0]; | |
635 | Identifier *id = NULL; | |
636 | if (Parameter *po = isParameter(o)) | |
637 | { | |
638 | id = po->ident; | |
639 | assert(id); | |
640 | } | |
641 | else | |
642 | { | |
643 | Dsymbol *s = getDsymbol(o); | |
644 | if (!s || !s->ident) | |
645 | { | |
646 | e->error("argument %s has no identifier", o->toChars()); | |
647 | return new ErrorExp(); | |
648 | } | |
649 | id = s->ident; | |
650 | } | |
651 | ||
652 | StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); | |
653 | return semantic(se, sc); | |
654 | } | |
655 | else if (e->ident == Id::getProtection) | |
656 | { | |
657 | if (dim != 1) | |
658 | return dimError(e, 1, dim); | |
659 | ||
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(); | |
666 | ||
667 | RootObject *o = (*e->args)[0]; | |
668 | Dsymbol *s = getDsymbol(o); | |
669 | if (!s) | |
670 | { | |
671 | if (!isError(o)) | |
672 | e->error("argument %s has no protection", o->toChars()); | |
673 | return new ErrorExp(); | |
674 | } | |
675 | if (s->_scope) | |
676 | s->semantic(s->_scope); | |
677 | ||
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); | |
682 | } | |
683 | else if (e->ident == Id::parent) | |
684 | { | |
685 | if (dim != 1) | |
686 | return dimError(e, 1, dim); | |
687 | ||
688 | RootObject *o = (*e->args)[0]; | |
689 | Dsymbol *s = getDsymbol(o); | |
690 | if (s) | |
691 | { | |
692 | if (FuncDeclaration *fd = s->isFuncDeclaration()) // Bugzilla 8943 | |
693 | s = fd->toAliasFunc(); | |
694 | if (!s->isImport()) // Bugzilla 8922 | |
695 | s = s->toParent(); | |
696 | } | |
697 | if (!s || s->isImport()) | |
698 | { | |
699 | e->error("argument %s has no parent", o->toChars()); | |
700 | return new ErrorExp(); | |
701 | } | |
702 | ||
703 | if (FuncDeclaration *f = s->isFuncDeclaration()) | |
704 | { | |
705 | if (TemplateDeclaration *td = getFuncTemplateDecl(f)) | |
706 | { | |
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; | |
712 | } | |
713 | ||
714 | if (FuncLiteralDeclaration *fld = f->isFuncLiteralDeclaration()) | |
715 | { | |
716 | // Directly translate to VarExp instead of FuncExp | |
717 | Expression *ex = new VarExp(e->loc, fld, true); | |
718 | return semantic(ex, sc); | |
719 | } | |
720 | } | |
721 | ||
722 | return resolve(e->loc, sc, s, false); | |
723 | } | |
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) | |
729 | { | |
730 | if (dim != 2) | |
731 | return dimError(e, 2, dim); | |
732 | ||
733 | RootObject *o = (*e->args)[0]; | |
734 | Expression *ex = isExpression((*e->args)[1]); | |
735 | if (!ex) | |
736 | { | |
737 | e->error("expression expected as second argument of __traits %s", e->ident->toChars()); | |
738 | return new ErrorExp(); | |
739 | } | |
740 | ex = ex->ctfeInterpret(); | |
741 | ||
742 | StringExp *se = ex->toStringExp(); | |
743 | if (!se || se->len == 0) | |
744 | { | |
745 | e->error("string expected as second argument of __traits %s instead of %s", e->ident->toChars(), ex->toChars()); | |
746 | return new ErrorExp(); | |
747 | } | |
748 | se = se->toUTF8(sc); | |
749 | ||
750 | if (se->sz != 1) | |
751 | { | |
752 | e->error("string must be chars"); | |
753 | return new ErrorExp(); | |
754 | } | |
755 | Identifier *id = Identifier::idPool((char *)se->string, se->len); | |
756 | ||
757 | /* Prefer dsymbol, because it might need some runtime contexts. | |
758 | */ | |
759 | Dsymbol *sym = getDsymbol(o); | |
760 | if (sym) | |
761 | { | |
762 | ex = new DsymbolExp(e->loc, sym); | |
763 | ex = new DotIdExp(e->loc, ex, id); | |
764 | } | |
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 | |
770 | { | |
771 | e->error("invalid first argument"); | |
772 | return new ErrorExp(); | |
773 | } | |
774 | ||
775 | if (e->ident == Id::hasMember) | |
776 | { | |
777 | if (sym) | |
778 | { | |
779 | if (sym->search(e->loc, id)) | |
780 | return True(e); | |
781 | } | |
782 | ||
783 | /* Take any errors as meaning it wasn't found | |
784 | */ | |
785 | Scope *scx = sc->push(); | |
786 | scx->flags |= SCOPEignoresymbolvisibility; | |
787 | ex = trySemantic(ex, scx); | |
788 | scx->pop(); | |
789 | return ex ? True(e) : False(e); | |
790 | } | |
791 | else if (e->ident == Id::getMember) | |
792 | { | |
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; | |
801 | } | |
802 | else if (e->ident == Id::getVirtualFunctions || | |
803 | e->ident == Id::getVirtualMethods || | |
804 | e->ident == Id::getOverloads) | |
805 | { | |
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(); | |
814 | ||
815 | /* Create tuple of functions of ex | |
816 | */ | |
817 | Expressions *exps = new Expressions(); | |
818 | FuncDeclaration *f; | |
819 | if (ex->op == TOKvar) | |
820 | { | |
821 | VarExp *ve = (VarExp *)ex; | |
822 | f = ve->var->isFuncDeclaration(); | |
823 | ex = NULL; | |
824 | } | |
825 | else if (ex->op == TOKdotvar) | |
826 | { | |
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; | |
833 | } | |
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); | |
841 | ||
842 | ex = new TupleExp(e->loc, exps); | |
843 | ex = semantic(ex, scx); | |
844 | scx->pop(); | |
845 | return ex; | |
846 | } | |
847 | else | |
848 | assert(0); | |
849 | } | |
850 | else if (e->ident == Id::classInstanceSize) | |
851 | { | |
852 | if (dim != 1) | |
853 | return dimError(e, 1, dim); | |
854 | ||
855 | RootObject *o = (*e->args)[0]; | |
856 | Dsymbol *s = getDsymbol(o); | |
857 | ClassDeclaration *cd = s ? s->isClassDeclaration() : NULL; | |
858 | if (!cd) | |
859 | { | |
860 | e->error("first argument is not a class"); | |
861 | return new ErrorExp(); | |
862 | } | |
863 | if (cd->sizeok != SIZEOKdone) | |
864 | { | |
865 | cd->size(cd->loc); | |
866 | } | |
867 | if (cd->sizeok != SIZEOKdone) | |
868 | { | |
869 | e->error("%s %s is forward referenced", cd->kind(), cd->toChars()); | |
870 | return new ErrorExp(); | |
871 | } | |
872 | ||
873 | return new IntegerExp(e->loc, cd->structsize, Type::tsize_t); | |
874 | } | |
875 | else if (e->ident == Id::getAliasThis) | |
876 | { | |
877 | if (dim != 1) | |
878 | return dimError(e, 1, dim); | |
879 | ||
880 | RootObject *o = (*e->args)[0]; | |
881 | Dsymbol *s = getDsymbol(o); | |
882 | AggregateDeclaration *ad = s ? s->isAggregateDeclaration() : NULL; | |
883 | if (!ad) | |
884 | { | |
885 | e->error("argument is not an aggregate type"); | |
886 | return new ErrorExp(); | |
887 | } | |
888 | ||
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; | |
895 | } | |
896 | else if (e->ident == Id::getAttributes) | |
897 | { | |
898 | if (dim != 1) | |
899 | return dimError(e, 1, dim); | |
900 | ||
901 | RootObject *o = (*e->args)[0]; | |
902 | Dsymbol *s = getDsymbol(o); | |
903 | if (!s) | |
904 | { | |
905 | e->error("first argument is not a symbol"); | |
906 | return new ErrorExp(); | |
907 | } | |
908 | if (Import *imp = s->isImport()) | |
909 | { | |
910 | s = imp->mod; | |
911 | } | |
912 | ||
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); | |
918 | } | |
919 | else if (e->ident == Id::getFunctionAttributes) | |
920 | { | |
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); | |
924 | ||
925 | RootObject *o = (*e->args)[0]; | |
926 | Dsymbol *s = getDsymbol(o); | |
927 | Type *t = isType(o); | |
928 | TypeFunction *tf = NULL; | |
929 | if (s) | |
930 | { | |
931 | if (FuncDeclaration *f = s->isFuncDeclaration()) | |
932 | t = f->type; | |
933 | else if (VarDeclaration *v = s->isVarDeclaration()) | |
934 | t = v->type; | |
935 | } | |
936 | if (t) | |
937 | { | |
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(); | |
944 | } | |
945 | if (!tf) | |
946 | { | |
947 | e->error("first argument is not a function"); | |
948 | return new ErrorExp(); | |
949 | } | |
950 | ||
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); | |
956 | ||
957 | TupleExp *tup = new TupleExp(e->loc, mods); | |
958 | return semantic(tup, sc); | |
959 | } | |
960 | else if (e->ident == Id::getFunctionVariadicStyle) | |
961 | { | |
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[] ...) | |
967 | */ | |
968 | // get symbol linkage as a string | |
969 | if (dim != 1) | |
970 | return dimError(e, 1, dim); | |
971 | ||
972 | LINK link; | |
973 | int varargs; | |
974 | RootObject *o = (*e->args)[0]; | |
975 | Type *t = isType(o); | |
976 | TypeFunction *tf = NULL; | |
977 | if (t) | |
978 | { | |
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(); | |
985 | } | |
986 | if (tf) | |
987 | { | |
988 | link = tf->linkage; | |
989 | varargs = tf->varargs; | |
990 | } | |
991 | else | |
992 | { | |
993 | Dsymbol *s = getDsymbol(o); | |
994 | FuncDeclaration *fd = NULL; | |
995 | if (!s || (fd = s->isFuncDeclaration()) == NULL) | |
996 | { | |
997 | e->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o->toChars()); | |
998 | return new ErrorExp(); | |
999 | } | |
1000 | link = fd->linkage; | |
1001 | fd->getParameters(&varargs); | |
1002 | } | |
1003 | const char *style; | |
1004 | switch (varargs) | |
1005 | { | |
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); | |
1012 | } | |
1013 | StringExp *se = new StringExp(e->loc, const_cast<char*>(style)); | |
1014 | return semantic(se, sc); | |
1015 | } | |
1016 | else if (e->ident == Id::getParameterStorageClasses) | |
1017 | { | |
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. | |
1020 | */ | |
1021 | // get symbol linkage as a string | |
1022 | if (dim != 2) | |
1023 | return dimError(e, 2, dim); | |
1024 | ||
1025 | RootObject *o1 = (*e->args)[1]; | |
1026 | RootObject *o = (*e->args)[0]; | |
1027 | Type *t = isType(o); | |
1028 | TypeFunction *tf = NULL; | |
1029 | if (t) | |
1030 | { | |
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(); | |
1037 | } | |
1038 | Parameters* fparams; | |
1039 | if (tf) | |
1040 | { | |
1041 | fparams = tf->parameters; | |
1042 | } | |
1043 | else | |
1044 | { | |
1045 | Dsymbol *s = getDsymbol(o); | |
1046 | FuncDeclaration *fd = NULL; | |
1047 | if (!s || (fd = s->isFuncDeclaration()) == NULL) | |
1048 | { | |
1049 | e->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function", | |
1050 | o->toChars(), o1->toChars()); | |
1051 | return new ErrorExp(); | |
1052 | } | |
1053 | fparams = fd->getParameters(NULL); | |
1054 | } | |
1055 | ||
1056 | StorageClass stc; | |
1057 | ||
1058 | // Set stc to storage class of the ith parameter | |
1059 | Expression *ex = isExpression((*e->args)[1]); | |
1060 | if (!ex) | |
1061 | { | |
1062 | e->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`", | |
1063 | o->toChars(), o1->toChars()); | |
1064 | return new ErrorExp(); | |
1065 | } | |
1066 | ex = ex->ctfeInterpret(); | |
1067 | uinteger_t ii = ex->toUInteger(); | |
1068 | if (ii >= Parameter::dim(fparams)) | |
1069 | { | |
1070 | e->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams), ex->toChars()); | |
1071 | return new ErrorExp(); | |
1072 | } | |
1073 | ||
1074 | unsigned n = (unsigned)ii; | |
1075 | Parameter *p = Parameter::getNth(fparams, n); | |
1076 | stc = p->storageClass; | |
1077 | ||
1078 | // This mirrors hdrgen.visit(Parameter p) | |
1079 | if (p->type && p->type->mod & MODshared) | |
1080 | stc &= ~STCshared; | |
1081 | ||
1082 | Expressions *exps = new Expressions; | |
1083 | ||
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"))); | |
1088 | ||
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"))); | |
1099 | ||
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"))); | |
1110 | ||
1111 | TupleExp *tup = new TupleExp(e->loc, exps); | |
1112 | return semantic(tup, sc); | |
1113 | } | |
1114 | else if (e->ident == Id::getLinkage) | |
1115 | { | |
1116 | // get symbol linkage as a string | |
1117 | if (dim != 1) | |
1118 | return dimError(e, 1, dim); | |
1119 | ||
1120 | LINK link; | |
1121 | RootObject *o = (*e->args)[0]; | |
1122 | Type *t = isType(o); | |
1123 | TypeFunction *tf = NULL; | |
1124 | if (t) | |
1125 | { | |
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(); | |
1132 | } | |
1133 | if (tf) | |
1134 | link = tf->linkage; | |
1135 | else | |
1136 | { | |
1137 | Dsymbol *s = getDsymbol(o); | |
1138 | Declaration *d = NULL; | |
1139 | if (!s || (d = s->isDeclaration()) == NULL) | |
1140 | { | |
1141 | e->error("argument to `__traits(getLinkage, %s)` is not a declaration", o->toChars()); | |
1142 | return new ErrorExp(); | |
1143 | } | |
1144 | link = d->linkage; | |
1145 | } | |
1146 | const char *linkage = linkageToChars(link); | |
1147 | StringExp *se = new StringExp(e->loc, const_cast<char *>(linkage)); | |
1148 | return semantic(se, sc); | |
1149 | } | |
1150 | else if (e->ident == Id::allMembers || | |
1151 | e->ident == Id::derivedMembers) | |
1152 | { | |
1153 | if (dim != 1) | |
1154 | return dimError(e, 1, dim); | |
1155 | ||
1156 | RootObject *o = (*e->args)[0]; | |
1157 | Dsymbol *s = getDsymbol(o); | |
1158 | if (!s) | |
1159 | { | |
1160 | e->error("argument has no members"); | |
1161 | return new ErrorExp(); | |
1162 | } | |
1163 | if (Import *imp = s->isImport()) | |
1164 | { | |
1165 | // Bugzilla 9692 | |
1166 | s = imp->mod; | |
1167 | } | |
1168 | ||
1169 | ScopeDsymbol *sds = s->isScopeDsymbol(); | |
1170 | if (!sds || sds->isTemplateDeclaration()) | |
1171 | { | |
1172 | e->error("%s %s has no members", s->kind(), s->toChars()); | |
1173 | return new ErrorExp(); | |
1174 | } | |
1175 | ||
1176 | // use a struct as local function | |
1177 | struct PushIdentsDg | |
1178 | { | |
1179 | ScopeDsymbol *sds; | |
1180 | Identifiers *idents; | |
1181 | ||
1182 | static int dg(void *ctx, size_t, Dsymbol *sm) | |
1183 | { | |
1184 | if (!sm) | |
1185 | return 1; | |
1186 | //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); | |
1187 | if (sm->ident) | |
1188 | { | |
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) | |
1196 | { | |
1197 | return 0; | |
1198 | } | |
1199 | ||
1200 | if (sm->ident == Id::empty) | |
1201 | { | |
1202 | return 0; | |
1203 | } | |
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; | |
1209 | ||
1210 | //printf("\t%s\n", sm->ident->toChars()); | |
1211 | Identifiers *idents = pid->idents; | |
1212 | ||
1213 | /* Skip if already present in idents[] | |
1214 | */ | |
1215 | for (size_t j = 0; j < idents->dim; j++) | |
1216 | { | |
1217 | Identifier *id = (*idents)[j]; | |
1218 | if (id == sm->ident) | |
1219 | return 0; | |
1220 | } | |
1221 | ||
1222 | idents->push(sm->ident); | |
1223 | } | |
1224 | else | |
1225 | { | |
1226 | EnumDeclaration *ed = sm->isEnumDeclaration(); | |
1227 | if (ed) | |
1228 | { | |
1229 | ScopeDsymbol_foreach(NULL, ed->members, &PushIdentsDg::dg, ctx); | |
1230 | } | |
1231 | } | |
1232 | return 0; | |
1233 | } | |
1234 | }; | |
1235 | ||
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) | |
1243 | { | |
1244 | if (cd->_scope) | |
1245 | cd->semantic(NULL); // Bugzilla 13668: Try to resolve forward reference | |
1246 | ||
1247 | struct PushBaseMembers | |
1248 | { | |
1249 | static void dg(ClassDeclaration *cd, PushIdentsDg *ctx) | |
1250 | { | |
1251 | for (size_t i = 0; i < cd->baseclasses->dim; i++) | |
1252 | { | |
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); | |
1258 | } | |
1259 | } | |
1260 | }; | |
1261 | PushBaseMembers::dg(cd, &ctx); | |
1262 | } | |
1263 | ||
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++) | |
1268 | { | |
1269 | Identifier *id = (*idents)[i]; | |
1270 | StringExp *se = new StringExp(e->loc, const_cast<char *>(id->toChars())); | |
1271 | (*exps)[i] = se; | |
1272 | } | |
1273 | ||
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, ...) ] | |
1277 | */ | |
1278 | Expression *ex = new TupleExp(e->loc, exps); | |
1279 | ex = semantic(ex, sc); | |
1280 | return ex; | |
1281 | } | |
1282 | else if (e->ident == Id::compiles) | |
1283 | { | |
1284 | /* Determine if all the objects - types, expressions, or symbols - | |
1285 | * compile without error | |
1286 | */ | |
1287 | if (!dim) | |
1288 | return False(e); | |
1289 | ||
1290 | for (size_t i = 0; i < dim; i++) | |
1291 | { | |
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; | |
1298 | ||
1299 | RootObject *o = (*e->args)[i]; | |
1300 | Type *t = isType(o); | |
1301 | Expression *ex = t ? typeToExpression(t) : isExpression(o); | |
1302 | if (!ex && t) | |
1303 | { | |
1304 | Dsymbol *s; | |
1305 | t->resolve(e->loc, sc2, &ex, &t, &s); | |
1306 | if (t) | |
1307 | { | |
1308 | t->semantic(e->loc, sc2); | |
1309 | if (t->ty == Terror) | |
1310 | err = true; | |
1311 | } | |
1312 | else if (s && s->errors) | |
1313 | err = true; | |
1314 | } | |
1315 | if (ex) | |
1316 | { | |
1317 | ex = semantic(ex, sc2); | |
1318 | ex = resolvePropertiesOnly(sc2, ex); | |
1319 | ex = ex->optimize(WANTvalue); | |
1320 | if (sc2->func && sc2->func->type->ty == Tfunction) | |
1321 | { | |
1322 | TypeFunction *tf = (TypeFunction *)sc2->func->type; | |
1323 | canThrow(ex, sc2->func, tf->isnothrow); | |
1324 | } | |
1325 | ex = checkGC(sc2, ex); | |
1326 | if (ex->op == TOKerror) | |
1327 | err = true; | |
1328 | } | |
1329 | ||
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(); | |
1336 | ||
1337 | if (global.endGagging(errors) || err) | |
1338 | { | |
1339 | return False(e); | |
1340 | } | |
1341 | } | |
1342 | return True(e); | |
1343 | } | |
1344 | else if (e->ident == Id::isSame) | |
1345 | { | |
1346 | /* Determine if two symbols are the same | |
1347 | */ | |
1348 | if (dim != 2) | |
1349 | return dimError(e, 2, dim); | |
1350 | ||
1351 | if (!TemplateInstance::semanticTiargs(e->loc, sc, e->args, 0)) | |
1352 | return new ErrorExp(); | |
1353 | ||
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) | |
1360 | { | |
1361 | Expression *ea1 = isExpression(o1); | |
1362 | Expression *ea2 = isExpression(o2); | |
1363 | if (ea1 && ea2) | |
1364 | { | |
1365 | if (ea1->equals(ea2)) | |
1366 | return True(e); | |
1367 | } | |
1368 | } | |
1369 | if (!s1 || !s2) | |
1370 | return False(e); | |
1371 | s1 = s1->toAlias(); | |
1372 | s2 = s2->toAlias(); | |
1373 | ||
1374 | if (s1->isFuncAliasDeclaration()) | |
1375 | s1 = ((FuncAliasDeclaration *)s1)->toAliasFunc(); | |
1376 | if (s2->isFuncAliasDeclaration()) | |
1377 | s2 = ((FuncAliasDeclaration *)s2)->toAliasFunc(); | |
1378 | ||
1379 | return (s1 == s2) ? True(e) : False(e); | |
1380 | } | |
1381 | else if (e->ident == Id::getUnitTests) | |
1382 | { | |
1383 | if (dim != 1) | |
1384 | return dimError(e, 1, dim); | |
1385 | ||
1386 | RootObject *o = (*e->args)[0]; | |
1387 | Dsymbol *s = getDsymbol(o); | |
1388 | if (!s) | |
1389 | { | |
1390 | e->error("argument %s to __traits(getUnitTests) must be a module or aggregate", | |
1391 | o->toChars()); | |
1392 | return new ErrorExp(); | |
1393 | } | |
1394 | if (Import *imp = s->isImport()) // Bugzilla 10990 | |
1395 | s = imp->mod; | |
1396 | ||
1397 | ScopeDsymbol* sds = s->isScopeDsymbol(); | |
1398 | if (!sds) | |
1399 | { | |
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(); | |
1403 | } | |
1404 | ||
1405 | Expressions *exps = new Expressions(); | |
1406 | if (global.params.useUnitTests) | |
1407 | { | |
1408 | // Should actually be a set | |
1409 | AA* uniqueUnitTests = NULL; | |
1410 | collectUnitTests(sds->members, uniqueUnitTests, exps); | |
1411 | } | |
1412 | TupleExp *te= new TupleExp(e->loc, exps); | |
1413 | return semantic(te, sc); | |
1414 | } | |
1415 | else if(e->ident == Id::getVirtualIndex) | |
1416 | { | |
1417 | if (dim != 1) | |
1418 | return dimError(e, 1, dim); | |
1419 | ||
1420 | RootObject *o = (*e->args)[0]; | |
1421 | Dsymbol *s = getDsymbol(o); | |
1422 | ||
1423 | FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; | |
1424 | if (!fd) | |
1425 | { | |
1426 | e->error("first argument to __traits(getVirtualIndex) must be a function"); | |
1427 | return new ErrorExp(); | |
1428 | } | |
1429 | ||
1430 | fd = fd->toAliasFunc(); // Neccessary to support multiple overloads. | |
1431 | return new IntegerExp(e->loc, fd->vtblIndex, Type::tptrdiff_t); | |
1432 | } | |
1433 | else if (e->ident == Id::getPointerBitmap) | |
1434 | { | |
1435 | return pointerBitmap(e); | |
1436 | } | |
1437 | ||
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(); | |
1443 | ||
1444 | e->error("wrong number of arguments %d", (int)dim); | |
1445 | return new ErrorExp(); | |
1446 | } |