2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/traits.c
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"
37 typedef int (*ForeachDg
)(void *ctx
, size_t idx
, Dsymbol
*s
);
38 int ScopeDsymbol_foreach(Scope
*sc
, Dsymbols
*members
, ForeachDg dg
, void *ctx
, size_t *pn
= NULL
);
39 void freeFieldinit(Scope
*sc
);
40 Expression
*resolve(Loc loc
, Scope
*sc
, Dsymbol
*s
, bool hasOverloads
);
41 Package
*resolveIsPackage(Dsymbol
*sym
);
42 Expression
*trySemantic(Expression
*e
, Scope
*sc
);
43 Expression
*semantic(Expression
*e
, Scope
*sc
);
44 Expression
*typeToExpression(Type
*t
);
47 /************************************************
48 * Delegate to be passed to overloadApply() that looks
49 * for functions matching a trait.
56 Expressions
*exps
; // collected results
57 Identifier
*ident
; // which trait we're looking for
58 bool includeTemplates
;
62 /* Compute the function signature and insert it in the
63 * hashtable, if not present. This is needed so that
64 * traits(getOverlods, F3, "visit") does not count `int visit(int)`
65 * twice in the following example:
67 * =============================================
68 * interface F1 { int visit(int);}
69 * interface F2 { int visit(int); void visit(); }
70 * interface F3 : F2, F1 {}
71 *==============================================
73 static void insertInterfaceInheritedFunction(Ptrait
*p
, FuncDeclaration
*fd
, Expression
*e
)
75 Identifier
*signature
= Identifier::idPool(fd
->type
->toChars());
76 //printf("%s - %s\n", fd->toChars, signature);
77 if (!dmd_aaGetRvalue(*p
->funcTypeHash
, (void *)signature
))
79 bool* value
= (bool*) dmd_aaGet(p
->funcTypeHash
, (void *)signature
);
85 static int fptraits(void *param
, Dsymbol
*s
)
87 Ptrait
*p
= (Ptrait
*)param
;
88 if (p
->includeTemplates
)
90 p
->exps
->push(new DsymbolExp(Loc(),s
, false));
93 FuncDeclaration
*fd
= s
->isFuncDeclaration();
97 if (p
->ident
== Id::getVirtualFunctions
&& !fd
->isVirtual())
100 if (p
->ident
== Id::getVirtualMethods
&& !fd
->isVirtualMethod())
104 FuncAliasDeclaration
* ad
= new FuncAliasDeclaration(fd
->ident
, fd
, false);
105 ad
->protection
= fd
->protection
;
107 e
= new DotVarExp(Loc(), p
->e1
, ad
, false);
109 e
= new DsymbolExp(Loc(), ad
, false);
110 // if the parent is an interface declaration
111 // we must check for functions with the same signature
112 // in different inherited interfaces
113 if (p
->sym
&& p
->sym
->isInterfaceDeclaration())
114 insertInterfaceInheritedFunction(p
, fd
, e
);
121 * Collects all unit test functions from the given array of symbols.
123 * This is a helper function used by the implementation of __traits(getUnitTests).
126 * symbols array of symbols to collect the functions from
127 * uniqueUnitTests an associative array (should actually be a set) to
128 * keep track of already collected functions. We're
129 * using an AA here to avoid doing a linear search of unitTests
132 * unitTests array of DsymbolExp's of the collected unit test functions
133 * uniqueUnitTests updated with symbols from unitTests[ ]
135 static void collectUnitTests(Dsymbols
*symbols
, AA
*uniqueUnitTests
, Expressions
*unitTests
)
139 for (size_t i
= 0; i
< symbols
->length
; i
++)
141 Dsymbol
*symbol
= (*symbols
)[i
];
142 UnitTestDeclaration
*unitTest
= symbol
->isUnitTestDeclaration();
145 if (!dmd_aaGetRvalue(uniqueUnitTests
, (void *)unitTest
))
147 FuncAliasDeclaration
* ad
= new FuncAliasDeclaration(unitTest
->ident
, unitTest
, false);
148 ad
->protection
= unitTest
->protection
;
149 Expression
* e
= new DsymbolExp(Loc(), ad
, false);
151 bool* value
= (bool*) dmd_aaGet(&uniqueUnitTests
, (void *)unitTest
);
157 AttribDeclaration
*attrDecl
= symbol
->isAttribDeclaration();
161 Dsymbols
*decl
= attrDecl
->include(NULL
);
162 collectUnitTests(decl
, uniqueUnitTests
, unitTests
);
168 /***************************************************
169 * Determine if type t is copyable.
173 * true if we can copy it
175 static bool isCopyable(Type
*t
)
177 //printf("isCopyable() %s\n", t->toChars());
178 if (TypeStruct
*ts
= t
->isTypeStruct())
180 if (ts
->sym
->postblit
&&
181 (ts
->sym
->postblit
->storage_class
& STCdisable
))
187 /************************ TraitsExp ************************************/
189 static Expression
*True(TraitsExp
*e
) { return new IntegerExp(e
->loc
, true, Type::tbool
); }
190 static Expression
*False(TraitsExp
*e
) { return new IntegerExp(e
->loc
, false, Type::tbool
); }
192 /**************************************
193 * Convert `Expression` or `Type` to corresponding `Dsymbol`,
194 * additionally strip off expression contexts.
196 * Some symbol related `__traits` ignore arguments expression contexts.
198 * struct S { void f() {} }
200 * pragma(msg, __traits(isNested, s.f));
201 * // s.f is DotVarExp, but __traits(isNested) needs a FuncDeclaration.
203 * This is used for that common `__traits` behavior.
205 static Dsymbol
*getDsymbolWithoutExpCtx(RootObject
*oarg
)
207 if (Expression
*e
= isExpression(oarg
))
209 if (e
->op
== TOKdotvar
)
210 return ((DotVarExp
*)e
)->var
;
211 if (e
->op
== TOKdottd
)
212 return ((DotTemplateExp
*)e
)->td
;
214 return getDsymbol(oarg
);
218 Gets the function type from a given AST node
219 if the node is a function of some sort.
222 o = an AST node to check for a `TypeFunction`
223 fdp = optional pointer to a function declararion, to be set
224 if `o` is a function declarartion.
227 a type node if `o` is a declaration of
228 a delegate, function, function-pointer
229 or a variable of the former. Otherwise, `null`.
231 static TypeFunction
*toTypeFunction(RootObject
*o
, FuncDeclaration
**fdp
= NULL
)
233 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
235 TypeFunction
*tf
= NULL
;
239 FuncDeclaration
*fd
= s
->isFuncDeclaration();
246 else if (VarDeclaration
*vd
= s
->isVarDeclaration())
251 if (t
->ty
== Tfunction
)
252 tf
= (TypeFunction
*)t
;
253 else if (t
->ty
== Tdelegate
)
254 tf
= (TypeFunction
*)t
->nextOf();
255 else if (t
->ty
== Tpointer
&& t
->nextOf()->ty
== Tfunction
)
256 tf
= (TypeFunction
*)t
->nextOf();
262 static bool isTypeArithmetic(Type
*t
) { return t
->isintegral() || t
->isfloating(); }
263 static bool isTypeFloating(Type
*t
) { return t
->isfloating(); }
264 static bool isTypeIntegral(Type
*t
) { return t
->isintegral(); }
265 static bool isTypeScalar(Type
*t
) { return t
->isscalar(); }
266 static bool isTypeUnsigned(Type
*t
) { return t
->isunsigned(); }
267 static bool isTypeAssociativeArray(Type
*t
) { return t
->toBasetype()->ty
== Taarray
; }
268 static bool isTypeStaticArray(Type
*t
) { return t
->toBasetype()->ty
== Tsarray
; }
269 static bool isTypeAbstractClass(Type
*t
) { return t
->toBasetype()->ty
== Tclass
&& ((TypeClass
*)t
->toBasetype())->sym
->isAbstract(); }
270 static bool isTypeFinalClass(Type
*t
) { return t
->toBasetype()->ty
== Tclass
&& (((TypeClass
*)t
->toBasetype())->sym
->storage_class
& STCfinal
) != 0; }
272 static Expression
*isTypeX(TraitsExp
*e
, bool (*fp
)(Type
*t
))
274 if (!e
->args
|| !e
->args
->length
)
276 for (size_t i
= 0; i
< e
->args
->length
; i
++)
278 Type
*t
= getType((*e
->args
)[i
]);
285 static bool isDsymDeprecated(Dsymbol
*s
) { return s
->isDeprecated(); }
287 static int fpisTemplate(void *, Dsymbol
*s
)
289 if (s
->isTemplateDeclaration())
295 bool isTemplate(Dsymbol
*s
)
297 if (!s
->toAlias()->isOverloadable())
300 return overloadApply(s
, NULL
, &fpisTemplate
) != 0;
303 static Expression
*isDsymX(TraitsExp
*e
, bool (*fp
)(Dsymbol
*s
))
305 if (!e
->args
|| !e
->args
->length
)
307 for (size_t i
= 0; i
< e
->args
->length
; i
++)
309 Dsymbol
*s
= getDsymbolWithoutExpCtx((*e
->args
)[i
]);
316 static bool isFuncAbstractFunction(FuncDeclaration
*f
) { return f
->isAbstract(); }
317 static bool isFuncVirtualFunction(FuncDeclaration
*f
) { return f
->isVirtual(); }
318 static bool isFuncVirtualMethod(FuncDeclaration
*f
) { return f
->isVirtualMethod(); }
319 static bool isFuncFinalFunction(FuncDeclaration
*f
) { return f
->isFinalFunc(); }
320 static bool isFuncStaticFunction(FuncDeclaration
*f
) { return !f
->needThis() && !f
->isNested(); }
321 static bool isFuncOverrideFunction(FuncDeclaration
*f
) { return f
->isOverride(); }
323 static Expression
*isFuncX(TraitsExp
*e
, bool (*fp
)(FuncDeclaration
*f
))
325 if (!e
->args
|| !e
->args
->length
)
327 for (size_t i
= 0; i
< e
->args
->length
; i
++)
329 Dsymbol
*s
= getDsymbolWithoutExpCtx((*e
->args
)[i
]);
332 FuncDeclaration
*f
= s
->isFuncDeclaration();
339 static bool isDeclDisabled(Declaration
*d
) { return d
->isDisabled(); }
340 static bool isDeclFuture(Declaration
*d
) { return d
->isFuture(); }
341 static bool isDeclRef(Declaration
*d
) { return d
->isRef(); }
342 static bool isDeclOut(Declaration
*d
) { return d
->isOut(); }
343 static bool isDeclLazy(Declaration
*d
) { return (d
->storage_class
& STClazy
) != 0; }
345 static Expression
*isDeclX(TraitsExp
*e
, bool (*fp
)(Declaration
*d
))
347 if (!e
->args
|| !e
->args
->length
)
349 for (size_t i
= 0; i
< e
->args
->length
; i
++)
351 Dsymbol
*s
= getDsymbolWithoutExpCtx((*e
->args
)[i
]);
354 Declaration
*d
= s
->isDeclaration();
361 static bool isPkgModule(Package
*p
) { return p
->isModule() || p
->isPackageMod(); }
362 static bool isPkgPackage(Package
*p
) { return p
->isModule() == NULL
; }
364 static Expression
*isPkgX(TraitsExp
*e
, bool (*fp
)(Package
*p
))
366 if (!e
->args
|| !e
->args
->length
)
368 for (size_t i
= 0; i
< e
->args
->length
; i
++)
370 Dsymbol
*s
= getDsymbolWithoutExpCtx((*e
->args
)[i
]);
373 Package
*p
= resolveIsPackage(s
);
380 // callback for TypeFunction::attributesApply
381 struct PushAttributes
385 static int fp(void *param
, const char *str
)
387 PushAttributes
*p
= (PushAttributes
*)param
;
388 p
->mods
->push(new StringExp(Loc(), const_cast<char *>(str
)));
393 StringTable traitsStringTable
;
395 struct TraitsInitializer
400 static TraitsInitializer traitsinitializer
;
402 TraitsInitializer::TraitsInitializer()
404 const char* traits
[] = {
407 "isAssociativeArray",
421 "isAbstractFunction",
423 "isOverrideFunction",
440 "getVirtualFunctions",
450 "getFunctionAttributes",
451 "getFunctionVariadicStyle",
452 "getParameterStorageClasses",
464 traitsStringTable
._init(56);
466 for (size_t idx
= 0;; idx
++)
468 const char *s
= traits
[idx
];
470 StringValue
*sv
= traitsStringTable
.insert(s
, strlen(s
), const_cast<char *>(s
));
475 void *trait_search_fp(void *, const char *seed
, int* cost
)
477 //printf("trait_search_fp('%s')\n", seed);
478 size_t len
= strlen(seed
);
483 StringValue
*sv
= traitsStringTable
.lookup(seed
, len
);
484 return sv
? (void*)sv
->ptrvalue
: NULL
;
488 * get an array of size_t values that indicate possible pointer words in memory
489 * if interpreted as the type given as argument
490 * the first array element is the size of the type for independent interpretation
492 * following elements bits represent one word (4/8 bytes depending on the target
493 * architecture). If set the corresponding memory might contain a pointer/reference.
495 * [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
497 Expression
*pointerBitmap(TraitsExp
*e
)
499 if (!e
->args
|| e
->args
->length
!= 1)
501 error(e
->loc
, "a single type expected for trait pointerBitmap");
502 return new ErrorExp();
504 Type
*t
= getType((*e
->args
)[0]);
507 error(e
->loc
, "%s is not a type", (*e
->args
)[0]->toChars());
508 return new ErrorExp();
511 if (t
->ty
== Tclass
&& !((TypeClass
*)t
)->sym
->isInterfaceDeclaration())
512 sz
= ((TypeClass
*)t
)->sym
->AggregateDeclaration::size(e
->loc
);
514 sz
= t
->size(e
->loc
);
515 if (sz
== SIZE_INVALID
)
516 return new ErrorExp();
518 const d_uns64 sz_size_t
= Type::tsize_t
->size(e
->loc
);
519 if (sz
> UINT64_MAX
- sz_size_t
)
521 error(e
->loc
, "size overflow for type %s", t
->toChars());
522 return new ErrorExp();
525 d_uns64 bitsPerWord
= sz_size_t
* 8;
526 d_uns64 cntptr
= (sz
+ sz_size_t
- 1) / sz_size_t
;
527 d_uns64 cntdata
= (cntptr
+ bitsPerWord
- 1) / bitsPerWord
;
529 data
.setDim((size_t)cntdata
);
532 class PointerBitmapVisitor
: public Visitor
535 PointerBitmapVisitor(Array
<d_uns64
>* _data
, d_uns64 _sz_size_t
)
536 : data(_data
), offset(0), sz_size_t(_sz_size_t
), error(false)
539 void setpointer(d_uns64 off
)
541 d_uns64 ptroff
= off
/ sz_size_t
;
542 (*data
)[(size_t)(ptroff
/ (8 * sz_size_t
))] |= 1LL << (ptroff
% (8 * sz_size_t
));
544 virtual void visit(Type
*t
)
546 Type
*tb
= t
->toBasetype();
550 virtual void visit(TypeError
*t
) { visit((Type
*)t
); }
551 virtual void visit(TypeNext
*) { assert(0); }
552 virtual void visit(TypeBasic
*t
)
557 virtual void visit(TypeVector
*) { }
558 virtual void visit(TypeArray
*) { assert(0); }
559 virtual void visit(TypeSArray
*t
)
561 d_uns64 arrayoff
= offset
;
562 d_uns64 nextsize
= t
->next
->size();
563 if (nextsize
== SIZE_INVALID
)
565 d_uns64 dim
= t
->dim
->toInteger();
566 for (d_uns64 i
= 0; i
< dim
; i
++)
568 offset
= arrayoff
+ i
* nextsize
;
569 t
->next
->accept(this);
573 virtual void visit(TypeDArray
*) { setpointer(offset
+ sz_size_t
); } // dynamic array is {length,ptr}
574 virtual void visit(TypeAArray
*) { setpointer(offset
); }
575 virtual void visit(TypePointer
*t
)
577 if (t
->nextOf()->ty
!= Tfunction
) // don't mark function pointers
580 virtual void visit(TypeReference
*) { setpointer(offset
); }
581 virtual void visit(TypeClass
*) { setpointer(offset
); }
582 virtual void visit(TypeFunction
*) { }
583 virtual void visit(TypeDelegate
*) { setpointer(offset
); } // delegate is {context, function}
584 virtual void visit(TypeQualified
*) { assert(0); } // assume resolved
585 virtual void visit(TypeIdentifier
*) { assert(0); }
586 virtual void visit(TypeInstance
*) { assert(0); }
587 virtual void visit(TypeTypeof
*) { assert(0); }
588 virtual void visit(TypeReturn
*) { assert(0); }
589 virtual void visit(TypeEnum
*t
) { visit((Type
*)t
); }
590 virtual void visit(TypeTuple
*t
) { visit((Type
*)t
); }
591 virtual void visit(TypeSlice
*) { assert(0); }
592 virtual void visit(TypeNull
*) { } // always a null pointer
594 virtual void visit(TypeStruct
*t
)
596 d_uns64 structoff
= offset
;
597 for (size_t i
= 0; i
< t
->sym
->fields
.length
; i
++)
599 VarDeclaration
*v
= t
->sym
->fields
[i
];
600 offset
= structoff
+ v
->offset
;
601 if (v
->type
->ty
== Tclass
)
604 v
->type
->accept(this);
609 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
610 void visitClass(TypeClass
* t
)
612 d_uns64 classoff
= offset
;
614 // skip vtable-ptr and monitor
615 if (t
->sym
->baseClass
)
616 visitClass((TypeClass
*)t
->sym
->baseClass
->type
);
618 for (size_t i
= 0; i
< t
->sym
->fields
.length
; i
++)
620 VarDeclaration
*v
= t
->sym
->fields
[i
];
621 offset
= classoff
+ v
->offset
;
622 v
->type
->accept(this);
627 Array
<d_uns64
>* data
;
633 PointerBitmapVisitor
pbv(&data
, sz_size_t
);
635 pbv
.visitClass((TypeClass
*)t
);
639 return new ErrorExp();
641 Expressions
* exps
= new Expressions
;
642 exps
->push(new IntegerExp(e
->loc
, sz
, Type::tsize_t
));
643 for (d_uns64 i
= 0; i
< cntdata
; i
++)
644 exps
->push(new IntegerExp(e
->loc
, data
[(size_t)i
], Type::tsize_t
));
646 ArrayLiteralExp
* ale
= new ArrayLiteralExp(e
->loc
, Type::tsize_t
->sarrayOf(cntdata
+ 1), exps
);
650 static Expression
*dimError(TraitsExp
*e
, int expected
, int dim
)
652 e
->error("expected %d arguments for `%s` but had %d", expected
, e
->ident
->toChars(), dim
);
653 return new ErrorExp();
656 Expression
*semanticTraits(TraitsExp
*e
, Scope
*sc
)
658 if (e
->ident
!= Id::compiles
&&
659 e
->ident
!= Id::isSame
&&
660 e
->ident
!= Id::identifier
&&
661 e
->ident
!= Id::getProtection
&& e
->ident
!= Id::getVisibility
&&
662 e
->ident
!= Id::getAttributes
)
664 // Pretend we're in a deprecated scope so that deprecation messages
665 // aren't triggered when checking if a symbol is deprecated
666 const StorageClass save
= sc
->stc
;
667 if (e
->ident
== Id::isDeprecated
)
668 sc
->stc
|= STCdeprecated
;
669 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 1))
672 return new ErrorExp();
676 size_t dim
= e
->args
? e
->args
->length
: 0;
678 if (e
->ident
== Id::isArithmetic
)
680 return isTypeX(e
, &isTypeArithmetic
);
682 else if (e
->ident
== Id::isFloating
)
684 return isTypeX(e
, &isTypeFloating
);
686 else if (e
->ident
== Id::isIntegral
)
688 return isTypeX(e
, &isTypeIntegral
);
690 else if (e
->ident
== Id::isScalar
)
692 return isTypeX(e
, &isTypeScalar
);
694 else if (e
->ident
== Id::isUnsigned
)
696 return isTypeX(e
, &isTypeUnsigned
);
698 else if (e
->ident
== Id::isAssociativeArray
)
700 return isTypeX(e
, &isTypeAssociativeArray
);
702 else if (e
->ident
== Id::isDeprecated
)
704 return isDsymX(e
, &isDsymDeprecated
);
706 else if (e
->ident
== Id::isFuture
)
708 return isDeclX(e
, &isDeclFuture
);
710 else if (e
->ident
== Id::isStaticArray
)
712 return isTypeX(e
, &isTypeStaticArray
);
714 else if (e
->ident
== Id::isAbstractClass
)
716 return isTypeX(e
, &isTypeAbstractClass
);
718 else if (e
->ident
== Id::isFinalClass
)
720 return isTypeX(e
, &isTypeFinalClass
);
722 else if (e
->ident
== Id::isTemplate
)
725 return dimError(e
, 1, dim
);
727 return isDsymX(e
, &isTemplate
);
729 else if (e
->ident
== Id::isPOD
)
732 return dimError(e
, 1, dim
);
734 RootObject
*o
= (*e
->args
)[0];
738 e
->error("type expected as second argument of __traits %s instead of %s",
739 e
->ident
->toChars(), o
->toChars());
740 return new ErrorExp();
743 Type
*tb
= t
->baseElemOf();
744 if (StructDeclaration
*sd
= (tb
->ty
== Tstruct
) ? ((TypeStruct
*)tb
)->sym
: NULL
)
746 return (sd
->isPOD()) ? True(e
) : False(e
);
750 else if (e
->ident
== Id::hasPostblit
)
753 return dimError(e
, 1, dim
);
755 RootObject
*o
= (*e
->args
)[0];
759 e
->error("type expected as second argument of __traits %s instead of %s",
760 e
->ident
->toChars(), o
->toChars());
761 return new ErrorExp();
764 Type
*tb
= t
->baseElemOf();
765 if (StructDeclaration
*sd
= (tb
->ty
== Tstruct
) ? ((TypeStruct
*)tb
)->sym
: NULL
)
767 return sd
->postblit
? True(e
) : False(e
);
771 else if (e
->ident
== Id::isCopyable
)
774 return dimError(e
, 1, dim
);
776 RootObject
*o
= (*e
->args
)[0];
780 e
->error("type expected as second argument of __traits %s instead of %s",
781 e
->ident
->toChars(), o
->toChars());
782 return new ErrorExp();
785 return isCopyable(t
) ? True(e
) : False(e
);
787 else if (e
->ident
== Id::isNested
)
790 return dimError(e
, 1, dim
);
792 RootObject
*o
= (*e
->args
)[0];
793 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
797 else if (AggregateDeclaration
*a
= s
->isAggregateDeclaration())
799 return a
->isNested() ? True(e
) : False(e
);
801 else if (FuncDeclaration
*f
= s
->isFuncDeclaration())
803 return f
->isNested() ? True(e
) : False(e
);
806 e
->error("aggregate or function expected instead of '%s'", o
->toChars());
807 return new ErrorExp();
809 else if (e
->ident
== Id::isDisabled
)
812 return dimError(e
, 1, dim
);
814 return isDeclX(e
, &isDeclDisabled
);
816 else if (e
->ident
== Id::isAbstractFunction
)
819 return dimError(e
, 1, dim
);
821 return isFuncX(e
, &isFuncAbstractFunction
);
823 else if (e
->ident
== Id::isVirtualFunction
)
826 return dimError(e
, 1, dim
);
828 return isFuncX(e
, &isFuncVirtualFunction
);
830 else if (e
->ident
== Id::isVirtualMethod
)
833 return dimError(e
, 1, dim
);
835 return isFuncX(e
, &isFuncVirtualMethod
);
837 else if (e
->ident
== Id::isFinalFunction
)
840 return dimError(e
, 1, dim
);
842 return isFuncX(e
, &isFuncFinalFunction
);
844 else if (e
->ident
== Id::isOverrideFunction
)
847 return dimError(e
, 1, dim
);
849 return isFuncX(e
, &isFuncOverrideFunction
);
851 else if (e
->ident
== Id::isStaticFunction
)
854 return dimError(e
, 1, dim
);
856 return isFuncX(e
, &isFuncStaticFunction
);
858 else if (e
->ident
== Id::isModule
)
861 return dimError(e
, 1, dim
);
863 return isPkgX(e
, &isPkgModule
);
865 else if (e
->ident
== Id::isPackage
)
868 return dimError(e
, 1, dim
);
870 return isPkgX(e
, &isPkgPackage
);
872 else if (e
->ident
== Id::isRef
)
875 return dimError(e
, 1, dim
);
877 return isDeclX(e
, &isDeclRef
);
879 else if (e
->ident
== Id::isOut
)
882 return dimError(e
, 1, dim
);
884 return isDeclX(e
, &isDeclOut
);
886 else if (e
->ident
== Id::isLazy
)
889 return dimError(e
, 1, dim
);
891 return isDeclX(e
, &isDeclLazy
);
893 else if (e
->ident
== Id::identifier
)
895 // Get identifier for symbol as a string literal
896 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
897 * a symbol should not be folded to a constant.
898 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
900 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 2))
901 return new ErrorExp();
903 return dimError(e
, 1, dim
);
905 RootObject
*o
= (*e
->args
)[0];
906 Identifier
*id
= NULL
;
907 if (Parameter
*po
= isParameter(o
))
911 e
->error("argument `%s` has no identifier", po
->type
->toChars());
912 return new ErrorExp();
918 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
921 e
->error("argument %s has no identifier", o
->toChars());
922 return new ErrorExp();
927 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(id
->toChars()));
928 return semantic(se
, sc
);
930 else if (e
->ident
== Id::getProtection
|| e
->ident
== Id::getVisibility
)
933 return dimError(e
, 1, dim
);
935 Scope
*sc2
= sc
->push();
936 sc2
->flags
= sc
->flags
| SCOPEnoaccesscheck
| SCOPEignoresymbolvisibility
;
937 bool ok
= TemplateInstance::semanticTiargs(e
->loc
, sc2
, e
->args
, 1);
940 return new ErrorExp();
942 RootObject
*o
= (*e
->args
)[0];
943 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
947 e
->error("argument %s has no protection", o
->toChars());
948 return new ErrorExp();
950 if (s
->semanticRun
== PASSinit
)
953 const char *protName
= protectionToChars(s
->prot().kind
); // TODO: How about package(names)
955 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(protName
));
956 return semantic(se
, sc
);
958 else if (e
->ident
== Id::parent
)
961 return dimError(e
, 1, dim
);
963 RootObject
*o
= (*e
->args
)[0];
964 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
967 if (FuncDeclaration
*fd
= s
->isFuncDeclaration()) // Bugzilla 8943
968 s
= fd
->toAliasFunc();
969 if (!s
->isImport()) // Bugzilla 8922
972 if (!s
|| s
->isImport())
974 e
->error("argument %s has no parent", o
->toChars());
975 return new ErrorExp();
978 if (FuncDeclaration
*f
= s
->isFuncDeclaration())
980 if (TemplateDeclaration
*td
= getFuncTemplateDecl(f
))
982 if (td
->overroot
) // if not start of overloaded list of TemplateDeclaration's
983 td
= td
->overroot
; // then get the start
984 Expression
*ex
= new TemplateExp(e
->loc
, td
, f
);
985 ex
= semantic(ex
, sc
);
989 if (FuncLiteralDeclaration
*fld
= f
->isFuncLiteralDeclaration())
991 // Directly translate to VarExp instead of FuncExp
992 Expression
*ex
= new VarExp(e
->loc
, fld
, true);
993 return semantic(ex
, sc
);
997 return resolve(e
->loc
, sc
, s
, false);
999 else if (e
->ident
== Id::child
)
1002 return dimError(e
, 2, dim
);
1005 RootObject
*op
= (*e
->args
)[0];
1006 if (Dsymbol
*symp
= getDsymbol(op
))
1007 ex
= new DsymbolExp(e
->loc
, symp
);
1008 else if (Expression
*exp
= isExpression(op
))
1012 e
->error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op
->toChars());
1013 return new ErrorExp();
1016 ex
= semantic(ex
, sc
);
1017 RootObject
*oc
= (*e
->args
)[1];
1018 Dsymbol
*symc
= getDsymbol(oc
);
1021 e
->error("symbol expected as second argument of __traits `child` instead of `%s`", oc
->toChars());
1022 return new ErrorExp();
1025 if (Declaration
*d
= symc
->isDeclaration())
1026 ex
= new DotVarExp(e
->loc
, ex
, d
);
1027 else if (TemplateDeclaration
*td
= symc
->isTemplateDeclaration())
1028 ex
= new DotExp(e
->loc
, ex
, new TemplateExp(e
->loc
, td
));
1029 else if (ScopeDsymbol
*ti
= symc
->isScopeDsymbol())
1030 ex
= new DotExp(e
->loc
, ex
, new ScopeExp(e
->loc
, ti
));
1034 ex
= semantic(ex
, sc
);
1037 else if (e
->ident
== Id::hasMember
||
1038 e
->ident
== Id::getMember
||
1039 e
->ident
== Id::getOverloads
||
1040 e
->ident
== Id::getVirtualMethods
||
1041 e
->ident
== Id::getVirtualFunctions
)
1043 if (dim
!= 2 && !(dim
== 3 && e
->ident
== Id::getOverloads
))
1044 return dimError(e
, 2, dim
);
1046 RootObject
*o
= (*e
->args
)[0];
1047 Expression
*ex
= isExpression((*e
->args
)[1]);
1050 e
->error("expression expected as second argument of __traits %s", e
->ident
->toChars());
1051 return new ErrorExp();
1053 ex
= ex
->ctfeInterpret();
1055 bool includeTemplates
= false;
1056 if (dim
== 3 && e
->ident
== Id::getOverloads
)
1058 Expression
*b
= isExpression((*e
->args
)[2]);
1059 b
= b
->ctfeInterpret();
1060 if (!b
->type
->equals(Type::tbool
))
1062 e
->error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b
->toChars(), b
->type
->toChars());
1063 return new ErrorExp();
1065 includeTemplates
= b
->isBool(true);
1068 StringExp
*se
= ex
->toStringExp();
1069 if (!se
|| se
->len
== 0)
1071 e
->error("string expected as second argument of __traits %s instead of %s", e
->ident
->toChars(), ex
->toChars());
1072 return new ErrorExp();
1074 se
= se
->toUTF8(sc
);
1078 e
->error("string must be chars");
1079 return new ErrorExp();
1081 Identifier
*id
= Identifier::idPool((char *)se
->string
, se
->len
);
1083 /* Prefer dsymbol, because it might need some runtime contexts.
1085 Dsymbol
*sym
= getDsymbol(o
);
1088 if (e
->ident
== Id::hasMember
)
1090 if (sym
->search(e
->loc
, id
) != NULL
)
1093 ex
= new DsymbolExp(e
->loc
, sym
);
1094 ex
= new DotIdExp(e
->loc
, ex
, id
);
1096 else if (Type
*t
= isType(o
))
1097 ex
= typeDotIdExp(e
->loc
, t
, id
);
1098 else if (Expression
*ex2
= isExpression(o
))
1099 ex
= new DotIdExp(e
->loc
, ex2
, id
);
1102 e
->error("invalid first argument");
1103 return new ErrorExp();
1106 if (e
->ident
== Id::hasMember
)
1108 /* Take any errors as meaning it wasn't found
1110 Scope
*scx
= sc
->push();
1111 scx
->flags
|= SCOPEignoresymbolvisibility
;
1112 ex
= trySemantic(ex
, scx
);
1114 return ex
? True(e
) : False(e
);
1116 else if (e
->ident
== Id::getMember
)
1118 if (ex
->op
== TOKdotid
)
1119 // Prevent semantic() from replacing Symbol with its initializer
1120 ((DotIdExp
*)ex
)->wantsym
= true;
1121 Scope
*scx
= sc
->push();
1122 scx
->flags
|= SCOPEignoresymbolvisibility
;
1123 ex
= semantic(ex
, scx
);
1127 else if (e
->ident
== Id::getVirtualFunctions
||
1128 e
->ident
== Id::getVirtualMethods
||
1129 e
->ident
== Id::getOverloads
)
1131 unsigned errors
= global
.errors
;
1132 Expression
*eorig
= ex
;
1133 Scope
*scx
= sc
->push();
1134 scx
->flags
|= SCOPEignoresymbolvisibility
;
1135 ex
= semantic(ex
, scx
);
1136 if (errors
< global
.errors
)
1137 e
->error("%s cannot be resolved", eorig
->toChars());
1140 /* Create tuple of functions of ex
1142 Expressions
*exps
= new Expressions();
1144 if (ex
->op
== TOKvar
)
1146 VarExp
*ve
= (VarExp
*)ex
;
1147 f
= ve
->var
->isFuncDeclaration();
1150 else if (ex
->op
== TOKdotvar
)
1152 DotVarExp
*dve
= (DotVarExp
*)ex
;
1153 f
= dve
->var
->isFuncDeclaration();
1154 if (dve
->e1
->op
== TOKdottype
|| dve
->e1
->op
== TOKthis
)
1159 else if (ex
->op
== TOKtemplate
)
1161 TemplateExp
*te
= (TemplateExp
*)ex
;
1162 TemplateDeclaration
*td
= te
->td
;
1164 if (td
&& td
->funcroot
)
1175 p
.includeTemplates
= includeTemplates
;
1176 AA
*funcTypeHash
= NULL
;
1177 p
.funcTypeHash
= &funcTypeHash
;
1179 InterfaceDeclaration
*ifd
= NULL
;
1181 ifd
= sym
->isInterfaceDeclaration();
1182 // If the symbol passed as a parameter is an
1183 // interface that inherits other interfaces
1184 if (ifd
&& ifd
->interfaces
.length
)
1186 // check the overloads of each inherited interface individually
1187 for (size_t i
= 0; i
< ifd
->interfaces
.length
; i
++)
1189 BaseClass
*bc
= ifd
->interfaces
.ptr
[i
];
1190 if (Dsymbol
*fd
= bc
->sym
->search(e
->loc
, f
->ident
))
1191 overloadApply(fd
, &p
, &fptraits
);
1195 overloadApply(f
, &p
, &fptraits
);
1197 ex
= new TupleExp(e
->loc
, exps
);
1198 ex
= semantic(ex
, scx
);
1205 else if (e
->ident
== Id::classInstanceSize
)
1208 return dimError(e
, 1, dim
);
1210 RootObject
*o
= (*e
->args
)[0];
1211 Dsymbol
*s
= getDsymbol(o
);
1212 ClassDeclaration
*cd
= s
? s
->isClassDeclaration() : NULL
;
1215 e
->error("first argument is not a class");
1216 return new ErrorExp();
1218 if (cd
->sizeok
!= SIZEOKdone
)
1222 if (cd
->sizeok
!= SIZEOKdone
)
1224 e
->error("%s %s is forward referenced", cd
->kind(), cd
->toChars());
1225 return new ErrorExp();
1228 return new IntegerExp(e
->loc
, cd
->structsize
, Type::tsize_t
);
1230 else if (e
->ident
== Id::getAliasThis
)
1233 return dimError(e
, 1, dim
);
1235 RootObject
*o
= (*e
->args
)[0];
1236 Dsymbol
*s
= getDsymbol(o
);
1237 AggregateDeclaration
*ad
= s
? s
->isAggregateDeclaration() : NULL
;
1240 e
->error("argument is not an aggregate type");
1241 return new ErrorExp();
1244 Expressions
*exps
= new Expressions();
1246 exps
->push(new StringExp(e
->loc
, const_cast<char *>(ad
->aliasthis
->ident
->toChars())));
1247 Expression
*ex
= new TupleExp(e
->loc
, exps
);
1248 ex
= semantic(ex
, sc
);
1251 else if (e
->ident
== Id::getAttributes
)
1253 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
1254 * a symbol should not be folded to a constant.
1255 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
1257 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 3))
1258 return new ErrorExp();
1261 return dimError(e
, 1, dim
);
1263 RootObject
*o
= (*e
->args
)[0];
1264 Parameter
*po
= isParameter(o
);
1265 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
1266 UserAttributeDeclaration
*udad
= NULL
;
1269 udad
= po
->userAttribDecl
;
1273 if (Import
*imp
= s
->isImport())
1277 //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
1278 udad
= s
->userAttribDecl
;
1282 e
->error("first argument is not a symbol");
1283 return new ErrorExp();
1286 Expressions
*exps
= udad
? udad
->getAttributes() : new Expressions();
1287 TupleExp
*tup
= new TupleExp(e
->loc
, exps
);
1288 return semantic(tup
, sc
);
1290 else if (e
->ident
== Id::getFunctionAttributes
)
1292 /* extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
1293 * https://dlang.org/spec/traits.html#getFunctionAttributes
1296 return dimError(e
, 1, dim
);
1298 TypeFunction
*tf
= toTypeFunction((*e
->args
)[0]);
1302 e
->error("first argument is not a function");
1303 return new ErrorExp();
1306 Expressions
*mods
= new Expressions();
1309 tf
->modifiersApply(&pa
, &PushAttributes::fp
);
1310 tf
->attributesApply(&pa
, &PushAttributes::fp
, TRUSTformatSystem
);
1312 TupleExp
*tup
= new TupleExp(e
->loc
, mods
);
1313 return semantic(tup
, sc
);
1315 else if (e
->ident
== Id::isReturnOnStack
)
1317 /* Extract as a boolean if function return value is on the stack
1318 * https://dlang.org/spec/traits.html#isReturnOnStack
1321 return dimError(e
, 1, dim
);
1323 RootObject
*o
= (*e
->args
)[0];
1324 FuncDeclaration
*fd
= NULL
;
1325 TypeFunction
*tf
= toTypeFunction(o
, &fd
);
1329 e
->error("argument to `__traits(isReturnOnStack, %s)` is not a function", o
->toChars());
1330 return new ErrorExp();
1333 bool value
= target
.isReturnOnStack(tf
, fd
&& fd
->needThis());
1334 return new IntegerExp(e
->loc
, value
, Type::tbool
);
1336 else if (e
->ident
== Id::getFunctionVariadicStyle
)
1338 /* Accept a symbol or a type. Returns one of the following:
1339 * "none" not a variadic function
1340 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
1341 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
1342 * "typesafe" void typesafe(T[] ...)
1344 // get symbol linkage as a string
1346 return dimError(e
, 1, dim
);
1350 RootObject
*o
= (*e
->args
)[0];
1351 FuncDeclaration
*fd
= NULL
;
1352 TypeFunction
*tf
= toTypeFunction(o
, &fd
);
1357 varargs
= tf
->parameterList
.varargs
;
1363 e
->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o
->toChars());
1364 return new ErrorExp();
1367 varargs
= fd
->getParameterList().varargs
;
1372 case 0: style
= "none"; break;
1373 case 1: style
= (link
== LINKd
) ? "argptr"
1375 case 2: style
= "typesafe"; break;
1379 StringExp
*se
= new StringExp(e
->loc
, const_cast<char*>(style
));
1380 return semantic(se
, sc
);
1382 else if (e
->ident
== Id::getParameterStorageClasses
)
1384 /* Accept a function symbol or a type, followed by a parameter index.
1385 * Returns a tuple of strings of the parameter's storage classes.
1387 // get symbol linkage as a string
1389 return dimError(e
, 2, dim
);
1391 RootObject
*o
= (*e
->args
)[0];
1392 RootObject
*o1
= (*e
->args
)[1];
1394 FuncDeclaration
*fd
= NULL
;
1395 TypeFunction
*tf
= toTypeFunction(o
, &fd
);
1397 ParameterList fparams
;
1400 fparams
= tf
->parameterList
;
1406 e
->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
1407 o
->toChars(), o1
->toChars());
1408 return new ErrorExp();
1410 fparams
= fd
->getParameterList();
1415 // Set stc to storage class of the ith parameter
1416 Expression
*ex
= isExpression((*e
->args
)[1]);
1419 e
->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1420 o
->toChars(), o1
->toChars());
1421 return new ErrorExp();
1423 ex
= ex
->ctfeInterpret();
1424 uinteger_t ii
= ex
->toUInteger();
1425 if (ii
>= fparams
.length())
1427 e
->error("parameter index must be in range 0..%u not %s", (unsigned)fparams
.length(), ex
->toChars());
1428 return new ErrorExp();
1431 unsigned n
= (unsigned)ii
;
1432 Parameter
*p
= fparams
[n
];
1433 stc
= p
->storageClass
;
1435 // This mirrors hdrgen.visit(Parameter p)
1436 if (p
->type
&& p
->type
->mod
& MODshared
)
1439 Expressions
*exps
= new Expressions
;
1442 exps
->push(new StringExp(e
->loc
, const_cast<char *>("auto")));
1443 if (stc
& STCreturn
)
1444 exps
->push(new StringExp(e
->loc
, const_cast<char *>("return")));
1447 exps
->push(new StringExp(e
->loc
, const_cast<char *>("out")));
1448 else if (stc
& STCref
)
1449 exps
->push(new StringExp(e
->loc
, const_cast<char *>("ref")));
1450 else if (stc
& STCin
)
1451 exps
->push(new StringExp(e
->loc
, const_cast<char *>("in")));
1452 else if (stc
& STClazy
)
1453 exps
->push(new StringExp(e
->loc
, const_cast<char *>("lazy")));
1454 else if (stc
& STCalias
)
1455 exps
->push(new StringExp(e
->loc
, const_cast<char *>("alias")));
1458 exps
->push(new StringExp(e
->loc
, const_cast<char *>("const")));
1459 if (stc
& STCimmutable
)
1460 exps
->push(new StringExp(e
->loc
, const_cast<char *>("immutable")));
1462 exps
->push(new StringExp(e
->loc
, const_cast<char *>("inout")));
1463 if (stc
& STCshared
)
1464 exps
->push(new StringExp(e
->loc
, const_cast<char *>("shared")));
1465 if (stc
& STCscope
&& !(stc
& STCscopeinferred
))
1466 exps
->push(new StringExp(e
->loc
, const_cast<char *>("scope")));
1468 TupleExp
*tup
= new TupleExp(e
->loc
, exps
);
1469 return semantic(tup
, sc
);
1471 else if (e
->ident
== Id::getLinkage
)
1473 // get symbol linkage as a string
1475 return dimError(e
, 1, dim
);
1478 RootObject
*o
= (*e
->args
)[0];
1480 TypeFunction
*tf
= toTypeFunction(o
);
1486 Dsymbol
*s
= getDsymbol(o
);
1487 Declaration
*d
= NULL
;
1488 AggregateDeclaration
*ad
= NULL
;
1489 if (!s
|| ((d
= s
->isDeclaration()) == NULL
1490 && (ad
= s
->isAggregateDeclaration()) == NULL
))
1492 e
->error("argument to `__traits(getLinkage, %s)` is not a declaration", o
->toChars());
1493 return new ErrorExp();
1499 switch (ad
->classKind
)
1504 case ClassKind::cpp
:
1507 case ClassKind::objc
:
1515 const char *linkage
= linkageToChars(link
);
1516 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(linkage
));
1517 return semantic(se
, sc
);
1519 else if (e
->ident
== Id::allMembers
||
1520 e
->ident
== Id::derivedMembers
)
1523 return dimError(e
, 1, dim
);
1525 RootObject
*o
= (*e
->args
)[0];
1526 Dsymbol
*s
= getDsymbol(o
);
1529 e
->error("argument has no members");
1530 return new ErrorExp();
1532 if (Import
*imp
= s
->isImport())
1538 ScopeDsymbol
*sds
= s
->isScopeDsymbol();
1539 if (!sds
|| sds
->isTemplateDeclaration())
1541 e
->error("%s %s has no members", s
->kind(), s
->toChars());
1542 return new ErrorExp();
1545 // use a struct as local function
1549 Identifiers
*idents
;
1551 static int dg(void *ctx
, size_t, Dsymbol
*sm
)
1556 // skip local symbols, such as static foreach loop variables
1557 if (Declaration
*decl
= sm
->isDeclaration())
1559 if (decl
->storage_class
& STClocal
)
1565 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
1568 // https://issues.dlang.org/show_bug.cgi?id=10096
1569 // https://issues.dlang.org/show_bug.cgi?id=10100
1570 // Skip over internal members in __traits(allMembers)
1571 if ((sm
->isCtorDeclaration() && sm
->ident
!= Id::ctor
) ||
1572 (sm
->isDtorDeclaration() && sm
->ident
!= Id::dtor
) ||
1573 (sm
->isPostBlitDeclaration() && sm
->ident
!= Id::postblit
) ||
1574 sm
->isInvariantDeclaration() ||
1575 sm
->isUnitTestDeclaration())
1580 if (sm
->ident
== Id::empty
)
1584 if (sm
->isTypeInfoDeclaration()) // Bugzilla 15177
1586 PushIdentsDg
*pid
= (PushIdentsDg
*)ctx
;
1587 if (!pid
->sds
->isModule() && sm
->isImport()) // Bugzilla 17057
1590 //printf("\t%s\n", sm->ident->toChars());
1591 Identifiers
*idents
= pid
->idents
;
1593 /* Skip if already present in idents[]
1595 for (size_t j
= 0; j
< idents
->length
; j
++)
1597 Identifier
*id
= (*idents
)[j
];
1598 if (id
== sm
->ident
)
1602 idents
->push(sm
->ident
);
1606 EnumDeclaration
*ed
= sm
->isEnumDeclaration();
1609 ScopeDsymbol_foreach(NULL
, ed
->members
, &PushIdentsDg::dg
, ctx
);
1616 Identifiers
*idents
= new Identifiers
;
1619 ctx
.idents
= idents
;
1620 ScopeDsymbol_foreach(sc
, sds
->members
, &PushIdentsDg::dg
, &ctx
);
1621 ClassDeclaration
*cd
= sds
->isClassDeclaration();
1622 if (cd
&& e
->ident
== Id::allMembers
)
1624 if (cd
->semanticRun
< PASSsemanticdone
)
1625 cd
->semantic(NULL
); // Bugzilla 13668: Try to resolve forward reference
1627 struct PushBaseMembers
1629 static void dg(ClassDeclaration
*cd
, PushIdentsDg
*ctx
)
1631 for (size_t i
= 0; i
< cd
->baseclasses
->length
; i
++)
1633 ClassDeclaration
*cb
= (*cd
->baseclasses
)[i
]->sym
;
1635 ScopeDsymbol_foreach(NULL
, cb
->members
, &PushIdentsDg::dg
, ctx
);
1636 if (cb
->baseclasses
->length
)
1641 PushBaseMembers::dg(cd
, &ctx
);
1644 // Turn Identifiers into StringExps reusing the allocated array
1645 assert(sizeof(Expressions
) == sizeof(Identifiers
));
1646 Expressions
*exps
= (Expressions
*)idents
;
1647 for (size_t i
= 0; i
< idents
->length
; i
++)
1649 Identifier
*id
= (*idents
)[i
];
1650 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(id
->toChars()));
1654 /* Making this a tuple is more flexible, as it can be statically unrolled.
1655 * To make an array literal, enclose __traits in [ ]:
1656 * [ __traits(allMembers, ...) ]
1658 Expression
*ex
= new TupleExp(e
->loc
, exps
);
1659 ex
= semantic(ex
, sc
);
1662 else if (e
->ident
== Id::compiles
)
1664 /* Determine if all the objects - types, expressions, or symbols -
1665 * compile without error
1670 for (size_t i
= 0; i
< dim
; i
++)
1672 unsigned errors
= global
.startGagging();
1673 Scope
*sc2
= sc
->push();
1676 sc2
->flags
= (sc
->flags
& ~(SCOPEctfe
| SCOPEcondition
)) | SCOPEcompile
| SCOPEfullinst
;
1679 RootObject
*o
= (*e
->args
)[i
];
1680 Type
*t
= isType(o
);
1681 Expression
*ex
= t
? typeToExpression(t
) : isExpression(o
);
1685 t
->resolve(e
->loc
, sc2
, &ex
, &t
, &s
);
1688 t
->semantic(e
->loc
, sc2
);
1689 if (t
->ty
== Terror
)
1692 else if (s
&& s
->errors
)
1697 ex
= semantic(ex
, sc2
);
1698 ex
= resolvePropertiesOnly(sc2
, ex
);
1699 ex
= ex
->optimize(WANTvalue
);
1700 if (sc2
->func
&& sc2
->func
->type
->ty
== Tfunction
)
1702 TypeFunction
*tf
= (TypeFunction
*)sc2
->func
->type
;
1703 canThrow(ex
, sc2
->func
, tf
->isnothrow
);
1705 ex
= checkGC(sc2
, ex
);
1706 if (ex
->op
== TOKerror
)
1710 // Carefully detach the scope from the parent and throw it away as
1711 // we only need it to evaluate the expression
1712 // https://issues.dlang.org/show_bug.cgi?id=15428
1714 sc2
->enclosing
= NULL
;
1717 if (global
.endGagging(errors
) || err
)
1724 else if (e
->ident
== Id::isSame
)
1726 /* Determine if two symbols are the same
1729 return dimError(e
, 2, dim
);
1731 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 0))
1732 return new ErrorExp();
1734 RootObject
*o1
= (*e
->args
)[0];
1735 RootObject
*o2
= (*e
->args
)[1];
1737 // issue 12001, allow isSame, <BasicType>, <BasicType>
1738 Type
*t1
= isType(o1
);
1739 Type
*t2
= isType(o2
);
1740 if (t1
&& t2
&& t1
->equals(t2
))
1743 Dsymbol
*s1
= getDsymbol(o1
);
1744 Dsymbol
*s2
= getDsymbol(o2
);
1745 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
1748 Expression
*ea1
= isExpression(o1
);
1749 Expression
*ea2
= isExpression(o2
);
1752 if (ea1
->equals(ea2
))
1761 if (s1
->isFuncAliasDeclaration())
1762 s1
= ((FuncAliasDeclaration
*)s1
)->toAliasFunc();
1763 if (s2
->isFuncAliasDeclaration())
1764 s2
= ((FuncAliasDeclaration
*)s2
)->toAliasFunc();
1766 return (s1
== s2
) ? True(e
) : False(e
);
1768 else if (e
->ident
== Id::getUnitTests
)
1771 return dimError(e
, 1, dim
);
1773 RootObject
*o
= (*e
->args
)[0];
1774 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
1777 e
->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1779 return new ErrorExp();
1781 if (Import
*imp
= s
->isImport()) // Bugzilla 10990
1784 ScopeDsymbol
* sds
= s
->isScopeDsymbol();
1787 e
->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
1788 s
->toChars(), s
->kind());
1789 return new ErrorExp();
1792 Expressions
*exps
= new Expressions();
1793 if (global
.params
.useUnitTests
)
1795 // Should actually be a set
1796 AA
* uniqueUnitTests
= NULL
;
1797 collectUnitTests(sds
->members
, uniqueUnitTests
, exps
);
1799 TupleExp
*te
= new TupleExp(e
->loc
, exps
);
1800 return semantic(te
, sc
);
1802 else if (e
->ident
== Id::getVirtualIndex
)
1805 return dimError(e
, 1, dim
);
1807 RootObject
*o
= (*e
->args
)[0];
1808 Dsymbol
*s
= getDsymbolWithoutExpCtx(o
);
1810 FuncDeclaration
*fd
= s
? s
->isFuncDeclaration() : NULL
;
1813 e
->error("first argument to __traits(getVirtualIndex) must be a function");
1814 return new ErrorExp();
1817 fd
= fd
->toAliasFunc(); // Neccessary to support multiple overloads.
1818 return new IntegerExp(e
->loc
, fd
->vtblIndex
, Type::tptrdiff_t
);
1820 else if (e
->ident
== Id::getPointerBitmap
)
1822 return pointerBitmap(e
);
1824 else if (e
->ident
== Id::isZeroInit
)
1827 return dimError(e
, 1, dim
);
1829 RootObject
*o
= (*e
->args
)[0];
1830 Type
*t
= isType(o
);
1833 e
->error("type expected as second argument of __traits `%s` instead of `%s`",
1834 e
->ident
->toChars(), o
->toChars());
1835 return new ErrorExp();
1838 Type
*tb
= t
->baseElemOf();
1839 return tb
->isZeroInit(e
->loc
) ? True(e
) : False(e
);
1841 else if (e
->ident
== Id::getTargetInfo
)
1844 return dimError(e
, 1, dim
);
1846 Expression
*ex
= isExpression((*e
->args
)[0]);
1847 StringExp
*se
= ex
? ex
->ctfeInterpret()->toStringExp() : NULL
;
1848 if (!ex
|| !se
|| se
->len
== 0)
1850 e
->error("string expected as argument of __traits `%s` instead of `%s`", e
->ident
->toChars(), ex
->toChars());
1851 return new ErrorExp();
1853 se
= se
->toUTF8(sc
);
1855 Expression
*r
= target
.getTargetInfo(se
->toPtr(), e
->loc
);
1858 e
->error("`getTargetInfo` key `\"%s\"` not supported by this implementation", se
->toPtr());
1859 return new ErrorExp();
1861 return semantic(r
, sc
);
1863 else if (e
->ident
== Id::getLocation
)
1866 return dimError(e
, 1, dim
);
1867 RootObject
*arg0
= (*e
->args
)[0];
1868 Dsymbol
*s
= getDsymbolWithoutExpCtx(arg0
);
1869 if (!s
|| !s
->loc
.filename
)
1871 e
->error("can only get the location of a symbol, not `%s`", arg0
->toChars());
1872 return new ErrorExp();
1875 const FuncDeclaration
*fd
= s
->isFuncDeclaration();
1876 if (fd
&& fd
->overnext
)
1878 e
->error("cannot get location of an overload set, "
1879 "use `__traits(getOverloads, ..., \"%s\"%s)[N]` "
1880 "to get the Nth overload",
1881 arg0
->toChars(), "");
1882 return new ErrorExp();
1885 Expressions
*exps
= new Expressions();
1887 (*exps
)[0] = new StringExp(e
->loc
, const_cast<char *>(s
->loc
.filename
), strlen(s
->loc
.filename
));
1888 (*exps
)[1] = new IntegerExp(e
->loc
, s
->loc
.linnum
, Type::tint32
);
1889 (*exps
)[2] = new IntegerExp(e
->loc
, s
->loc
.charnum
, Type::tint32
);
1890 TupleExp
*tup
= new TupleExp(e
->loc
, exps
);
1891 return semantic(tup
, sc
);
1894 if (const char *sub
= (const char *)speller(e
->ident
->toChars(), &trait_search_fp
, NULL
, idchars
))
1895 e
->error("unrecognized trait '%s', did you mean '%s'?", e
->ident
->toChars(), sub
);
1897 e
->error("unrecognized trait '%s'", e
->ident
->toChars());
1898 return new ErrorExp();
1900 e
->error("wrong number of arguments %d", (int)dim
);
1901 return new ErrorExp();