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"
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
, Type::tsize_t
->sarrayOf(cntdata
+ 1), exps
);
486 static Expression
*dimError(TraitsExp
*e
, int expected
, int dim
)
488 e
->error("expected %d arguments for `%s` but had %d", expected
, e
->ident
->toChars(), dim
);
489 return new ErrorExp();
492 Expression
*semanticTraits(TraitsExp
*e
, Scope
*sc
)
494 if (e
->ident
!= Id::compiles
&& e
->ident
!= Id::isSame
&&
495 e
->ident
!= Id::identifier
&& e
->ident
!= Id::getProtection
)
497 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 1))
498 return new ErrorExp();
500 size_t dim
= e
->args
? e
->args
->dim
: 0;
502 if (e
->ident
== Id::isArithmetic
)
504 return isTypeX(e
, &isTypeArithmetic
);
506 else if (e
->ident
== Id::isFloating
)
508 return isTypeX(e
, &isTypeFloating
);
510 else if (e
->ident
== Id::isIntegral
)
512 return isTypeX(e
, &isTypeIntegral
);
514 else if (e
->ident
== Id::isScalar
)
516 return isTypeX(e
, &isTypeScalar
);
518 else if (e
->ident
== Id::isUnsigned
)
520 return isTypeX(e
, &isTypeUnsigned
);
522 else if (e
->ident
== Id::isAssociativeArray
)
524 return isTypeX(e
, &isTypeAssociativeArray
);
526 else if (e
->ident
== Id::isStaticArray
)
528 return isTypeX(e
, &isTypeStaticArray
);
530 else if (e
->ident
== Id::isAbstractClass
)
532 return isTypeX(e
, &isTypeAbstractClass
);
534 else if (e
->ident
== Id::isFinalClass
)
536 return isTypeX(e
, &isTypeFinalClass
);
538 else if (e
->ident
== Id::isTemplate
)
540 return isSymbolX(e
, &isTemplate
);
542 else if (e
->ident
== Id::isPOD
)
545 return dimError(e
, 1, dim
);
547 RootObject
*o
= (*e
->args
)[0];
551 e
->error("type expected as second argument of __traits %s instead of %s",
552 e
->ident
->toChars(), o
->toChars());
553 return new ErrorExp();
556 Type
*tb
= t
->baseElemOf();
557 if (StructDeclaration
*sd
= (tb
->ty
== Tstruct
) ? ((TypeStruct
*)tb
)->sym
: NULL
)
559 return (sd
->isPOD()) ? True(e
) : False(e
);
563 else if (e
->ident
== Id::isNested
)
566 return dimError(e
, 1, dim
);
568 RootObject
*o
= (*e
->args
)[0];
569 Dsymbol
*s
= getDsymbol(o
);
573 else if (AggregateDeclaration
*a
= s
->isAggregateDeclaration())
575 return a
->isNested() ? True(e
) : False(e
);
577 else if (FuncDeclaration
*f
= s
->isFuncDeclaration())
579 return f
->isNested() ? True(e
) : False(e
);
582 e
->error("aggregate or function expected instead of '%s'", o
->toChars());
583 return new ErrorExp();
585 else if (e
->ident
== Id::isAbstractFunction
)
587 return isFuncX(e
, &isFuncAbstractFunction
);
589 else if (e
->ident
== Id::isVirtualFunction
)
591 return isFuncX(e
, &isFuncVirtualFunction
);
593 else if (e
->ident
== Id::isVirtualMethod
)
595 return isFuncX(e
, &isFuncVirtualMethod
);
597 else if (e
->ident
== Id::isFinalFunction
)
599 return isFuncX(e
, &isFuncFinalFunction
);
601 else if (e
->ident
== Id::isOverrideFunction
)
603 return isFuncX(e
, &isFuncOverrideFunction
);
605 else if (e
->ident
== Id::isStaticFunction
)
607 return isFuncX(e
, &isFuncStaticFunction
);
609 else if (e
->ident
== Id::isRef
)
611 return isDeclX(e
, &isDeclRef
);
613 else if (e
->ident
== Id::isOut
)
615 return isDeclX(e
, &isDeclOut
);
617 else if (e
->ident
== Id::isLazy
)
619 return isDeclX(e
, &isDeclLazy
);
621 else if (e
->ident
== Id::identifier
)
623 // Get identifier for symbol as a string literal
624 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
625 * a symbol should not be folded to a constant.
626 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
628 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 2))
629 return new ErrorExp();
631 return dimError(e
, 1, dim
);
633 RootObject
*o
= (*e
->args
)[0];
634 Identifier
*id
= NULL
;
635 if (Parameter
*po
= isParameter(o
))
642 Dsymbol
*s
= getDsymbol(o
);
645 e
->error("argument %s has no identifier", o
->toChars());
646 return new ErrorExp();
651 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(id
->toChars()));
652 return semantic(se
, sc
);
654 else if (e
->ident
== Id::getProtection
)
657 return dimError(e
, 1, dim
);
659 Scope
*sc2
= sc
->push();
660 sc2
->flags
= sc
->flags
| SCOPEnoaccesscheck
;
661 bool ok
= TemplateInstance::semanticTiargs(e
->loc
, sc2
, e
->args
, 1);
664 return new ErrorExp();
666 RootObject
*o
= (*e
->args
)[0];
667 Dsymbol
*s
= getDsymbol(o
);
671 e
->error("argument %s has no protection", o
->toChars());
672 return new ErrorExp();
674 if (s
->semanticRun
== PASSinit
)
677 const char *protName
= protectionToChars(s
->prot().kind
); // TODO: How about package(names)
679 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(protName
));
680 return semantic(se
, sc
);
682 else if (e
->ident
== Id::parent
)
685 return dimError(e
, 1, dim
);
687 RootObject
*o
= (*e
->args
)[0];
688 Dsymbol
*s
= getDsymbol(o
);
691 if (FuncDeclaration
*fd
= s
->isFuncDeclaration()) // Bugzilla 8943
692 s
= fd
->toAliasFunc();
693 if (!s
->isImport()) // Bugzilla 8922
696 if (!s
|| s
->isImport())
698 e
->error("argument %s has no parent", o
->toChars());
699 return new ErrorExp();
702 if (FuncDeclaration
*f
= s
->isFuncDeclaration())
704 if (TemplateDeclaration
*td
= getFuncTemplateDecl(f
))
706 if (td
->overroot
) // if not start of overloaded list of TemplateDeclaration's
707 td
= td
->overroot
; // then get the start
708 Expression
*ex
= new TemplateExp(e
->loc
, td
, f
);
709 ex
= semantic(ex
, sc
);
713 if (FuncLiteralDeclaration
*fld
= f
->isFuncLiteralDeclaration())
715 // Directly translate to VarExp instead of FuncExp
716 Expression
*ex
= new VarExp(e
->loc
, fld
, true);
717 return semantic(ex
, sc
);
721 return resolve(e
->loc
, sc
, s
, false);
723 else if (e
->ident
== Id::hasMember
||
724 e
->ident
== Id::getMember
||
725 e
->ident
== Id::getOverloads
||
726 e
->ident
== Id::getVirtualMethods
||
727 e
->ident
== Id::getVirtualFunctions
)
730 return dimError(e
, 2, dim
);
732 RootObject
*o
= (*e
->args
)[0];
733 Expression
*ex
= isExpression((*e
->args
)[1]);
736 e
->error("expression expected as second argument of __traits %s", e
->ident
->toChars());
737 return new ErrorExp();
739 ex
= ex
->ctfeInterpret();
741 StringExp
*se
= ex
->toStringExp();
742 if (!se
|| se
->len
== 0)
744 e
->error("string expected as second argument of __traits %s instead of %s", e
->ident
->toChars(), ex
->toChars());
745 return new ErrorExp();
751 e
->error("string must be chars");
752 return new ErrorExp();
754 Identifier
*id
= Identifier::idPool((char *)se
->string
, se
->len
);
756 /* Prefer dsymbol, because it might need some runtime contexts.
758 Dsymbol
*sym
= getDsymbol(o
);
761 ex
= new DsymbolExp(e
->loc
, sym
);
762 ex
= new DotIdExp(e
->loc
, ex
, id
);
764 else if (Type
*t
= isType(o
))
765 ex
= typeDotIdExp(e
->loc
, t
, id
);
766 else if (Expression
*ex2
= isExpression(o
))
767 ex
= new DotIdExp(e
->loc
, ex2
, id
);
770 e
->error("invalid first argument");
771 return new ErrorExp();
774 if (e
->ident
== Id::hasMember
)
778 if (sym
->search(e
->loc
, id
))
782 /* Take any errors as meaning it wasn't found
784 Scope
*scx
= sc
->push();
785 scx
->flags
|= SCOPEignoresymbolvisibility
;
786 ex
= trySemantic(ex
, scx
);
788 return ex
? True(e
) : False(e
);
790 else if (e
->ident
== Id::getMember
)
792 if (ex
->op
== TOKdotid
)
793 // Prevent semantic() from replacing Symbol with its initializer
794 ((DotIdExp
*)ex
)->wantsym
= true;
795 Scope
*scx
= sc
->push();
796 scx
->flags
|= SCOPEignoresymbolvisibility
;
797 ex
= semantic(ex
, scx
);
801 else if (e
->ident
== Id::getVirtualFunctions
||
802 e
->ident
== Id::getVirtualMethods
||
803 e
->ident
== Id::getOverloads
)
805 unsigned errors
= global
.errors
;
806 Expression
*eorig
= ex
;
807 Scope
*scx
= sc
->push();
808 scx
->flags
|= SCOPEignoresymbolvisibility
;
809 ex
= semantic(ex
, scx
);
810 if (errors
< global
.errors
)
811 e
->error("%s cannot be resolved", eorig
->toChars());
814 /* Create tuple of functions of ex
816 Expressions
*exps
= new Expressions();
818 if (ex
->op
== TOKvar
)
820 VarExp
*ve
= (VarExp
*)ex
;
821 f
= ve
->var
->isFuncDeclaration();
824 else if (ex
->op
== TOKdotvar
)
826 DotVarExp
*dve
= (DotVarExp
*)ex
;
827 f
= dve
->var
->isFuncDeclaration();
828 if (dve
->e1
->op
== TOKdottype
|| dve
->e1
->op
== TOKthis
)
839 overloadApply(f
, &p
, &fptraits
);
841 ex
= new TupleExp(e
->loc
, exps
);
842 ex
= semantic(ex
, scx
);
849 else if (e
->ident
== Id::classInstanceSize
)
852 return dimError(e
, 1, dim
);
854 RootObject
*o
= (*e
->args
)[0];
855 Dsymbol
*s
= getDsymbol(o
);
856 ClassDeclaration
*cd
= s
? s
->isClassDeclaration() : NULL
;
859 e
->error("first argument is not a class");
860 return new ErrorExp();
862 if (cd
->sizeok
!= SIZEOKdone
)
866 if (cd
->sizeok
!= SIZEOKdone
)
868 e
->error("%s %s is forward referenced", cd
->kind(), cd
->toChars());
869 return new ErrorExp();
872 return new IntegerExp(e
->loc
, cd
->structsize
, Type::tsize_t
);
874 else if (e
->ident
== Id::getAliasThis
)
877 return dimError(e
, 1, dim
);
879 RootObject
*o
= (*e
->args
)[0];
880 Dsymbol
*s
= getDsymbol(o
);
881 AggregateDeclaration
*ad
= s
? s
->isAggregateDeclaration() : NULL
;
884 e
->error("argument is not an aggregate type");
885 return new ErrorExp();
888 Expressions
*exps
= new Expressions();
890 exps
->push(new StringExp(e
->loc
, const_cast<char *>(ad
->aliasthis
->ident
->toChars())));
891 Expression
*ex
= new TupleExp(e
->loc
, exps
);
892 ex
= semantic(ex
, sc
);
895 else if (e
->ident
== Id::getAttributes
)
898 return dimError(e
, 1, dim
);
900 RootObject
*o
= (*e
->args
)[0];
901 Dsymbol
*s
= getDsymbol(o
);
904 e
->error("first argument is not a symbol");
905 return new ErrorExp();
907 if (Import
*imp
= s
->isImport())
912 //printf("getAttributes %s, attrs = %p, scope = %p\n", s->toChars(), s->userAttribDecl, s->_scope);
913 UserAttributeDeclaration
*udad
= s
->userAttribDecl
;
914 Expressions
*exps
= udad
? udad
->getAttributes() : new Expressions();
915 TupleExp
*tup
= new TupleExp(e
->loc
, exps
);
916 return semantic(tup
, sc
);
918 else if (e
->ident
== Id::getFunctionAttributes
)
920 /// extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
922 return dimError(e
, 1, dim
);
924 RootObject
*o
= (*e
->args
)[0];
925 Dsymbol
*s
= getDsymbol(o
);
927 TypeFunction
*tf
= NULL
;
930 if (FuncDeclaration
*f
= s
->isFuncDeclaration())
932 else if (VarDeclaration
*v
= s
->isVarDeclaration())
937 if (t
->ty
== Tfunction
)
938 tf
= (TypeFunction
*)t
;
939 else if (t
->ty
== Tdelegate
)
940 tf
= (TypeFunction
*)t
->nextOf();
941 else if (t
->ty
== Tpointer
&& t
->nextOf()->ty
== Tfunction
)
942 tf
= (TypeFunction
*)t
->nextOf();
946 e
->error("first argument is not a function");
947 return new ErrorExp();
950 Expressions
*mods
= new Expressions();
953 tf
->modifiersApply(&pa
, &PushAttributes::fp
);
954 tf
->attributesApply(&pa
, &PushAttributes::fp
, TRUSTformatSystem
);
956 TupleExp
*tup
= new TupleExp(e
->loc
, mods
);
957 return semantic(tup
, sc
);
959 else if (e
->ident
== Id::getFunctionVariadicStyle
)
961 /* Accept a symbol or a type. Returns one of the following:
962 * "none" not a variadic function
963 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
964 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
965 * "typesafe" void typesafe(T[] ...)
967 // get symbol linkage as a string
969 return dimError(e
, 1, dim
);
973 RootObject
*o
= (*e
->args
)[0];
975 TypeFunction
*tf
= NULL
;
978 if (t
->ty
== Tfunction
)
979 tf
= (TypeFunction
*)t
;
980 else if (t
->ty
== Tdelegate
)
981 tf
= (TypeFunction
*)t
->nextOf();
982 else if (t
->ty
== Tpointer
&& t
->nextOf()->ty
== Tfunction
)
983 tf
= (TypeFunction
*)t
->nextOf();
988 varargs
= tf
->varargs
;
992 Dsymbol
*s
= getDsymbol(o
);
993 FuncDeclaration
*fd
= NULL
;
994 if (!s
|| (fd
= s
->isFuncDeclaration()) == NULL
)
996 e
->error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o
->toChars());
997 return new ErrorExp();
1000 fd
->getParameters(&varargs
);
1005 case 0: style
= "none"; break;
1006 case 1: style
= (link
== LINKd
) ? "argptr"
1008 case 2: style
= "typesafe"; break;
1012 StringExp
*se
= new StringExp(e
->loc
, const_cast<char*>(style
));
1013 return semantic(se
, sc
);
1015 else if (e
->ident
== Id::getParameterStorageClasses
)
1017 /* Accept a function symbol or a type, followed by a parameter index.
1018 * Returns a tuple of strings of the parameter's storage classes.
1020 // get symbol linkage as a string
1022 return dimError(e
, 2, dim
);
1024 RootObject
*o1
= (*e
->args
)[1];
1025 RootObject
*o
= (*e
->args
)[0];
1026 Type
*t
= isType(o
);
1027 TypeFunction
*tf
= NULL
;
1030 if (t
->ty
== Tfunction
)
1031 tf
= (TypeFunction
*)t
;
1032 else if (t
->ty
== Tdelegate
)
1033 tf
= (TypeFunction
*)t
->nextOf();
1034 else if (t
->ty
== Tpointer
&& t
->nextOf()->ty
== Tfunction
)
1035 tf
= (TypeFunction
*)t
->nextOf();
1037 Parameters
* fparams
;
1040 fparams
= tf
->parameters
;
1044 Dsymbol
*s
= getDsymbol(o
);
1045 FuncDeclaration
*fd
= NULL
;
1046 if (!s
|| (fd
= s
->isFuncDeclaration()) == NULL
)
1048 e
->error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
1049 o
->toChars(), o1
->toChars());
1050 return new ErrorExp();
1052 fparams
= fd
->getParameters(NULL
);
1057 // Set stc to storage class of the ith parameter
1058 Expression
*ex
= isExpression((*e
->args
)[1]);
1061 e
->error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1062 o
->toChars(), o1
->toChars());
1063 return new ErrorExp();
1065 ex
= ex
->ctfeInterpret();
1066 uinteger_t ii
= ex
->toUInteger();
1067 if (ii
>= Parameter::dim(fparams
))
1069 e
->error("parameter index must be in range 0..%u not %s", (unsigned)Parameter::dim(fparams
), ex
->toChars());
1070 return new ErrorExp();
1073 unsigned n
= (unsigned)ii
;
1074 Parameter
*p
= Parameter::getNth(fparams
, n
);
1075 stc
= p
->storageClass
;
1077 // This mirrors hdrgen.visit(Parameter p)
1078 if (p
->type
&& p
->type
->mod
& MODshared
)
1081 Expressions
*exps
= new Expressions
;
1084 exps
->push(new StringExp(e
->loc
, const_cast<char *>("auto")));
1085 if (stc
& STCreturn
)
1086 exps
->push(new StringExp(e
->loc
, const_cast<char *>("return")));
1089 exps
->push(new StringExp(e
->loc
, const_cast<char *>("out")));
1090 else if (stc
& STCref
)
1091 exps
->push(new StringExp(e
->loc
, const_cast<char *>("ref")));
1092 else if (stc
& STCin
)
1093 exps
->push(new StringExp(e
->loc
, const_cast<char *>("in")));
1094 else if (stc
& STClazy
)
1095 exps
->push(new StringExp(e
->loc
, const_cast<char *>("lazy")));
1096 else if (stc
& STCalias
)
1097 exps
->push(new StringExp(e
->loc
, const_cast<char *>("alias")));
1100 exps
->push(new StringExp(e
->loc
, const_cast<char *>("const")));
1101 if (stc
& STCimmutable
)
1102 exps
->push(new StringExp(e
->loc
, const_cast<char *>("immutable")));
1104 exps
->push(new StringExp(e
->loc
, const_cast<char *>("inout")));
1105 if (stc
& STCshared
)
1106 exps
->push(new StringExp(e
->loc
, const_cast<char *>("shared")));
1107 if (stc
& STCscope
&& !(stc
& STCscopeinferred
))
1108 exps
->push(new StringExp(e
->loc
, const_cast<char *>("scope")));
1110 TupleExp
*tup
= new TupleExp(e
->loc
, exps
);
1111 return semantic(tup
, sc
);
1113 else if (e
->ident
== Id::getLinkage
)
1115 // get symbol linkage as a string
1117 return dimError(e
, 1, dim
);
1120 RootObject
*o
= (*e
->args
)[0];
1121 Type
*t
= isType(o
);
1122 TypeFunction
*tf
= NULL
;
1125 if (t
->ty
== Tfunction
)
1126 tf
= (TypeFunction
*)t
;
1127 else if (t
->ty
== Tdelegate
)
1128 tf
= (TypeFunction
*)t
->nextOf();
1129 else if (t
->ty
== Tpointer
&& t
->nextOf()->ty
== Tfunction
)
1130 tf
= (TypeFunction
*)t
->nextOf();
1136 Dsymbol
*s
= getDsymbol(o
);
1137 Declaration
*d
= NULL
;
1138 AggregateDeclaration
*ad
= NULL
;
1139 if (!s
|| ((d
= s
->isDeclaration()) == NULL
1140 && (ad
= s
->isAggregateDeclaration()) == NULL
))
1142 e
->error("argument to `__traits(getLinkage, %s)` is not a declaration", o
->toChars());
1143 return new ErrorExp();
1149 switch (ad
->classKind
)
1154 case ClassKind::cpp
:
1157 case ClassKind::objc
:
1165 const char *linkage
= linkageToChars(link
);
1166 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(linkage
));
1167 return semantic(se
, sc
);
1169 else if (e
->ident
== Id::allMembers
||
1170 e
->ident
== Id::derivedMembers
)
1173 return dimError(e
, 1, dim
);
1175 RootObject
*o
= (*e
->args
)[0];
1176 Dsymbol
*s
= getDsymbol(o
);
1179 e
->error("argument has no members");
1180 return new ErrorExp();
1182 if (Import
*imp
= s
->isImport())
1188 ScopeDsymbol
*sds
= s
->isScopeDsymbol();
1189 if (!sds
|| sds
->isTemplateDeclaration())
1191 e
->error("%s %s has no members", s
->kind(), s
->toChars());
1192 return new ErrorExp();
1195 // use a struct as local function
1199 Identifiers
*idents
;
1201 static int dg(void *ctx
, size_t, Dsymbol
*sm
)
1206 // skip local symbols, such as static foreach loop variables
1207 if (Declaration
*decl
= sm
->isDeclaration())
1209 if (decl
->storage_class
& STClocal
)
1215 //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
1218 // https://issues.dlang.org/show_bug.cgi?id=10096
1219 // https://issues.dlang.org/show_bug.cgi?id=10100
1220 // Skip over internal members in __traits(allMembers)
1221 if ((sm
->isCtorDeclaration() && sm
->ident
!= Id::ctor
) ||
1222 (sm
->isDtorDeclaration() && sm
->ident
!= Id::dtor
) ||
1223 (sm
->isPostBlitDeclaration() && sm
->ident
!= Id::postblit
) ||
1224 sm
->isInvariantDeclaration() ||
1225 sm
->isUnitTestDeclaration())
1230 if (sm
->ident
== Id::empty
)
1234 if (sm
->isTypeInfoDeclaration()) // Bugzilla 15177
1236 PushIdentsDg
*pid
= (PushIdentsDg
*)ctx
;
1237 if (!pid
->sds
->isModule() && sm
->isImport()) // Bugzilla 17057
1240 //printf("\t%s\n", sm->ident->toChars());
1241 Identifiers
*idents
= pid
->idents
;
1243 /* Skip if already present in idents[]
1245 for (size_t j
= 0; j
< idents
->dim
; j
++)
1247 Identifier
*id
= (*idents
)[j
];
1248 if (id
== sm
->ident
)
1252 idents
->push(sm
->ident
);
1256 EnumDeclaration
*ed
= sm
->isEnumDeclaration();
1259 ScopeDsymbol_foreach(NULL
, ed
->members
, &PushIdentsDg::dg
, ctx
);
1266 Identifiers
*idents
= new Identifiers
;
1269 ctx
.idents
= idents
;
1270 ScopeDsymbol_foreach(sc
, sds
->members
, &PushIdentsDg::dg
, &ctx
);
1271 ClassDeclaration
*cd
= sds
->isClassDeclaration();
1272 if (cd
&& e
->ident
== Id::allMembers
)
1274 if (cd
->semanticRun
< PASSsemanticdone
)
1275 cd
->semantic(NULL
); // Bugzilla 13668: Try to resolve forward reference
1277 struct PushBaseMembers
1279 static void dg(ClassDeclaration
*cd
, PushIdentsDg
*ctx
)
1281 for (size_t i
= 0; i
< cd
->baseclasses
->dim
; i
++)
1283 ClassDeclaration
*cb
= (*cd
->baseclasses
)[i
]->sym
;
1285 ScopeDsymbol_foreach(NULL
, cb
->members
, &PushIdentsDg::dg
, ctx
);
1286 if (cb
->baseclasses
->dim
)
1291 PushBaseMembers::dg(cd
, &ctx
);
1294 // Turn Identifiers into StringExps reusing the allocated array
1295 assert(sizeof(Expressions
) == sizeof(Identifiers
));
1296 Expressions
*exps
= (Expressions
*)idents
;
1297 for (size_t i
= 0; i
< idents
->dim
; i
++)
1299 Identifier
*id
= (*idents
)[i
];
1300 StringExp
*se
= new StringExp(e
->loc
, const_cast<char *>(id
->toChars()));
1304 /* Making this a tuple is more flexible, as it can be statically unrolled.
1305 * To make an array literal, enclose __traits in [ ]:
1306 * [ __traits(allMembers, ...) ]
1308 Expression
*ex
= new TupleExp(e
->loc
, exps
);
1309 ex
= semantic(ex
, sc
);
1312 else if (e
->ident
== Id::compiles
)
1314 /* Determine if all the objects - types, expressions, or symbols -
1315 * compile without error
1320 for (size_t i
= 0; i
< dim
; i
++)
1322 unsigned errors
= global
.startGagging();
1323 Scope
*sc2
= sc
->push();
1326 sc2
->flags
= (sc
->flags
& ~(SCOPEctfe
| SCOPEcondition
)) | SCOPEcompile
| SCOPEfullinst
;
1329 RootObject
*o
= (*e
->args
)[i
];
1330 Type
*t
= isType(o
);
1331 Expression
*ex
= t
? typeToExpression(t
) : isExpression(o
);
1335 t
->resolve(e
->loc
, sc2
, &ex
, &t
, &s
);
1338 t
->semantic(e
->loc
, sc2
);
1339 if (t
->ty
== Terror
)
1342 else if (s
&& s
->errors
)
1347 ex
= semantic(ex
, sc2
);
1348 ex
= resolvePropertiesOnly(sc2
, ex
);
1349 ex
= ex
->optimize(WANTvalue
);
1350 if (sc2
->func
&& sc2
->func
->type
->ty
== Tfunction
)
1352 TypeFunction
*tf
= (TypeFunction
*)sc2
->func
->type
;
1353 canThrow(ex
, sc2
->func
, tf
->isnothrow
);
1355 ex
= checkGC(sc2
, ex
);
1356 if (ex
->op
== TOKerror
)
1360 // Carefully detach the scope from the parent and throw it away as
1361 // we only need it to evaluate the expression
1362 // https://issues.dlang.org/show_bug.cgi?id=15428
1364 sc2
->enclosing
= NULL
;
1367 if (global
.endGagging(errors
) || err
)
1374 else if (e
->ident
== Id::isSame
)
1376 /* Determine if two symbols are the same
1379 return dimError(e
, 2, dim
);
1381 if (!TemplateInstance::semanticTiargs(e
->loc
, sc
, e
->args
, 0))
1382 return new ErrorExp();
1384 RootObject
*o1
= (*e
->args
)[0];
1385 RootObject
*o2
= (*e
->args
)[1];
1387 // issue 12001, allow isSame, <BasicType>, <BasicType>
1388 Type
*t1
= isType(o1
);
1389 Type
*t2
= isType(o2
);
1390 if (t1
&& t2
&& t1
->equals(t2
))
1393 Dsymbol
*s1
= getDsymbol(o1
);
1394 Dsymbol
*s2
= getDsymbol(o2
);
1395 //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars());
1398 Expression
*ea1
= isExpression(o1
);
1399 Expression
*ea2
= isExpression(o2
);
1402 if (ea1
->equals(ea2
))
1411 if (s1
->isFuncAliasDeclaration())
1412 s1
= ((FuncAliasDeclaration
*)s1
)->toAliasFunc();
1413 if (s2
->isFuncAliasDeclaration())
1414 s2
= ((FuncAliasDeclaration
*)s2
)->toAliasFunc();
1416 return (s1
== s2
) ? True(e
) : False(e
);
1418 else if (e
->ident
== Id::getUnitTests
)
1421 return dimError(e
, 1, dim
);
1423 RootObject
*o
= (*e
->args
)[0];
1424 Dsymbol
*s
= getDsymbol(o
);
1427 e
->error("argument %s to __traits(getUnitTests) must be a module or aggregate",
1429 return new ErrorExp();
1431 if (Import
*imp
= s
->isImport()) // Bugzilla 10990
1434 ScopeDsymbol
* sds
= s
->isScopeDsymbol();
1437 e
->error("argument %s to __traits(getUnitTests) must be a module or aggregate, not a %s",
1438 s
->toChars(), s
->kind());
1439 return new ErrorExp();
1442 Expressions
*exps
= new Expressions();
1443 if (global
.params
.useUnitTests
)
1445 // Should actually be a set
1446 AA
* uniqueUnitTests
= NULL
;
1447 collectUnitTests(sds
->members
, uniqueUnitTests
, exps
);
1449 TupleExp
*te
= new TupleExp(e
->loc
, exps
);
1450 return semantic(te
, sc
);
1452 else if (e
->ident
== Id::getVirtualIndex
)
1455 return dimError(e
, 1, dim
);
1457 RootObject
*o
= (*e
->args
)[0];
1458 Dsymbol
*s
= getDsymbol(o
);
1460 FuncDeclaration
*fd
= s
? s
->isFuncDeclaration() : NULL
;
1463 e
->error("first argument to __traits(getVirtualIndex) must be a function");
1464 return new ErrorExp();
1467 fd
= fd
->toAliasFunc(); // Neccessary to support multiple overloads.
1468 return new IntegerExp(e
->loc
, fd
->vtblIndex
, Type::tptrdiff_t
);
1470 else if (e
->ident
== Id::getPointerBitmap
)
1472 return pointerBitmap(e
);
1475 if (const char *sub
= (const char *)speller(e
->ident
->toChars(), &trait_search_fp
, NULL
, idchars
))
1476 e
->error("unrecognized trait '%s', did you mean '%s'?", e
->ident
->toChars(), sub
);
1478 e
->error("unrecognized trait '%s'", e
->ident
->toChars());
1479 return new ErrorExp();
1481 e
->error("wrong number of arguments %d", (int)dim
);
1482 return new ErrorExp();