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
11 #include "root/dsystem.h"
12 #include "root/rmem.h"
14 #include "root/checkedint.h"
19 #include "expression.h"
25 #include "statement.h"
26 #include "declaration.h"
27 #include "aggregate.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.
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();
63 Ptrait
*p
= (Ptrait
*)param
;
64 if (p
->ident
== Id::getVirtualFunctions
&& !f
->isVirtual())
67 if (p
->ident
== Id::getVirtualMethods
&& !f
->isVirtualMethod())
71 FuncAliasDeclaration
* ad
= new FuncAliasDeclaration(f
->ident
, f
, false);
72 ad
->protection
= f
->protection
;
74 e
= new DotVarExp(Loc(), p
->e1
, ad
, false);
76 e
= new DsymbolExp(Loc(), ad
, false);
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).
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
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
)
100 for (size_t i
= 0; i
< symbols
->dim
; i
++)
102 Dsymbol
*symbol
= (*symbols
)[i
];
103 UnitTestDeclaration
*unitTest
= symbol
->isUnitTestDeclaration();
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);
112 bool* value
= (bool*) dmd_aaGet(&uniqueUnitTests
, (void *)unitTest
);
118 AttribDeclaration
*attrDecl
= symbol
->isAttribDeclaration();
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
)
148 for (size_t i
= 0; i
< e
->args
->dim
; i
++)
150 Type
*t
= getType((*e
->args
)[i
]);
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
)
168 for (size_t i
= 0; i
< e
->args
->dim
; i
++)
170 Dsymbol
*s
= getDsymbol((*e
->args
)[i
]);
173 FuncDeclaration
*f
= s
->isFuncDeclaration();
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
)
188 for (size_t i
= 0; i
< e
->args
->dim
; i
++)
190 Dsymbol
*s
= getDsymbol((*e
->args
)[i
]);
193 Declaration
*d
= s
->isDeclaration();
200 // callback for TypeFunction::attributesApply
201 struct PushAttributes
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
)));
213 StringTable traitsStringTable
;
215 struct TraitsInitializer
220 static TraitsInitializer traitsinitializer
;
222 TraitsInitializer::TraitsInitializer()
224 const char* traits
[] = {
227 "isAssociativeArray",
238 "isAbstractFunction",
240 "isOverrideFunction",
252 "getVirtualFunctions",
262 "getFunctionAttributes",
263 "getFunctionVariadicStyle",
264 "getParameterStorageClasses",
271 traitsStringTable
._init(40);
273 for (size_t idx
= 0;; idx
++)
275 const char *s
= traits
[idx
];
277 StringValue
*sv
= traitsStringTable
.insert(s
, strlen(s
), const_cast<char *>(s
));
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
);
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())
302 bool isTemplate(Dsymbol
*s
)
304 if (!s
->toAlias()->isOverloadable())
307 return overloadApply(s
, NULL
, &fpisTemplate
) != 0;
310 Expression
*isSymbolX(TraitsExp
*e
, bool (*fp
)(Dsymbol
*s
))
312 if (!e
->args
|| !e
->args
->dim
)
314 for (size_t i
= 0; i
< e
->args
->dim
; i
++)
316 Dsymbol
*s
= getDsymbol((*e
->args
)[i
]);
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
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]);
343 error(e
->loc
, "%s is not a type", (*e
->args
)[0]->toChars());
344 return new ErrorExp();
347 if (t
->ty
== Tclass
&& !((TypeClass
*)t
)->sym
->isInterfaceDeclaration())
348 sz
= ((TypeClass
*)t
)->sym
->AggregateDeclaration::size(e
->loc
);
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
;
365 data
.setDim((size_t)cntdata
);
368 class PointerBitmapVisitor
: public Visitor
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();
386 virtual void visit(TypeError
*t
) { visit((Type
*)t
); }
387 virtual void visit(TypeNext
*) { assert(0); }
388 virtual void visit(TypeBasic
*t
)
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
)
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);
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
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
)
440 v
->type
->accept(this);
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);
463 Array
<d_uns64
>* data
;
469 PointerBitmapVisitor
pbv(&data
, sz_size_t
);
471 pbv
.visitClass((TypeClass
*)t
);
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);
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
)
546 return dimError(e
, 1, dim
);
548 RootObject
*o
= (*e
->args
)[0];
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
);
564 else if (e
->ident
== Id::isNested
)
567 return dimError(e
, 1, dim
);
569 RootObject
*o
= (*e
->args
)[0];
570 Dsymbol
*s
= getDsymbol(o
);
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();
632 return dimError(e
, 1, dim
);
634 RootObject
*o
= (*e
->args
)[0];
635 Identifier
*id
= NULL
;
636 if (Parameter
*po
= isParameter(o
))
643 Dsymbol
*s
= getDsymbol(o
);
646 e
->error("argument %s has no identifier", o
->toChars());
647 return new ErrorExp();
652 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(id
->toChars()));
653 return semantic(se
, sc
);
655 else if (e
->ident
== Id::getProtection
)
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);
665 return new ErrorExp();
667 RootObject
*o
= (*e
->args
)[0];
668 Dsymbol
*s
= getDsymbol(o
);
672 e
->error("argument %s has no protection", o
->toChars());
673 return new ErrorExp();
676 s
->semantic(s
->_scope
);
678 const char *protName
= protectionToChars(s
->prot().kind
); // TODO: How about package(names)
680 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(protName
));
681 return semantic(se
, sc
);
683 else if (e
->ident
== Id::parent
)
686 return dimError(e
, 1, dim
);
688 RootObject
*o
= (*e
->args
)[0];
689 Dsymbol
*s
= getDsymbol(o
);
692 if (FuncDeclaration
*fd
= s
->isFuncDeclaration()) // Bugzilla 8943
693 s
= fd
->toAliasFunc();
694 if (!s
->isImport()) // Bugzilla 8922
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
);
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
)
731 return dimError(e
, 2, dim
);
733 RootObject
*o
= (*e
->args
)[0];
734 Expression
*ex
= isExpression((*e
->args
)[1]);
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();
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
);
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
);
771 e
->error("invalid first argument");
772 return new ErrorExp();
775 if (e
->ident
== Id::hasMember
)
779 if (sym
->search(e
->loc
, id
))
783 /* Take any errors as meaning it wasn't found
785 Scope
*scx
= sc
->push();
786 scx
->flags
|= SCOPEignoresymbolvisibility
;
787 ex
= trySemantic(ex
, scx
);
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
);
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());
815 /* Create tuple of functions of ex
817 Expressions
*exps
= new Expressions();
819 if (ex
->op
== TOKvar
)
821 VarExp
*ve
= (VarExp
*)ex
;
822 f
= ve
->var
->isFuncDeclaration();
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
)
840 overloadApply(f
, &p
, &fptraits
);
842 ex
= new TupleExp(e
->loc
, exps
);
843 ex
= semantic(ex
, scx
);
850 else if (e
->ident
== Id::classInstanceSize
)
853 return dimError(e
, 1, dim
);
855 RootObject
*o
= (*e
->args
)[0];
856 Dsymbol
*s
= getDsymbol(o
);
857 ClassDeclaration
*cd
= s
? s
->isClassDeclaration() : NULL
;
860 e
->error("first argument is not a class");
861 return new ErrorExp();
863 if (cd
->sizeok
!= SIZEOKdone
)
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
)
878 return dimError(e
, 1, dim
);
880 RootObject
*o
= (*e
->args
)[0];
881 Dsymbol
*s
= getDsymbol(o
);
882 AggregateDeclaration
*ad
= s
? s
->isAggregateDeclaration() : NULL
;
885 e
->error("argument is not an aggregate type");
886 return new ErrorExp();
889 Expressions
*exps
= new Expressions();
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
);
896 else if (e
->ident
== Id::getAttributes
)
899 return dimError(e
, 1, dim
);
901 RootObject
*o
= (*e
->args
)[0];
902 Dsymbol
*s
= getDsymbol(o
);
905 e
->error("first argument is not a symbol");
906 return new ErrorExp();
908 if (Import
*imp
= s
->isImport())
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.
923 return dimError(e
, 1, dim
);
925 RootObject
*o
= (*e
->args
)[0];
926 Dsymbol
*s
= getDsymbol(o
);
928 TypeFunction
*tf
= NULL
;
931 if (FuncDeclaration
*f
= s
->isFuncDeclaration())
933 else if (VarDeclaration
*v
= s
->isVarDeclaration())
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();
947 e
->error("first argument is not a function");
948 return new ErrorExp();
951 Expressions
*mods
= new Expressions();
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
970 return dimError(e
, 1, dim
);
974 RootObject
*o
= (*e
->args
)[0];
976 TypeFunction
*tf
= NULL
;
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();
989 varargs
= tf
->varargs
;
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();
1001 fd
->getParameters(&varargs
);
1006 case 0: style
= "none"; break;
1007 case 1: style
= (link
== LINKd
) ? "argptr"
1009 case 2: style
= "typesafe"; break;
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
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
;
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
;
1041 fparams
= tf
->parameters
;
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
);
1058 // Set stc to storage class of the ith parameter
1059 Expression
*ex
= isExpression((*e
->args
)[1]);
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
)
1082 Expressions
*exps
= new Expressions
;
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")));
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")));
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")));
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
1118 return dimError(e
, 1, dim
);
1121 RootObject
*o
= (*e
->args
)[0];
1122 Type
*t
= isType(o
);
1123 TypeFunction
*tf
= NULL
;
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();
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();
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
)
1154 return dimError(e
, 1, dim
);
1156 RootObject
*o
= (*e
->args
)[0];
1157 Dsymbol
*s
= getDsymbol(o
);
1160 e
->error("argument has no members");
1161 return new ErrorExp();
1163 if (Import
*imp
= s
->isImport())
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
1180 Identifiers
*idents
;
1182 static int dg(void *ctx
, size_t, Dsymbol
*sm
)
1186 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
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
)
1200 if (sm
->ident
== Id::empty
)
1204 if (sm
->isTypeInfoDeclaration()) // Bugzilla 15177
1206 PushIdentsDg
*pid
= (PushIdentsDg
*)ctx
;
1207 if (!pid
->sds
->isModule() && sm
->isImport()) // Bugzilla 17057
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
)
1222 idents
->push(sm
->ident
);
1226 EnumDeclaration
*ed
= sm
->isEnumDeclaration();
1229 ScopeDsymbol_foreach(NULL
, ed
->members
, &PushIdentsDg::dg
, ctx
);
1236 Identifiers
*idents
= new Identifiers
;
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
)
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
;
1255 ScopeDsymbol_foreach(NULL
, cb
->members
, &PushIdentsDg::dg
, ctx
);
1256 if (cb
->baseclasses
->dim
)
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()));
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
);
1282 else if (e
->ident
== Id::compiles
)
1284 /* Determine if all the objects - types, expressions, or symbols -
1285 * compile without error
1290 for (size_t i
= 0; i
< dim
; i
++)
1292 unsigned errors
= global
.startGagging();
1293 Scope
*sc2
= sc
->push();
1296 sc2
->flags
= (sc
->flags
& ~(SCOPEctfe
| SCOPEcondition
)) | SCOPEcompile
| SCOPEfullinst
;
1299 RootObject
*o
= (*e
->args
)[i
];
1300 Type
*t
= isType(o
);
1301 Expression
*ex
= t
? typeToExpression(t
) : isExpression(o
);
1305 t
->resolve(e
->loc
, sc2
, &ex
, &t
, &s
);
1308 t
->semantic(e
->loc
, sc2
);
1309 if (t
->ty
== Terror
)
1312 else if (s
&& s
->errors
)
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
)
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
1334 sc2
->enclosing
= NULL
;
1337 if (global
.endGagging(errors
) || err
)
1344 else if (e
->ident
== Id::isSame
)
1346 /* Determine if two symbols are the same
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());
1361 Expression
*ea1
= isExpression(o1
);
1362 Expression
*ea2
= isExpression(o2
);
1365 if (ea1
->equals(ea2
))
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
)
1384 return dimError(e
, 1, dim
);
1386 RootObject
*o
= (*e
->args
)[0];
1387 Dsymbol
*s
= getDsymbol(o
);
1390 e
->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1392 return new ErrorExp();
1394 if (Import
*imp
= s
->isImport()) // Bugzilla 10990
1397 ScopeDsymbol
* sds
= s
->isScopeDsymbol();
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
)
1418 return dimError(e
, 1, dim
);
1420 RootObject
*o
= (*e
->args
)[0];
1421 Dsymbol
*s
= getDsymbol(o
);
1423 FuncDeclaration
*fd
= s
? s
->isFuncDeclaration() : NULL
;
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
);
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();