2 * Handle introspection functionality of the `__traits()` construct.
4 * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits)
6 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/traits.d, _traits.d)
10 * Documentation: https://dlang.org/phobos/dmd_traits.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/traits.d
16 import core
.stdc
.stdio
;
19 import dmd
.arraytypes
;
20 import dmd
.astcodegen
;
25 import dmd
.declaration
;
31 import dmd
.dsymbolsem
;
34 import dmd
.expression
;
35 import dmd
.expressionsem
;
40 import dmd
.identifier
;
44 import dmd
.root
.array
;
45 import dmd
.root
.speller
;
46 import dmd
.root
.stringtable
;
51 import dmd
.root
.rootobject
;
52 import dmd
.common
.outbuffer
;
53 import dmd
.root
.string
;
55 enum LOGSEMANTIC
= false;
57 /************************ TraitsExp ************************************/
59 /**************************************
60 * Convert `Expression` or `Type` to corresponding `Dsymbol`, additionally
61 * stripping off expression contexts.
63 * Some symbol related `__traits` ignore arguments expression contexts.
66 * struct S { void f() {} }
68 * pragma(msg, __traits(isNested, s.f));
69 * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`.
72 * This is used for that common `__traits` behavior.
75 * oarg object to get the symbol for
77 * Dsymbol the corresponding symbol for oarg
79 private Dsymbol
getDsymbolWithoutExpCtx(RootObject oarg
)
81 if (auto e
= isExpression(oarg
))
83 if (auto dve
= e
.isDotVarExp())
85 if (auto dte
= e
.isDotTemplateExp())
88 return getDsymbol(oarg
);
91 private const StringTable
!bool traitsStringTable
;
95 static immutable string
[] names
=
113 "isAbstractFunction",
115 "isOverrideFunction",
132 "getVirtualFunctions",
141 "getFunctionAttributes",
142 "getFunctionVariadicStyle",
143 "getParameterStorageClasses",
151 "hasCopyConstructor",
156 StringTable
!(bool)* stringTable
= cast(StringTable
!(bool)*) &traitsStringTable
;
157 stringTable
._init(names
.length
);
161 auto sv
= stringTable
.insert(s
, true);
167 * get an array of size_t values that indicate possible pointer words in memory
168 * if interpreted as the type given as argument
169 * Returns: the size of the type in bytes, ulong.max on error
171 ulong getTypePointerBitmap(Loc loc
, Type t
, Array
!(ulong)* data
)
174 if (t
.ty
== Tclass
&& !(cast(TypeClass
)t
).sym
.isInterfaceDeclaration())
175 sz
= (cast(TypeClass
)t
).sym
.AggregateDeclaration
.size(loc
);
178 if (sz
== SIZE_INVALID
)
181 const sz_size_t
= Type
.tsize_t
.size(loc
);
182 if (sz
> sz
.max
- sz_size_t
)
184 error(loc
, "size overflow for type `%s`", t
.toChars());
188 ulong bitsPerWord
= sz_size_t
* 8;
189 ulong cntptr
= (sz
+ sz_size_t
- 1) / sz_size_t
;
190 ulong cntdata
= (cntptr
+ bitsPerWord
- 1) / bitsPerWord
;
192 data
.setDim(cast(size_t
)cntdata
);
195 extern (C
++) final class PointerBitmapVisitor
: Visitor
197 alias visit
= Visitor
.visit
;
199 extern (D
) this(Array
!(ulong)* _data
, ulong _sz_size_t
)
202 this.sz_size_t
= _sz_size_t
;
205 void setpointer(ulong off
)
207 ulong ptroff
= off
/ sz_size_t
;
208 (*data
)[cast(size_t
)(ptroff
/ (8 * sz_size_t
))] |
= 1L << (ptroff
% (8 * sz_size_t
));
211 override void visit(Type t
)
213 Type tb
= t
.toBasetype();
218 override void visit(TypeError t
)
223 override void visit(TypeNext t
)
228 override void visit(TypeBasic t
)
234 override void visit(TypeVector t
)
238 override void visit(TypeArray t
)
243 override void visit(TypeSArray t
)
245 ulong arrayoff
= offset
;
246 ulong nextsize
= t
.next
.size();
247 if (nextsize
== SIZE_INVALID
)
249 ulong dim
= t
.dim
.toInteger();
250 for (ulong i
= 0; i
< dim
; i
++)
252 offset
= arrayoff
+ i
* nextsize
;
258 override void visit(TypeDArray t
)
260 setpointer(offset
+ sz_size_t
);
263 // dynamic array is {length,ptr}
264 override void visit(TypeAArray t
)
269 override void visit(TypePointer t
)
271 if (t
.nextOf().ty
!= Tfunction
) // don't mark function pointers
275 override void visit(TypeReference t
)
280 override void visit(TypeClass t
)
285 override void visit(TypeFunction t
)
289 override void visit(TypeDelegate t
)
294 // delegate is {context, function}
295 override void visit(TypeQualified t
)
301 override void visit(TypeIdentifier t
)
306 override void visit(TypeInstance t
)
311 override void visit(TypeTypeof t
)
316 override void visit(TypeReturn t
)
321 override void visit(TypeEnum t
)
326 override void visit(TypeTuple t
)
331 override void visit(TypeSlice t
)
336 override void visit(TypeNull t
)
338 // always a null pointer
341 override void visit(TypeStruct t
)
343 ulong structoff
= offset
;
344 foreach (v
; t
.sym
.fields
)
346 offset
= structoff
+ v
.offset
;
347 if (v
.type
.ty
== Tclass
)
355 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
356 void visitClass(TypeClass t
)
358 ulong classoff
= offset
;
359 // skip vtable-ptr and monitor
361 visitClass(cast(TypeClass
)t
.sym
.baseClass
.type
);
362 foreach (v
; t
.sym
.fields
)
364 offset
= classoff
+ v
.offset
;
376 scope PointerBitmapVisitor pbv
= new PointerBitmapVisitor(data
, sz_size_t
);
378 pbv
.visitClass(cast(TypeClass
)t
);
381 return pbv
.error ?
ulong.max
: sz
;
385 * get an array of size_t values that indicate possible pointer words in memory
386 * if interpreted as the type given as argument
387 * the first array element is the size of the type for independent interpretation
389 * following elements bits represent one word (4/8 bytes depending on the target
390 * architecture). If set the corresponding memory might contain a pointer/reference.
392 * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
394 private Expression
pointerBitmap(TraitsExp e
)
396 if (!e
.args || e
.args
.dim
!= 1)
398 error(e
.loc
, "a single type expected for trait pointerBitmap");
399 return ErrorExp
.get();
402 Type t
= getType((*e
.args
)[0]);
405 error(e
.loc
, "`%s` is not a type", (*e
.args
)[0].toChars());
406 return ErrorExp
.get();
410 ulong sz
= getTypePointerBitmap(e
.loc
, t
, &data
);
412 return ErrorExp
.get();
414 auto exps
= new Expressions(data
.dim
+ 1);
415 (*exps
)[0] = new IntegerExp(e
.loc
, sz
, Type
.tsize_t
);
416 foreach (size_t i
; 1 .. exps
.dim
)
417 (*exps
)[i
] = new IntegerExp(e
.loc
, data
[cast(size_t
) (i
- 1)], Type
.tsize_t
);
419 auto ale
= new ArrayLiteralExp(e
.loc
, Type
.tsize_t
.sarrayOf(data
.dim
+ 1), exps
);
423 Expression
semanticTraits(TraitsExp e
, Scope
* sc
)
425 static if (LOGSEMANTIC
)
427 printf("TraitsExp::semantic() %s\n", e
.toChars());
430 if (e
.ident
!= Id
.compiles
&&
431 e
.ident
!= Id
.isSame
&&
432 e
.ident
!= Id
.identifier
&&
433 e
.ident
!= Id
.getProtection
&& e
.ident
!= Id
.getVisibility
&&
434 e
.ident
!= Id
.getAttributes
)
436 // Pretend we're in a deprecated scope so that deprecation messages
437 // aren't triggered when checking if a symbol is deprecated
439 if (e
.ident
== Id
.isDeprecated
)
440 sc
.stc |
= STC
.deprecated_
;
441 if (!TemplateInstance
.semanticTiargs(e
.loc
, sc
, e
.args
, 1))
444 return ErrorExp
.get();
448 size_t dim
= e
.args ? e
.args
.dim
: 0;
450 Expression
dimError(int expected
)
452 e
.error("expected %d arguments for `%s` but had %d", expected
, e
.ident
.toChars(), cast(int)dim
);
453 return ErrorExp
.get();
456 static IntegerExp
True()
458 return IntegerExp
.createBool(true);
461 static IntegerExp
False()
463 return IntegerExp
.createBool(false);
467 * Gets the function type from a given AST node
468 * if the node is a function of some sort.
470 * o = an AST node to check for a `TypeFunction`
471 * fdp = if `o` is a FuncDeclaration then fdp is set to that, otherwise `null`
473 * a type node if `o` is a declaration of
474 * a delegate, function, function-pointer or a variable of the former.
477 static TypeFunction
toTypeFunction(RootObject o
, out FuncDeclaration fdp
)
480 if (auto s
= getDsymbolWithoutExpCtx(o
))
482 if (auto fd
= s
.isFuncDeclaration())
487 else if (auto vd
= s
.isVarDeclaration())
497 if (auto tf
= t
.isFunction_Delegate_PtrToFunction())
504 IntegerExp
isX(T
)(bool delegate(T
) fp
)
510 static if (is(T
== Type
))
513 static if (is(T
: Dsymbol
))
515 auto s
= getDsymbolWithoutExpCtx(o
);
519 static if (is(T
== Dsymbol
))
521 static if (is(T
== Declaration
))
522 auto y
= s
.isDeclaration();
523 static if (is(T
== FuncDeclaration
))
524 auto y
= s
.isFuncDeclaration();
532 alias isTypeX
= isX
!Type
;
533 alias isDsymX
= isX
!Dsymbol
;
534 alias isDeclX
= isX
!Declaration
;
535 alias isFuncX
= isX
!FuncDeclaration
;
537 Expression
isPkgX(bool function(Package
) fp
)
539 return isDsymX((Dsymbol sym
) {
540 Package p
= resolveIsPackage(sym
);
541 return (p
!is null) && fp(p
);
545 if (e
.ident
== Id
.isArithmetic
)
547 return isTypeX(t
=> t
.isintegral() || t
.isfloating());
549 if (e
.ident
== Id
.isFloating
)
551 return isTypeX(t
=> t
.isfloating());
553 if (e
.ident
== Id
.isIntegral
)
555 return isTypeX(t
=> t
.isintegral());
557 if (e
.ident
== Id
.isScalar
)
559 return isTypeX(t
=> t
.isscalar());
561 if (e
.ident
== Id
.isUnsigned
)
563 return isTypeX(t
=> t
.isunsigned());
565 if (e
.ident
== Id
.isAssociativeArray
)
567 return isTypeX(t
=> t
.toBasetype().ty
== Taarray
);
569 if (e
.ident
== Id
.isDeprecated
)
571 if (isTypeX(t
=> t
.iscomplex() || t
.isimaginary()).toBool().hasValue(true))
573 return isDsymX(t
=> t
.isDeprecated());
575 if (e
.ident
== Id
.isFuture
)
577 return isDeclX(t
=> t
.isFuture());
579 if (e
.ident
== Id
.isStaticArray
)
581 return isTypeX(t
=> t
.toBasetype().ty
== Tsarray
);
583 if (e
.ident
== Id
.isAbstractClass
)
585 return isTypeX(t
=> t
.toBasetype().ty
== Tclass
&&
586 (cast(TypeClass
)t
.toBasetype()).sym
.isAbstract());
588 if (e
.ident
== Id
.isFinalClass
)
590 return isTypeX(t
=> t
.toBasetype().ty
== Tclass
&&
591 ((cast(TypeClass
)t
.toBasetype()).sym
.storage_class
& STC
.final_
) != 0);
593 if (e
.ident
== Id
.isTemplate
)
600 if (!s
.toAlias().isOverloadable())
602 return overloadApply(s
,
603 sm
=> sm
.isTemplateDeclaration() !is null) != 0;
606 if (e
.ident
== Id
.isPOD
)
611 auto o
= (*e
.args
)[0];
615 e
.error("type expected as second argument of __traits `%s` instead of `%s`",
616 e
.ident
.toChars(), o
.toChars());
617 return ErrorExp
.get();
620 Type tb
= t
.baseElemOf();
621 if (auto sd
= tb
.ty
== Tstruct ?
(cast(TypeStruct
)tb
).sym
: null)
623 return sd
.isPOD() ?
True() : False();
627 if (e
.ident
== Id
.hasCopyConstructor || e
.ident
== Id
.hasPostblit
)
632 auto o
= (*e
.args
)[0];
636 e
.error("type expected as second argument of __traits `%s` instead of `%s`",
637 e
.ident
.toChars(), o
.toChars());
638 return ErrorExp
.get();
641 Type tb
= t
.baseElemOf();
642 if (auto sd
= tb
.ty
== Tstruct ?
(cast(TypeStruct
)tb
).sym
: null)
644 return (e
.ident
== Id
.hasPostblit
) ?
(sd
.postblit ?
True() : False())
645 : (sd
.hasCopyCtor ?
True() : False());
649 if (e
.ident
== Id
.isCopyable
)
654 auto o
= (*e
.args
)[0];
658 e
.error("type expected as second argument of __traits `%s` instead of `%s`",
659 e
.ident
.toChars(), o
.toChars());
660 return ErrorExp
.get();
663 t
= t
.toBasetype(); // get the base in case `t` is an `enum`
665 if (auto ts
= t
.isTypeStruct())
667 ts
.sym
.dsymbolSemantic(sc
);
670 return isCopyable(t
) ?
True() : False();
673 if (e
.ident
== Id
.isNested
)
678 auto o
= (*e
.args
)[0];
679 auto s
= getDsymbolWithoutExpCtx(o
);
683 else if (auto ad
= s
.isAggregateDeclaration())
685 return ad
.isNested() ?
True() : False();
687 else if (auto fd
= s
.isFuncDeclaration())
689 return fd
.isNested() ?
True() : False();
692 e
.error("aggregate or function expected instead of `%s`", o
.toChars());
693 return ErrorExp
.get();
695 if (e
.ident
== Id
.isDisabled
)
700 return isDeclX(f
=> f
.isDisabled());
702 if (e
.ident
== Id
.isAbstractFunction
)
707 return isFuncX(f
=> f
.isAbstract());
709 if (e
.ident
== Id
.isVirtualFunction
)
714 return isFuncX(f
=> f
.isVirtual());
716 if (e
.ident
== Id
.isVirtualMethod
)
721 return isFuncX(f
=> f
.isVirtualMethod());
723 if (e
.ident
== Id
.isFinalFunction
)
728 return isFuncX(f
=> f
.isFinalFunc());
730 if (e
.ident
== Id
.isOverrideFunction
)
735 return isFuncX(f
=> f
.isOverride());
737 if (e
.ident
== Id
.isStaticFunction
)
742 return isFuncX(f
=> !f
.needThis() && !f
.isNested());
744 if (e
.ident
== Id
.isModule
)
749 return isPkgX(p
=> p
.isModule() || p
.isPackageMod());
751 if (e
.ident
== Id
.isPackage
)
756 return isPkgX(p
=> p
.isModule() is null);
758 if (e
.ident
== Id
.isRef
)
763 return isDeclX(d
=> d
.isRef());
765 if (e
.ident
== Id
.isOut
)
770 return isDeclX(d
=> d
.isOut());
772 if (e
.ident
== Id
.isLazy
)
777 return isDeclX(d
=> (d
.storage_class
& STC
.lazy_
) != 0);
779 if (e
.ident
== Id
.identifier
)
781 // Get identifier for symbol as a string literal
782 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
783 * a symbol should not be folded to a constant.
784 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
786 if (!TemplateInstance
.semanticTiargs(e
.loc
, sc
, e
.args
, 2))
787 return ErrorExp
.get();
791 auto o
= (*e
.args
)[0];
793 if (auto po
= isParameter(o
))
797 e
.error("argument `%s` has no identifier", po
.type
.toChars());
798 return ErrorExp
.get();
804 Dsymbol s
= getDsymbolWithoutExpCtx(o
);
807 e
.error("argument `%s` has no identifier", o
.toChars());
808 return ErrorExp
.get();
813 auto se
= new StringExp(e
.loc
, id
.toString());
814 return se
.expressionSemantic(sc
);
816 if (e
.ident
== Id
.getProtection || e
.ident
== Id
.getVisibility
)
821 Scope
* sc2
= sc
.push();
822 sc2
.flags
= sc
.flags | SCOPE
.noaccesscheck | SCOPE
.ignoresymbolvisibility
;
823 bool ok
= TemplateInstance
.semanticTiargs(e
.loc
, sc2
, e
.args
, 1);
826 return ErrorExp
.get();
828 auto o
= (*e
.args
)[0];
829 auto s
= getDsymbolWithoutExpCtx(o
);
833 e
.error("argument `%s` has no visibility", o
.toChars());
834 return ErrorExp
.get();
836 if (s
.semanticRun
== PASS
.initial
)
837 s
.dsymbolSemantic(null);
839 auto protName
= visibilityToString(s
.visible().kind
); // TODO: How about package(names)
841 auto se
= new StringExp(e
.loc
, protName
);
842 return se
.expressionSemantic(sc
);
844 if (e
.ident
== Id
.parent
)
849 auto o
= (*e
.args
)[0];
850 auto s
= getDsymbolWithoutExpCtx(o
);
853 // https://issues.dlang.org/show_bug.cgi?id=12496
857 // class C(uint value) { }
859 // __traits(parent, T1.C!2)
860 if (auto ad
= s
.isAggregateDeclaration()) // `s` is `C`
862 if (ad
.isNested()) // `C` is nested
864 if (auto p
= s
.toParent()) // `C`'s parent is `C!2`, believe it or not
866 if (p
.isTemplateInstance()) // `C!2` is a template instance
868 s
= p
; // `C!2`'s parent is `T1`
869 auto td
= (cast(TemplateInstance
)p
).tempdecl
;
871 s
= td
; // get the declaration context just in case there's two contexts
877 if (auto fd
= s
.isFuncDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=8943
878 s
= fd
.toAliasFunc();
879 if (!s
.isImport()) // https://issues.dlang.org/show_bug.cgi?id=8922
882 if (!s || s
.isImport())
884 e
.error("argument `%s` has no parent", o
.toChars());
885 return ErrorExp
.get();
888 if (auto f
= s
.isFuncDeclaration())
890 if (auto td
= getFuncTemplateDecl(f
))
892 if (td
.overroot
) // if not start of overloaded list of TemplateDeclaration's
893 td
= td
.overroot
; // then get the start
894 Expression ex
= new TemplateExp(e
.loc
, td
, f
);
895 ex
= ex
.expressionSemantic(sc
);
898 if (auto fld = f
.isFuncLiteralDeclaration())
900 // Directly translate to VarExp instead of FuncExp
901 Expression ex
= new VarExp(e
.loc
, fld, true);
902 return ex
.expressionSemantic(sc
);
905 return symbolToExp(s
, e
.loc
, sc
, false);
907 if (e
.ident
== Id
.child
)
913 auto op
= (*e
.args
)[0];
914 if (auto symp
= getDsymbol(op
))
915 ex
= new DsymbolExp(e
.loc
, symp
);
916 else if (auto exp
= op
.isExpression())
920 e
.error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op
.toChars());
921 return ErrorExp
.get();
924 ex
= ex
.expressionSemantic(sc
);
925 auto oc
= (*e
.args
)[1];
926 auto symc
= getDsymbol(oc
);
929 e
.error("symbol expected as second argument of __traits `child` instead of `%s`", oc
.toChars());
930 return ErrorExp
.get();
933 if (auto d
= symc
.isDeclaration())
934 ex
= new DotVarExp(e
.loc
, ex
, d
);
935 else if (auto td
= symc
.isTemplateDeclaration())
936 ex
= new DotExp(e
.loc
, ex
, new TemplateExp(e
.loc
, td
));
937 else if (auto ti
= symc
.isScopeDsymbol())
938 ex
= new DotExp(e
.loc
, ex
, new ScopeExp(e
.loc
, ti
));
942 ex
= ex
.expressionSemantic(sc
);
945 if (e
.ident
== Id
.toType
)
950 auto ex
= isExpression((*e
.args
)[0]);
953 e
.error("expression expected as second argument of __traits `%s`", e
.ident
.toChars());
954 return ErrorExp
.get();
956 ex
= ex
.ctfeInterpret();
958 StringExp se
= semanticString(sc
, ex
, "__traits(toType, string)");
961 return ErrorExp
.get();
963 Type t
= decoToType(se
.toUTF8(sc
).peekString());
966 e
.error("cannot determine `%s`", e
.toChars());
967 return ErrorExp
.get();
969 return (new TypeExp(e
.loc
, t
)).expressionSemantic(sc
);
971 if (e
.ident
== Id
.hasMember ||
972 e
.ident
== Id
.getMember ||
973 e
.ident
== Id
.getOverloads ||
974 e
.ident
== Id
.getVirtualMethods ||
975 e
.ident
== Id
.getVirtualFunctions
)
977 if (dim
!= 2 && !(dim
== 3 && e
.ident
== Id
.getOverloads
))
980 auto o
= (*e
.args
)[0];
981 auto ex
= isExpression((*e
.args
)[1]);
984 e
.error("expression expected as second argument of __traits `%s`", e
.ident
.toChars());
985 return ErrorExp
.get();
987 ex
= ex
.ctfeInterpret();
989 bool includeTemplates
= false;
990 if (dim
== 3 && e
.ident
== Id
.getOverloads
)
992 auto b
= isExpression((*e
.args
)[2]);
993 b
= b
.ctfeInterpret();
994 if (!b
.type
.equals(Type
.tbool
))
996 e
.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b
.toChars(), b
.type
.toChars());
997 return ErrorExp
.get();
999 includeTemplates
= b
.toBool().get();
1002 StringExp se
= ex
.toStringExp();
1003 if (!se || se
.len
== 0)
1005 e
.error("string expected as second argument of __traits `%s` instead of `%s`", e
.ident
.toChars(), ex
.toChars());
1006 return ErrorExp
.get();
1012 e
.error("string must be chars");
1013 return ErrorExp
.get();
1015 auto id
= Identifier
.idPool(se
.peekString());
1017 /* Prefer a Type, because getDsymbol(Type) can lose type modifiers.
1018 Then a Dsymbol, because it might need some runtime contexts.
1021 Dsymbol sym
= getDsymbol(o
);
1022 if (auto t
= isType(o
))
1023 ex
= typeDotIdExp(e
.loc
, t
, id
);
1026 if (e
.ident
== Id
.hasMember
)
1028 if (auto sm
= sym
.search(e
.loc
, id
))
1031 ex
= new DsymbolExp(e
.loc
, sym
);
1032 ex
= new DotIdExp(e
.loc
, ex
, id
);
1034 else if (auto ex2
= isExpression(o
))
1035 ex
= new DotIdExp(e
.loc
, ex2
, id
);
1038 e
.error("invalid first argument");
1039 return ErrorExp
.get();
1042 // ignore symbol visibility and disable access checks for these traits
1043 Scope
* scx
= sc
.push();
1044 scx
.flags |
= SCOPE
.ignoresymbolvisibility | SCOPE
.noaccesscheck
;
1045 scope (exit
) scx
.pop();
1047 if (e
.ident
== Id
.hasMember
)
1049 /* Take any errors as meaning it wasn't found
1051 ex
= ex
.trySemantic(scx
);
1052 return ex ?
True() : False();
1054 else if (e
.ident
== Id
.getMember
)
1056 if (auto die
= ex
.isDotIdExp())
1057 // Prevent semantic() from replacing Symbol with its initializer
1059 ex
= ex
.expressionSemantic(scx
);
1062 else if (e
.ident
== Id
.getVirtualFunctions ||
1063 e
.ident
== Id
.getVirtualMethods ||
1064 e
.ident
== Id
.getOverloads
)
1066 uint errors
= global
.errors
;
1067 Expression eorig
= ex
;
1068 ex
= ex
.expressionSemantic(scx
);
1069 if (errors
< global
.errors
)
1070 e
.error("`%s` cannot be resolved", eorig
.toChars());
1072 /* Create tuple of functions of ex
1074 auto exps
= new Expressions();
1076 if (auto ve
= ex
.isVarExp
)
1078 if (ve
.var
.isFuncDeclaration() || ve
.var
.isOverDeclaration())
1082 else if (auto dve
= ex
.isDotVarExp
)
1084 if (dve
.var
.isFuncDeclaration() || dve
.var
.isOverDeclaration())
1086 if (dve
.e1
.op
== EXP
.dotType || dve
.e1
.op
== EXP
.this_
)
1091 else if (auto te
= ex
.isTemplateExp
)
1095 if (td
&& td
.funcroot
)
1099 else if (auto dte
= ex
.isDotTemplateExp
)
1103 if (td
&& td
.funcroot
)
1106 if (dte
.e1
.op
!= EXP
.dotType
&& dte
.e1
.op
!= EXP
.this_
)
1109 bool[string
] funcTypeHash
;
1111 /* Compute the function signature and insert it in the
1112 * hashtable, if not present. This is needed so that
1113 * traits(getOverlods, F3, "visit") does not count `int visit(int)`
1114 * twice in the following example:
1116 * =============================================
1117 * interface F1 { int visit(int);}
1118 * interface F2 { int visit(int); void visit(); }
1119 * interface F3 : F2, F1 {}
1120 *==============================================
1122 void insertInterfaceInheritedFunction(FuncDeclaration fd
, Expression e
)
1124 auto signature
= fd
.type
.toString();
1125 //printf("%s - %s\n", fd.toChars, signature);
1126 if (signature
!in funcTypeHash
)
1128 funcTypeHash
[signature
] = true;
1135 auto fd
= s
.isFuncDeclaration();
1138 if (includeTemplates
)
1140 if (auto td
= s
.isTemplateDeclaration())
1142 // if td is part of an overload set we must take a copy
1143 // which shares the same `instances` cache but without
1144 // `overroot` and `overnext` set to avoid overload
1145 // behaviour in the result.
1146 if (td
.overnext
!is null)
1148 if (td
.instances
is null)
1150 // create an empty AA just to copy it
1151 scope ti
= new TemplateInstance(Loc
.initial
, Id
.empty
, null);
1152 auto tib
= TemplateInstanceBox(ti
);
1153 td
.instances
[tib
] = null;
1154 td
.instances
.clear();
1156 td
= td
.syntaxCopy(null);
1157 import core
.stdc
.string
: memcpy
;
1158 memcpy(cast(void*) td
, cast(void*) s
,
1159 __traits(classInstanceSize
, TemplateDeclaration
));
1164 auto e
= ex ?
new DotTemplateExp(Loc
.initial
, ex
, td
)
1165 : new DsymbolExp(Loc
.initial
, td
);
1171 if (e
.ident
== Id
.getVirtualFunctions
&& !fd
.isVirtual())
1173 if (e
.ident
== Id
.getVirtualMethods
&& !fd
.isVirtualMethod())
1176 auto fa
= new FuncAliasDeclaration(fd
.ident
, fd
, false);
1177 fa
.visibility
= fd
.visibility
;
1179 auto e
= ex ?
new DotVarExp(Loc
.initial
, ex
, fa
, false)
1180 : new DsymbolExp(Loc
.initial
, fa
, false);
1182 // if the parent is an interface declaration
1183 // we must check for functions with the same signature
1184 // in different inherited interfaces
1185 if (sym
&& sym
.isInterfaceDeclaration())
1186 insertInterfaceInheritedFunction(fd
, e
);
1192 InterfaceDeclaration ifd
= null;
1194 ifd
= sym
.isInterfaceDeclaration();
1195 // If the symbol passed as a parameter is an
1196 // interface that inherits other interfaces
1197 overloadApply(f
, &dg
);
1198 if (ifd
&& ifd
.interfaces
&& f
)
1200 // check the overloads of each inherited interface individually
1201 foreach (bc
; ifd
.interfaces
)
1203 if (auto fd
= bc
.sym
.search(e
.loc
, f
.ident
))
1204 overloadApply(fd
, &dg
);
1208 auto tup
= new TupleExp(e
.loc
, exps
);
1209 return tup
.expressionSemantic(scx
);
1214 if (e
.ident
== Id
.classInstanceSize
)
1219 auto o
= (*e
.args
)[0];
1220 auto s
= getDsymbol(o
);
1221 auto cd
= s ? s
.isClassDeclaration() : null;
1224 e
.error("first argument is not a class");
1225 return ErrorExp
.get();
1227 if (cd
.sizeok
!= Sizeok
.done
)
1231 if (cd
.sizeok
!= Sizeok
.done
)
1233 e
.error("%s `%s` is forward referenced", cd
.kind(), cd
.toChars());
1234 return ErrorExp
.get();
1237 return new IntegerExp(e
.loc
, cd
.structsize
, Type
.tsize_t
);
1239 if (e
.ident
== Id
.getAliasThis
)
1244 auto o
= (*e
.args
)[0];
1245 auto s
= getDsymbol(o
);
1246 auto ad
= s ? s
.isAggregateDeclaration() : null;
1248 auto exps
= new Expressions();
1249 if (ad
&& ad
.aliasthis
)
1250 exps
.push(new StringExp(e
.loc
, ad
.aliasthis
.ident
.toString()));
1251 Expression ex
= new TupleExp(e
.loc
, exps
);
1252 ex
= ex
.expressionSemantic(sc
);
1255 if (e
.ident
== Id
.getAttributes
)
1257 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
1258 * a symbol should not be folded to a constant.
1259 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
1261 if (!TemplateInstance
.semanticTiargs(e
.loc
, sc
, e
.args
, 3))
1262 return ErrorExp
.get();
1267 auto o
= (*e
.args
)[0];
1268 auto po
= isParameter(o
);
1269 auto s
= getDsymbolWithoutExpCtx(o
);
1270 UserAttributeDeclaration udad
= null;
1273 udad
= po
.userAttribDecl
;
1279 s
= s
.isImport().mod
;
1281 //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
1282 udad
= s
.userAttribDecl
;
1288 Expression x
= isExpression(o
);
1291 printf("e = %s %s\n", EXPtoString(x
.op
).ptr
, x
.toChars());
1293 printf("t = %d %s\n", t
.ty
, t
.toChars());
1295 e
.error("first argument is not a symbol");
1296 return ErrorExp
.get();
1299 auto exps
= udad ? udad
.getAttributes() : new Expressions();
1300 auto tup
= new TupleExp(e
.loc
, exps
);
1301 return tup
.expressionSemantic(sc
);
1303 if (e
.ident
== Id
.getFunctionAttributes
)
1305 /* Extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
1306 * https://dlang.org/spec/traits.html#getFunctionAttributes
1312 TypeFunction tf
= toTypeFunction((*e
.args
)[0], fd
);
1316 e
.error("first argument is not a function");
1317 return ErrorExp
.get();
1320 auto mods
= new Expressions();
1322 void addToMods(string
str)
1324 mods
.push(new StringExp(Loc
.initial
, str));
1326 tf
.modifiersApply(&addToMods
);
1327 tf
.attributesApply(&addToMods
, TRUSTformatSystem
);
1329 auto tup
= new TupleExp(e
.loc
, mods
);
1330 return tup
.expressionSemantic(sc
);
1332 if (e
.ident
== Id
.isReturnOnStack
)
1334 /* Extract as a boolean if function return value is on the stack
1335 * https://dlang.org/spec/traits.html#isReturnOnStack
1340 RootObject o
= (*e
.args
)[0];
1342 TypeFunction tf
= toTypeFunction(o
, fd
);
1346 e
.error("argument to `__traits(isReturnOnStack, %s)` is not a function", o
.toChars());
1347 return ErrorExp
.get();
1350 bool value
= target
.isReturnOnStack(tf
, fd
&& fd
.needThis());
1351 return IntegerExp
.createBool(value
);
1353 if (e
.ident
== Id
.getFunctionVariadicStyle
)
1355 /* Accept a symbol or a type. Returns one of the following:
1356 * "none" not a variadic function
1357 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
1358 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
1359 * "typesafe" void typesafe(T[] ...)
1361 // get symbol linkage as a string
1367 auto o
= (*e
.args
)[0];
1370 TypeFunction tf
= toTypeFunction(o
, fd
);
1375 varargs
= tf
.parameterList
.varargs
;
1381 e
.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o
.toChars());
1382 return ErrorExp
.get();
1385 varargs
= fd
.getParameterList().varargs
;
1388 final switch (varargs
)
1390 case VarArg
.none
: style
= "none"; break;
1391 case VarArg
.variadic
: style
= (link
== LINK
.d
)
1394 case VarArg
.typesafe
: style
= "typesafe"; break;
1396 auto se
= new StringExp(e
.loc
, style
);
1397 return se
.expressionSemantic(sc
);
1399 if (e
.ident
== Id
.getParameterStorageClasses
)
1401 /* Accept a function symbol or a type, followed by a parameter index.
1402 * Returns a tuple of strings of the parameter's storage classes.
1404 // get symbol linkage as a string
1408 auto o
= (*e
.args
)[0];
1409 auto o1
= (*e
.args
)[1];
1411 ParameterList fparams
;
1414 if (auto exp
= isExpression(o
))
1415 ce
= exp
.isCallExp();
1419 fparams
= ce
.f
.getParameterList();
1424 auto tf
= toTypeFunction(o
, fd
);
1426 fparams
= tf
.parameterList
;
1428 fparams
= fd
.getParameterList();
1431 e
.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function or a function call",
1432 o
.toChars(), o1
.toChars());
1433 return ErrorExp
.get();
1437 // Avoid further analysis for invalid functions leading to misleading error messages
1438 if (!fparams
.parameters
)
1439 return ErrorExp
.get();
1443 // Set stc to storage class of the ith parameter
1444 auto ex
= isExpression((*e
.args
)[1]);
1447 e
.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1448 o
.toChars(), o1
.toChars());
1449 return ErrorExp
.get();
1451 ex
= ex
.ctfeInterpret();
1452 auto ii
= ex
.toUInteger();
1453 if (ii
>= fparams
.length
)
1455 e
.error("parameter index must be in range 0..%u not %s", cast(uint)fparams
.length
, ex
.toChars());
1456 return ErrorExp
.get();
1459 uint n
= cast(uint)ii
;
1460 Parameter p
= fparams
[n
];
1461 stc = p
.storageClass
;
1463 // This mirrors hdrgen.visit(Parameter p)
1464 if (p
.type
&& p
.type
.mod
& MODFlags
.shared_
)
1465 stc &= ~STC
.shared_
;
1467 auto exps
= new Expressions
;
1471 exps
.push(new StringExp(e
.loc
, s
));
1474 if (stc & STC
.auto_
)
1476 if (stc & STC
.return_
)
1481 else if (stc & STC
.in_
)
1483 else if (stc & STC
.ref_
)
1485 else if (stc & STC
.lazy_
)
1487 else if (stc & STC
.alias_
)
1490 if (stc & STC
.const_
)
1492 if (stc & STC
.immutable_
)
1496 if (stc & STC
.shared_
)
1498 if (stc & STC
.scope_
&& !(stc & STC
.scopeinferred
))
1501 auto tup
= new TupleExp(e
.loc
, exps
);
1502 return tup
.expressionSemantic(sc
);
1504 if (e
.ident
== Id
.getLinkage
)
1506 // get symbol linkage as a string
1511 auto o
= (*e
.args
)[0];
1514 TypeFunction tf
= toTypeFunction(o
, fd
);
1518 link
= fd ? fd
.linkage
: tf
.linkage
;
1522 auto s
= getDsymbol(o
);
1524 AggregateDeclaration agg
;
1525 if (!s ||
((d
= s
.isDeclaration()) is null && (agg
= s
.isAggregateDeclaration()) is null))
1527 e
.error("argument to `__traits(getLinkage, %s)` is not a declaration", o
.toChars());
1528 return ErrorExp
.get();
1535 // Resolves forward references
1536 if (agg
.sizeok
!= Sizeok
.done
)
1539 if (agg
.sizeok
!= Sizeok
.done
)
1541 e
.error("%s `%s` is forward referenced", agg
.kind(), agg
.toChars());
1542 return ErrorExp
.get();
1546 final switch (agg
.classKind
)
1554 case ClassKind
.objc
:
1563 auto linkage
= linkageToChars(link
);
1564 auto se
= new StringExp(e
.loc
, linkage
.toDString());
1565 return se
.expressionSemantic(sc
);
1567 if (e
.ident
== Id
.allMembers ||
1568 e
.ident
== Id
.derivedMembers
)
1573 auto o
= (*e
.args
)[0];
1574 auto s
= getDsymbol(o
);
1577 e
.error("In expression `%s` `%s` can't have members", e
.toChars(), o
.toChars());
1578 e
.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", o
.toChars());
1580 return ErrorExp
.get();
1582 if (auto imp
= s
.isImport())
1584 // https://issues.dlang.org/show_bug.cgi?id=9692
1588 // https://issues.dlang.org/show_bug.cgi?id=16044
1589 if (auto p
= s
.isPackage())
1591 if (auto pm
= p
.isPackageMod())
1595 auto sds
= s
.isScopeDsymbol();
1596 if (!sds || sds
.isTemplateDeclaration())
1598 e
.error("In expression `%s` %s `%s` has no members", e
.toChars(), s
.kind(), s
.toChars());
1599 e
.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", s
.toChars());
1600 return ErrorExp
.get();
1603 auto idents
= new Identifiers();
1605 int pushIdentsDg(size_t n
, Dsymbol sm
)
1610 // skip local symbols, such as static foreach loop variables
1611 if (auto decl
= sm
.isDeclaration())
1613 if (decl
.storage_class
& STC
.local
)
1617 // skip 'this' context pointers
1618 else if (decl
.isThisDeclaration())
1622 // https://issues.dlang.org/show_bug.cgi?id=20915
1623 // skip version and debug identifiers
1624 if (sm
.isVersionSymbol() || sm
.isDebugSymbol())
1627 //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
1630 // https://issues.dlang.org/show_bug.cgi?id=10096
1631 // https://issues.dlang.org/show_bug.cgi?id=10100
1632 // Skip over internal members in __traits(allMembers)
1633 if ((sm
.isCtorDeclaration() && sm
.ident
!= Id
.ctor
) ||
1634 (sm
.isDtorDeclaration() && sm
.ident
!= Id
.dtor
) ||
1635 (sm
.isPostBlitDeclaration() && sm
.ident
!= Id
.postblit
) ||
1636 sm
.isInvariantDeclaration() ||
1637 sm
.isUnitTestDeclaration())
1642 if (sm
.ident
== Id
.empty
)
1646 if (sm
.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177
1648 if ((!sds
.isModule() && !sds
.isPackage()) && sm
.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057
1651 //printf("\t%s\n", sm.ident.toChars());
1653 /* Skip if already present in idents[]
1655 foreach (id
; *idents
)
1660 // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
1663 import core
.stdc
.string
: strcmp
;
1664 assert(strcmp(id
.toChars(), sm
.ident
.toChars()) != 0);
1667 idents
.push(sm
.ident
);
1669 else if (auto ed
= sm
.isEnumDeclaration())
1671 ScopeDsymbol
._foreach(null, ed
.members
, &pushIdentsDg
);
1676 ScopeDsymbol
._foreach(sc
, sds
.members
, &pushIdentsDg
);
1677 auto cd
= sds
.isClassDeclaration();
1678 if (cd
&& e
.ident
== Id
.allMembers
)
1680 if (cd
.semanticRun
< PASS
.semanticdone
)
1681 cd
.dsymbolSemantic(null); // https://issues.dlang.org/show_bug.cgi?id=13668
1682 // Try to resolve forward reference
1684 void pushBaseMembersDg(ClassDeclaration cd
)
1686 for (size_t i
= 0; i
< cd
.baseclasses
.dim
; i
++)
1688 auto cb
= (*cd
.baseclasses
)[i
].sym
;
1690 ScopeDsymbol
._foreach(null, cb
.members
, &pushIdentsDg
);
1691 if (cb
.baseclasses
.dim
)
1692 pushBaseMembersDg(cb
);
1696 pushBaseMembersDg(cd
);
1699 // Turn Identifiers into StringExps reusing the allocated array
1700 assert(Expressions
.sizeof
== Identifiers
.sizeof
);
1701 auto exps
= cast(Expressions
*)idents
;
1702 foreach (i
, id
; *idents
)
1704 auto se
= new StringExp(e
.loc
, id
.toString());
1708 /* Making this a tuple is more flexible, as it can be statically unrolled.
1709 * To make an array literal, enclose __traits in [ ]:
1710 * [ __traits(allMembers, ...) ]
1712 Expression ex
= new TupleExp(e
.loc
, exps
);
1713 ex
= ex
.expressionSemantic(sc
);
1716 if (e
.ident
== Id
.compiles
)
1718 /* Determine if all the objects - types, expressions, or symbols -
1719 * compile without error
1724 foreach (o
; *e
.args
)
1726 uint errors
= global
.startGagging();
1727 Scope
* sc2
= sc
.push();
1730 sc2
.flags
= (sc
.flags
& ~(SCOPE
.ctfe | SCOPE
.condition
)) | SCOPE
.compile | SCOPE
.fullinst
;
1735 auto ex
= isExpression(o
);
1739 t
.resolve(e
.loc
, sc2
, ex
, t
, s
);
1742 t
.typeSemantic(e
.loc
, sc2
);
1746 else if (s
&& s
.errors
)
1751 ex
= ex
.expressionSemantic(sc2
);
1752 ex
= resolvePropertiesOnly(sc2
, ex
);
1753 ex
= ex
.optimize(WANTvalue
);
1754 if (sc2
.func
&& sc2
.func
.type
.ty
== Tfunction
)
1756 const tf
= cast(TypeFunction
)sc2
.func
.type
;
1757 err |
= tf
.isnothrow
&& canThrow(ex
, sc2
.func
, false);
1759 ex
= checkGC(sc2
, ex
);
1760 if (ex
.op
== EXP
.error
)
1764 // Carefully detach the scope from the parent and throw it away as
1765 // we only need it to evaluate the expression
1766 // https://issues.dlang.org/show_bug.cgi?id=15428
1769 if (global
.endGagging(errors
) || err
)
1776 if (e
.ident
== Id
.isSame
)
1778 /* Determine if two symbols are the same
1783 // https://issues.dlang.org/show_bug.cgi?id=20761
1784 // tiarg semantic may expand in place the list of arguments, for example:
1786 // before tiarg sema: __traits(isSame, seq!(0,0), seq!(1,1))
1787 // after : __traits(isSame, 0, 0, 1, 1)
1789 // so we split in two lists
1791 ob1
.push((*e
.args
)[0]);
1793 ob2
.push((*e
.args
)[1]);
1794 if (!TemplateInstance
.semanticTiargs(e
.loc
, sc
, &ob1
, 0))
1795 return ErrorExp
.get();
1796 if (!TemplateInstance
.semanticTiargs(e
.loc
, sc
, &ob2
, 0))
1797 return ErrorExp
.get();
1798 if (ob1
.dim
!= ob2
.dim
)
1800 foreach (immutable i
; 0 .. ob1
.dim
)
1801 if (!ob1
[i
].isSame(ob2
[i
], sc
))
1805 if (e
.ident
== Id
.getUnitTests
)
1810 auto o
= (*e
.args
)[0];
1811 auto s
= getDsymbolWithoutExpCtx(o
);
1814 e
.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate",
1816 return ErrorExp
.get();
1818 if (auto imp
= s
.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990
1821 auto sds
= s
.isScopeDsymbol();
1822 if (!sds || sds
.isTemplateDeclaration())
1824 e
.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate, not a %s",
1825 s
.toChars(), s
.kind());
1826 return ErrorExp
.get();
1829 auto exps
= new Expressions();
1830 if (global
.params
.useUnitTests
)
1832 bool[void*] uniqueUnitTests
;
1834 void symbolDg(Dsymbol s
)
1836 if (auto ad
= s
.isAttribDeclaration())
1838 ad
.include(null).foreachDsymbol(&symbolDg
);
1840 else if (auto tm
= s
.isTemplateMixin())
1842 tm
.members
.foreachDsymbol(&symbolDg
);
1844 else if (auto ud
= s
.isUnitTestDeclaration())
1846 if (cast(void*)ud
in uniqueUnitTests
)
1849 uniqueUnitTests
[cast(void*)ud
] = true;
1851 auto ad
= new FuncAliasDeclaration(ud
.ident
, ud
, false);
1852 ad
.visibility
= ud
.visibility
;
1854 auto e
= new DsymbolExp(Loc
.initial
, ad
, false);
1859 sds
.members
.foreachDsymbol(&symbolDg
);
1861 auto te
= new TupleExp(e
.loc
, exps
);
1862 return te
.expressionSemantic(sc
);
1864 if (e
.ident
== Id
.getVirtualIndex
)
1869 auto o
= (*e
.args
)[0];
1870 auto s
= getDsymbolWithoutExpCtx(o
);
1872 auto fd
= s ? s
.isFuncDeclaration() : null;
1875 e
.error("first argument to __traits(getVirtualIndex) must be a function");
1876 return ErrorExp
.get();
1879 fd
= fd
.toAliasFunc(); // Necessary to support multiple overloads.
1880 return new IntegerExp(e
.loc
, fd
.vtblIndex
, Type
.tptrdiff_t
);
1882 if (e
.ident
== Id
.getPointerBitmap
)
1884 return pointerBitmap(e
);
1886 if (e
.ident
== Id
.initSymbol
)
1891 auto o
= (*e
.args
)[0];
1893 AggregateDeclaration ad
= t ?
isAggregate(t
) : null;
1895 // Interfaces don't have an init symbol and hence cause linker errors
1896 if (!ad || ad
.isInterfaceDeclaration())
1898 e
.error("struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o
.toChars());
1899 return ErrorExp
.get();
1902 Declaration d
= new SymbolDeclaration(ad
.loc
, ad
);
1903 d
.type
= Type
.tvoid
.arrayOf().constOf();
1904 d
.storage_class |
= STC
.rvalue
;
1905 return new VarExp(e
.loc
, d
);
1907 if (e
.ident
== Id
.isZeroInit
)
1912 auto o
= (*e
.args
)[0];
1916 e
.error("type expected as second argument of __traits `%s` instead of `%s`",
1917 e
.ident
.toChars(), o
.toChars());
1918 return ErrorExp
.get();
1921 Type tb
= t
.baseElemOf();
1922 return tb
.isZeroInit(e
.loc
) ?
True() : False();
1924 if (e
.ident
== Id
.getTargetInfo
)
1929 auto ex
= isExpression((*e
.args
)[0]);
1930 StringExp se
= ex ? ex
.ctfeInterpret().toStringExp() : null;
1931 if (!ex ||
!se || se
.len
== 0)
1933 e
.error("string expected as argument of __traits `%s` instead of `%s`", e
.ident
.toChars(), ex
.toChars());
1934 return ErrorExp
.get();
1938 const slice
= se
.peekString();
1939 Expression r
= target
.getTargetInfo(slice
.ptr
, e
.loc
); // BUG: reliance on terminating 0
1942 e
.error("`getTargetInfo` key `\"%.*s\"` not supported by this implementation",
1943 cast(int)slice
.length
, slice
.ptr
);
1944 return ErrorExp
.get();
1946 return r
.expressionSemantic(sc
);
1948 if (e
.ident
== Id
.getLocation
)
1952 auto arg0
= (*e
.args
)[0];
1953 Dsymbol s
= getDsymbolWithoutExpCtx(arg0
);
1954 if (!s ||
!s
.loc
.isValid())
1956 e
.error("can only get the location of a symbol, not `%s`", arg0
.toChars());
1957 return ErrorExp
.get();
1960 const fd
= s
.isFuncDeclaration();
1961 // FIXME:td.overnext is always set, even when using an index on it
1962 //const td = s.isTemplateDeclaration();
1963 if ((fd
&& fd
.overnext
) /*|| (td && td.overnext)*/)
1965 e
.error("cannot get location of an overload set, " ~
1966 "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " ~
1967 "to get the Nth overload",
1968 arg0
.toChars(), /*td ? ", true".ptr :*/ "".ptr
);
1969 return ErrorExp
.get();
1972 auto exps
= new Expressions(3);
1973 (*exps
)[0] = new StringExp(e
.loc
, s
.loc
.filename
.toDString());
1974 (*exps
)[1] = new IntegerExp(e
.loc
, s
.loc
.linnum
,Type
.tint32
);
1975 (*exps
)[2] = new IntegerExp(e
.loc
, s
.loc
.charnum
,Type
.tint32
);
1976 auto tup
= new TupleExp(e
.loc
, exps
);
1977 return tup
.expressionSemantic(sc
);
1979 if (e
.ident
== Id
.getCppNamespaces
)
1981 auto o
= (*e
.args
)[0];
1982 auto s
= getDsymbolWithoutExpCtx(o
);
1983 auto exps
= new Expressions(0);
1984 if (auto d
= s
.isDeclaration())
1988 d
.error("circular reference in `__traits(GetCppNamespaces,...)`");
1989 return ErrorExp
.get();
1995 Prepend the namespaces in the linked list `ns` to `es`.
1997 Returns: true if `ns` contains an `ErrorExp`.
1999 bool prependNamespaces(Expressions
* es
, CPPNamespaceDeclaration ns
)
2001 // Semantic processing will convert `extern(C++, "a", "b", "c")`
2002 // into `extern(C++, "a") extern(C++, "b") extern(C++, "c")`,
2003 // creating a linked list what `a`'s `cppnamespace` points to `b`,
2004 // and `b`'s points to `c`. Our entry point is `a`.
2005 for (; ns
!is null; ns
= ns
.cppnamespace
)
2007 ns
.dsymbolSemantic(sc
);
2009 if (ns
.exp
.isErrorExp())
2012 auto se
= ns
.exp
.toStringExp();
2013 // extern(C++, (emptyTuple))
2015 // will produce a blank ident
2022 for (auto p
= s
; !p
.isModule(); p
= p
.toParent())
2024 p
.dsymbolSemantic(sc
);
2025 auto pp
= p
.toParent();
2026 if (pp
.isTemplateInstance())
2028 if (!p
.cppnamespace
)
2030 //if (!p.toParent().cppnamespace)
2032 auto inner
= new Expressions(0);
2033 auto outer
= new Expressions(0);
2034 if (prependNamespaces(inner
, p
.cppnamespace
)) return ErrorExp
.get();
2035 if (prependNamespaces(outer
, pp
.cppnamespace
)) return ErrorExp
.get();
2038 while(i
< outer
.dim
&& ((*inner
)[i
]) == (*outer
)[i
])
2041 foreach_reverse (ns
; (*inner
)[][i
.. $])
2047 exps
.insert(0, new StringExp(p
.loc
, p
.ident
.toString()));
2049 if (prependNamespaces(exps
, p
.cppnamespace
))
2050 return ErrorExp
.get();
2052 if (auto d
= s
.isDeclaration())
2054 auto tup
= new TupleExp(e
.loc
, exps
);
2055 return tup
.expressionSemantic(sc
);
2057 //https://issues.dlang.org/show_bug.cgi?id=22291
2058 if (e
.ident
== Id
.parameters
)
2063 char[] contents
= cast(char[]) e
.args
.toString();
2064 contents
= contents
[1..$];
2065 contents
[$-1] = '\0';
2066 e
.error("`__traits(parameters)` cannot have arguments, but `%s` was supplied", contents
.ptr
);
2067 return ErrorExp
.get();
2070 auto fd
= sc
.getEnclosingFunction();
2073 e
.error("`__traits(parameters)` may only be used inside a function");
2074 return ErrorExp
.get();
2077 auto tf
= fd
.type
.isTypeFunction();
2079 auto exps
= new Expressions(0);
2080 int addParameterDG(size_t idx
, Parameter x
)
2083 exps
.push(new IdentifierExp(e
.loc
, x
.ident
));
2087 This is required since not all "parameters" actually have a name
2088 until they (tuples) are expanded e.g. an anonymous tuple parameter's
2089 contents get given names but not the tuple itself.
2091 Parameter
._foreach(tf
.parameterList
.parameters
, &addParameterDG
);
2092 auto tup
= new TupleExp(e
.loc
, exps
);
2093 return tup
.expressionSemantic(sc
);
2095 static const(char)[] trait_search_fp(const(char)[] seed
, out int cost
)
2097 //printf("trait_search_fp('%s')\n", seed);
2100 cost
= 0; // all the same cost
2101 const sv
= traitsStringTable
.lookup(seed
);
2102 return sv ? sv
.toString() : null;
2105 if (auto sub = speller
!trait_search_fp(e
.ident
.toString()))
2106 e
.error("unrecognized trait `%s`, did you mean `%.*s`?", e
.ident
.toChars(), cast(int) sub.length
, sub.ptr
);
2108 e
.error("unrecognized trait `%s`", e
.ident
.toChars());
2109 return ErrorExp
.get();
2112 /// compare arguments of __traits(isSame)
2113 private bool isSame(RootObject o1
, RootObject o2
, Scope
* sc
)
2115 static FuncLiteralDeclaration
isLambda(RootObject oarg
)
2117 if (auto t
= isDsymbol(oarg
))
2119 if (auto td
= t
.isTemplateDeclaration())
2121 if (td
.members
&& td
.members
.dim
== 1)
2123 if (auto fd
= (*td
.members
)[0].isFuncLiteralDeclaration())
2128 else if (auto ea
= isExpression(oarg
))
2130 if (ea
.op
== EXP
.function_
)
2132 if (auto fe
= ea
.isFuncExp())
2139 auto l1
= isLambda(o1
);
2140 auto l2
= isLambda(o2
);
2144 import dmd
.lambdacomp
: isSameFuncLiteral
;
2145 if (isSameFuncLiteral(l1
, l2
, sc
))
2149 // issue 12001, allow isSame, <BasicType>, <BasicType>
2150 Type t1
= isType(o1
);
2151 Type t2
= isType(o2
);
2152 if (t1
&& t2
&& t1
.equals(t2
))
2155 auto s1
= getDsymbol(o1
);
2156 auto s2
= getDsymbol(o2
);
2157 //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars());
2160 printf("o1: %p\n", o1
);
2161 printf("o2: %p\n", o2
);
2164 if (auto ea
= isExpression(o1
))
2165 printf("%s\n", ea
.toChars());
2166 if (auto ta
= isType(o1
))
2167 printf("%s\n", ta
.toChars());
2171 printf("%s %s\n", s1
.kind(), s1
.toChars());
2175 auto ea1
= isExpression(o1
);
2176 auto ea2
= isExpression(o2
);
2179 if (ea1
.equals(ea2
))
2189 if (auto fa1
= s1
.isFuncAliasDeclaration())
2190 s1
= fa1
.toAliasFunc();
2191 if (auto fa2
= s2
.isFuncAliasDeclaration())
2192 s2
= fa2
.toAliasFunc();
2194 // https://issues.dlang.org/show_bug.cgi?id=11259
2195 // compare import symbol to a package symbol
2196 static bool cmp(Dsymbol s1
, Dsymbol s2
)
2198 auto imp
= s1
.isImport();
2199 return imp
&& imp
.pkg
&& imp
.pkg
== s2
.isPackage();
2202 if (cmp(s1
,s2
) ||
cmp(s2
,s1
))
2208 // https://issues.dlang.org/show_bug.cgi?id=18771
2209 // OverloadSets are equal if they contain the same functions
2210 auto overSet1
= s1
.isOverloadSet();
2214 auto overSet2
= s2
.isOverloadSet();
2218 if (overSet1
.a
.dim
!= overSet2
.a
.dim
)
2221 // OverloadSets contain array of Dsymbols => O(n*n)
2222 // to compare for equality as the order of overloads
2223 // might not be the same
2225 foreach(overload1
; overSet1
.a
)
2227 foreach(overload2
; overSet2
.a
)
2229 if (overload1
== overload2
)