d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
[official-gcc.git] / gcc / d / dmd / traits.d
blob04e1c47d16e944c8f1a5ab26f041dc4618a54d49
1 /**
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
14 module dmd.traits;
16 import core.stdc.stdio;
18 import dmd.aggregate;
19 import dmd.arraytypes;
20 import dmd.astcodegen;
21 import dmd.astenums;
22 import dmd.attrib;
23 import dmd.canthrow;
24 import dmd.dclass;
25 import dmd.declaration;
26 import dmd.dimport;
27 import dmd.dmangle;
28 import dmd.dmodule;
29 import dmd.dscope;
30 import dmd.dsymbol;
31 import dmd.dsymbolsem;
32 import dmd.dtemplate;
33 import dmd.errors;
34 import dmd.expression;
35 import dmd.expressionsem;
36 import dmd.func;
37 import dmd.globals;
38 import dmd.hdrgen;
39 import dmd.id;
40 import dmd.identifier;
41 import dmd.mtype;
42 import dmd.nogc;
43 import dmd.parse;
44 import dmd.root.array;
45 import dmd.root.speller;
46 import dmd.root.stringtable;
47 import dmd.target;
48 import dmd.tokens;
49 import dmd.typesem;
50 import dmd.visitor;
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.
64 * For example:
65 * ----
66 * struct S { void f() {} }
67 * S s;
68 * pragma(msg, __traits(isNested, s.f));
69 * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`.
70 * ----
72 * This is used for that common `__traits` behavior.
74 * Input:
75 * oarg object to get the symbol for
76 * Returns:
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())
84 return dve.var;
85 if (auto dte = e.isDotTemplateExp())
86 return dte.td;
88 return getDsymbol(oarg);
91 private const StringTable!bool traitsStringTable;
93 shared static this()
95 static immutable string[] names =
97 "isAbstractClass",
98 "isArithmetic",
99 "isAssociativeArray",
100 "isDisabled",
101 "isDeprecated",
102 "isFuture",
103 "isFinalClass",
104 "isPOD",
105 "isNested",
106 "isFloating",
107 "isIntegral",
108 "isScalar",
109 "isStaticArray",
110 "isUnsigned",
111 "isVirtualFunction",
112 "isVirtualMethod",
113 "isAbstractFunction",
114 "isFinalFunction",
115 "isOverrideFunction",
116 "isStaticFunction",
117 "isModule",
118 "isPackage",
119 "isRef",
120 "isOut",
121 "isLazy",
122 "isReturnOnStack",
123 "hasMember",
124 "identifier",
125 "getProtection",
126 "getVisibility",
127 "parent",
128 "child",
129 "getLinkage",
130 "getMember",
131 "getOverloads",
132 "getVirtualFunctions",
133 "getVirtualMethods",
134 "classInstanceSize",
135 "allMembers",
136 "derivedMembers",
137 "isSame",
138 "compiles",
139 "getAliasThis",
140 "getAttributes",
141 "getFunctionAttributes",
142 "getFunctionVariadicStyle",
143 "getParameterStorageClasses",
144 "getUnitTests",
145 "getVirtualIndex",
146 "getPointerBitmap",
147 "isZeroInit",
148 "getTargetInfo",
149 "getLocation",
150 "hasPostblit",
151 "hasCopyConstructor",
152 "isCopyable",
153 "parameters"
156 StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable;
157 stringTable._init(names.length);
159 foreach (s; names)
161 auto sv = stringTable.insert(s, true);
162 assert(sv);
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)
173 ulong sz;
174 if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
175 sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
176 else
177 sz = t.size(loc);
178 if (sz == SIZE_INVALID)
179 return ulong.max;
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());
185 return ulong.max;
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);
193 data.zero();
195 extern (C++) final class PointerBitmapVisitor : Visitor
197 alias visit = Visitor.visit;
198 public:
199 extern (D) this(Array!(ulong)* _data, ulong _sz_size_t)
201 this.data = _data;
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();
214 if (tb != t)
215 tb.accept(this);
218 override void visit(TypeError t)
220 visit(cast(Type)t);
223 override void visit(TypeNext t)
225 assert(0);
228 override void visit(TypeBasic t)
230 if (t.ty == Tvoid)
231 setpointer(offset);
234 override void visit(TypeVector t)
238 override void visit(TypeArray t)
240 assert(0);
243 override void visit(TypeSArray t)
245 ulong arrayoff = offset;
246 ulong nextsize = t.next.size();
247 if (nextsize == SIZE_INVALID)
248 error = true;
249 ulong dim = t.dim.toInteger();
250 for (ulong i = 0; i < dim; i++)
252 offset = arrayoff + i * nextsize;
253 t.next.accept(this);
255 offset = arrayoff;
258 override void visit(TypeDArray t)
260 setpointer(offset + sz_size_t);
263 // dynamic array is {length,ptr}
264 override void visit(TypeAArray t)
266 setpointer(offset);
269 override void visit(TypePointer t)
271 if (t.nextOf().ty != Tfunction) // don't mark function pointers
272 setpointer(offset);
275 override void visit(TypeReference t)
277 setpointer(offset);
280 override void visit(TypeClass t)
282 setpointer(offset);
285 override void visit(TypeFunction t)
289 override void visit(TypeDelegate t)
291 setpointer(offset);
294 // delegate is {context, function}
295 override void visit(TypeQualified t)
297 assert(0);
300 // assume resolved
301 override void visit(TypeIdentifier t)
303 assert(0);
306 override void visit(TypeInstance t)
308 assert(0);
311 override void visit(TypeTypeof t)
313 assert(0);
316 override void visit(TypeReturn t)
318 assert(0);
321 override void visit(TypeEnum t)
323 visit(cast(Type)t);
326 override void visit(TypeTuple t)
328 visit(cast(Type)t);
331 override void visit(TypeSlice t)
333 assert(0);
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)
348 setpointer(offset);
349 else
350 v.type.accept(this);
352 offset = structoff;
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
360 if (t.sym.baseClass)
361 visitClass(cast(TypeClass)t.sym.baseClass.type);
362 foreach (v; t.sym.fields)
364 offset = classoff + v.offset;
365 v.type.accept(this);
367 offset = classoff;
370 Array!(ulong)* data;
371 ulong offset;
372 ulong sz_size_t;
373 bool error;
376 scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t);
377 if (t.ty == Tclass)
378 pbv.visitClass(cast(TypeClass)t);
379 else
380 t.accept(pbv);
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
388 * of the array
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]);
403 if (!t)
405 error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
406 return ErrorExp.get();
409 Array!(ulong) data;
410 ulong sz = getTypePointerBitmap(e.loc, t, &data);
411 if (sz == ulong.max)
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);
420 return ale;
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
438 const save = sc.stc;
439 if (e.ident == Id.isDeprecated)
440 sc.stc |= STC.deprecated_;
441 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1))
443 sc.stc = save;
444 return ErrorExp.get();
446 sc.stc = save;
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);
466 /********
467 * Gets the function type from a given AST node
468 * if the node is a function of some sort.
469 * Params:
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`
472 * Returns:
473 * a type node if `o` is a declaration of
474 * a delegate, function, function-pointer or a variable of the former.
475 * Otherwise, `null`.
477 static TypeFunction toTypeFunction(RootObject o, out FuncDeclaration fdp)
479 Type t;
480 if (auto s = getDsymbolWithoutExpCtx(o))
482 if (auto fd = s.isFuncDeclaration())
484 t = fd.type;
485 fdp = fd;
487 else if (auto vd = s.isVarDeclaration())
488 t = vd.type;
489 else
490 t = isType(o);
492 else
493 t = isType(o);
495 if (t)
497 if (auto tf = t.isFunction_Delegate_PtrToFunction())
498 return tf;
501 return null;
504 IntegerExp isX(T)(bool delegate(T) fp)
506 if (!dim)
507 return False();
508 foreach (o; *e.args)
510 static if (is(T == Type))
511 auto y = getType(o);
513 static if (is(T : Dsymbol))
515 auto s = getDsymbolWithoutExpCtx(o);
516 if (!s)
517 return False();
519 static if (is(T == Dsymbol))
520 alias y = s;
521 static if (is(T == Declaration))
522 auto y = s.isDeclaration();
523 static if (is(T == FuncDeclaration))
524 auto y = s.isFuncDeclaration();
526 if (!y || !fp(y))
527 return False();
529 return True();
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))
572 return 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)
595 if (dim != 1)
596 return dimError(1);
598 return isDsymX((s)
600 if (!s.toAlias().isOverloadable())
601 return false;
602 return overloadApply(s,
603 sm => sm.isTemplateDeclaration() !is null) != 0;
606 if (e.ident == Id.isPOD)
608 if (dim != 1)
609 return dimError(1);
611 auto o = (*e.args)[0];
612 auto t = isType(o);
613 if (!t)
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();
625 return True();
627 if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit)
629 if (dim != 1)
630 return dimError(1);
632 auto o = (*e.args)[0];
633 auto t = isType(o);
634 if (!t)
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());
647 return False();
649 if (e.ident == Id.isCopyable)
651 if (dim != 1)
652 return dimError(1);
654 auto o = (*e.args)[0];
655 auto t = isType(o);
656 if (!t)
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)
675 if (dim != 1)
676 return dimError(1);
678 auto o = (*e.args)[0];
679 auto s = getDsymbolWithoutExpCtx(o);
680 if (!s)
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)
697 if (dim != 1)
698 return dimError(1);
700 return isDeclX(f => f.isDisabled());
702 if (e.ident == Id.isAbstractFunction)
704 if (dim != 1)
705 return dimError(1);
707 return isFuncX(f => f.isAbstract());
709 if (e.ident == Id.isVirtualFunction)
711 if (dim != 1)
712 return dimError(1);
714 return isFuncX(f => f.isVirtual());
716 if (e.ident == Id.isVirtualMethod)
718 if (dim != 1)
719 return dimError(1);
721 return isFuncX(f => f.isVirtualMethod());
723 if (e.ident == Id.isFinalFunction)
725 if (dim != 1)
726 return dimError(1);
728 return isFuncX(f => f.isFinalFunc());
730 if (e.ident == Id.isOverrideFunction)
732 if (dim != 1)
733 return dimError(1);
735 return isFuncX(f => f.isOverride());
737 if (e.ident == Id.isStaticFunction)
739 if (dim != 1)
740 return dimError(1);
742 return isFuncX(f => !f.needThis() && !f.isNested());
744 if (e.ident == Id.isModule)
746 if (dim != 1)
747 return dimError(1);
749 return isPkgX(p => p.isModule() || p.isPackageMod());
751 if (e.ident == Id.isPackage)
753 if (dim != 1)
754 return dimError(1);
756 return isPkgX(p => p.isModule() is null);
758 if (e.ident == Id.isRef)
760 if (dim != 1)
761 return dimError(1);
763 return isDeclX(d => d.isRef());
765 if (e.ident == Id.isOut)
767 if (dim != 1)
768 return dimError(1);
770 return isDeclX(d => d.isOut());
772 if (e.ident == Id.isLazy)
774 if (dim != 1)
775 return dimError(1);
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();
788 if (dim != 1)
789 return dimError(1);
791 auto o = (*e.args)[0];
792 Identifier id;
793 if (auto po = isParameter(o))
795 if (!po.ident)
797 e.error("argument `%s` has no identifier", po.type.toChars());
798 return ErrorExp.get();
800 id = po.ident;
802 else
804 Dsymbol s = getDsymbolWithoutExpCtx(o);
805 if (!s || !s.ident)
807 e.error("argument `%s` has no identifier", o.toChars());
808 return ErrorExp.get();
810 id = s.ident;
813 auto se = new StringExp(e.loc, id.toString());
814 return se.expressionSemantic(sc);
816 if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
818 if (dim != 1)
819 return dimError(1);
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);
824 sc2.pop();
825 if (!ok)
826 return ErrorExp.get();
828 auto o = (*e.args)[0];
829 auto s = getDsymbolWithoutExpCtx(o);
830 if (!s)
832 if (!isError(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)
840 assert(protName);
841 auto se = new StringExp(e.loc, protName);
842 return se.expressionSemantic(sc);
844 if (e.ident == Id.parent)
846 if (dim != 1)
847 return dimError(1);
849 auto o = (*e.args)[0];
850 auto s = getDsymbolWithoutExpCtx(o);
851 if (s)
853 // https://issues.dlang.org/show_bug.cgi?id=12496
854 // Consider:
855 // class T1
856 // {
857 // class C(uint value) { }
858 // }
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;
870 if (td)
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
880 s = s.toParent();
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);
896 return ex;
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)
909 if (dim != 2)
910 return dimError(2);
912 Expression ex;
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())
917 ex = exp;
918 else
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);
927 if (!symc)
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));
939 else
940 assert(0);
942 ex = ex.expressionSemantic(sc);
943 return ex;
945 if (e.ident == Id.toType)
947 if (dim != 1)
948 return dimError(1);
950 auto ex = isExpression((*e.args)[0]);
951 if (!ex)
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)");
959 if (!se)
961 return ErrorExp.get();
963 Type t = decoToType(se.toUTF8(sc).peekString());
964 if (!t)
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))
978 return dimError(2);
980 auto o = (*e.args)[0];
981 auto ex = isExpression((*e.args)[1]);
982 if (!ex)
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();
1008 se = se.toUTF8(sc);
1010 if (se.sz != 1)
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);
1024 else if (sym)
1026 if (e.ident == Id.hasMember)
1028 if (auto sm = sym.search(e.loc, id))
1029 return True();
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);
1036 else
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
1058 die.wantsym = true;
1059 ex = ex.expressionSemantic(scx);
1060 return ex;
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();
1075 Dsymbol f;
1076 if (auto ve = ex.isVarExp)
1078 if (ve.var.isFuncDeclaration() || ve.var.isOverDeclaration())
1079 f = ve.var;
1080 ex = null;
1082 else if (auto dve = ex.isDotVarExp)
1084 if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration())
1085 f = dve.var;
1086 if (dve.e1.op == EXP.dotType || dve.e1.op == EXP.this_)
1087 ex = null;
1088 else
1089 ex = dve.e1;
1091 else if (auto te = ex.isTemplateExp)
1093 auto td = te.td;
1094 f = td;
1095 if (td && td.funcroot)
1096 f = td.funcroot;
1097 ex = null;
1099 else if (auto dte = ex.isDotTemplateExp)
1101 auto td = dte.td;
1102 f = td;
1103 if (td && td.funcroot)
1104 f = td.funcroot;
1105 ex = null;
1106 if (dte.e1.op != EXP.dotType && dte.e1.op != EXP.this_)
1107 ex = dte.e1;
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;
1129 exps.push(e);
1133 int dg(Dsymbol s)
1135 auto fd = s.isFuncDeclaration();
1136 if (!fd)
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));
1160 td.overroot = null;
1161 td.overnext = null;
1164 auto e = ex ? new DotTemplateExp(Loc.initial, ex, td)
1165 : new DsymbolExp(Loc.initial, td);
1166 exps.push(e);
1169 return 0;
1171 if (e.ident == Id.getVirtualFunctions && !fd.isVirtual())
1172 return 0;
1173 if (e.ident == Id.getVirtualMethods && !fd.isVirtualMethod())
1174 return 0;
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);
1187 else
1188 exps.push(e);
1189 return 0;
1192 InterfaceDeclaration ifd = null;
1193 if (sym)
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);
1211 else
1212 assert(0);
1214 if (e.ident == Id.classInstanceSize)
1216 if (dim != 1)
1217 return dimError(1);
1219 auto o = (*e.args)[0];
1220 auto s = getDsymbol(o);
1221 auto cd = s ? s.isClassDeclaration() : null;
1222 if (!cd)
1224 e.error("first argument is not a class");
1225 return ErrorExp.get();
1227 if (cd.sizeok != Sizeok.done)
1229 cd.size(e.loc);
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)
1241 if (dim != 1)
1242 return dimError(1);
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);
1253 return ex;
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();
1264 if (dim != 1)
1265 return dimError(1);
1267 auto o = (*e.args)[0];
1268 auto po = isParameter(o);
1269 auto s = getDsymbolWithoutExpCtx(o);
1270 UserAttributeDeclaration udad = null;
1271 if (po)
1273 udad = po.userAttribDecl;
1275 else if (s)
1277 if (s.isImport())
1279 s = s.isImport().mod;
1281 //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
1282 udad = s.userAttribDecl;
1284 else
1286 version (none)
1288 Expression x = isExpression(o);
1289 Type t = isType(o);
1290 if (x)
1291 printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars());
1292 if (t)
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
1308 if (dim != 1)
1309 return dimError(1);
1311 FuncDeclaration fd;
1312 TypeFunction tf = toTypeFunction((*e.args)[0], fd);
1314 if (!tf)
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
1337 if (dim != 1)
1338 return dimError(1);
1340 RootObject o = (*e.args)[0];
1341 FuncDeclaration fd;
1342 TypeFunction tf = toTypeFunction(o, fd);
1344 if (!tf)
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
1362 if (dim != 1)
1363 return dimError(1);
1365 LINK link;
1366 VarArg varargs;
1367 auto o = (*e.args)[0];
1369 FuncDeclaration fd;
1370 TypeFunction tf = toTypeFunction(o, fd);
1372 if (tf)
1374 link = tf.linkage;
1375 varargs = tf.parameterList.varargs;
1377 else
1379 if (!fd)
1381 e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars());
1382 return ErrorExp.get();
1384 link = fd.linkage;
1385 varargs = fd.getParameterList().varargs;
1387 string style;
1388 final switch (varargs)
1390 case VarArg.none: style = "none"; break;
1391 case VarArg.variadic: style = (link == LINK.d)
1392 ? "argptr"
1393 : "stdarg"; break;
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
1405 if (dim != 2)
1406 return dimError(2);
1408 auto o = (*e.args)[0];
1409 auto o1 = (*e.args)[1];
1411 ParameterList fparams;
1413 CallExp ce;
1414 if (auto exp = isExpression(o))
1415 ce = exp.isCallExp();
1417 if (ce)
1419 fparams = ce.f.getParameterList();
1421 else
1423 FuncDeclaration fd;
1424 auto tf = toTypeFunction(o, fd);
1425 if (tf)
1426 fparams = tf.parameterList;
1427 else if (fd)
1428 fparams = fd.getParameterList();
1429 else
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();
1441 StorageClass stc;
1443 // Set stc to storage class of the ith parameter
1444 auto ex = isExpression((*e.args)[1]);
1445 if (!ex)
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;
1469 void push(string s)
1471 exps.push(new StringExp(e.loc, s));
1474 if (stc & STC.auto_)
1475 push("auto");
1476 if (stc & STC.return_)
1477 push("return");
1479 if (stc & STC.out_)
1480 push("out");
1481 else if (stc & STC.in_)
1482 push("in");
1483 else if (stc & STC.ref_)
1484 push("ref");
1485 else if (stc & STC.lazy_)
1486 push("lazy");
1487 else if (stc & STC.alias_)
1488 push("alias");
1490 if (stc & STC.const_)
1491 push("const");
1492 if (stc & STC.immutable_)
1493 push("immutable");
1494 if (stc & STC.wild)
1495 push("inout");
1496 if (stc & STC.shared_)
1497 push("shared");
1498 if (stc & STC.scope_ && !(stc & STC.scopeinferred))
1499 push("scope");
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
1507 if (dim != 1)
1508 return dimError(1);
1510 LINK link;
1511 auto o = (*e.args)[0];
1513 FuncDeclaration fd;
1514 TypeFunction tf = toTypeFunction(o, fd);
1516 if (tf)
1518 link = fd ? fd.linkage : tf.linkage;
1520 else
1522 auto s = getDsymbol(o);
1523 Declaration d;
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();
1531 if (d !is null)
1532 link = d.linkage;
1533 else
1535 // Resolves forward references
1536 if (agg.sizeok != Sizeok.done)
1538 agg.size(e.loc);
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)
1548 case ClassKind.d:
1549 link = LINK.d;
1550 break;
1551 case ClassKind.cpp:
1552 link = LINK.cpp;
1553 break;
1554 case ClassKind.objc:
1555 link = LINK.objc;
1556 break;
1557 case ClassKind.c:
1558 link = LINK.c;
1559 break;
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)
1570 if (dim != 1)
1571 return dimError(1);
1573 auto o = (*e.args)[0];
1574 auto s = getDsymbol(o);
1575 if (!s)
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
1585 s = imp.mod;
1588 // https://issues.dlang.org/show_bug.cgi?id=16044
1589 if (auto p = s.isPackage())
1591 if (auto pm = p.isPackageMod())
1592 s = pm;
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)
1607 if (!sm)
1608 return 1;
1610 // skip local symbols, such as static foreach loop variables
1611 if (auto decl = sm.isDeclaration())
1613 if (decl.storage_class & STC.local)
1615 return 0;
1617 // skip 'this' context pointers
1618 else if (decl.isThisDeclaration())
1619 return 0;
1622 // https://issues.dlang.org/show_bug.cgi?id=20915
1623 // skip version and debug identifiers
1624 if (sm.isVersionSymbol() || sm.isDebugSymbol())
1625 return 0;
1627 //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
1628 if (sm.ident)
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())
1640 return 0;
1642 if (sm.ident == Id.empty)
1644 return 0;
1646 if (sm.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177
1647 return 0;
1648 if ((!sds.isModule() && !sds.isPackage()) && sm.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057
1649 return 0;
1651 //printf("\t%s\n", sm.ident.toChars());
1653 /* Skip if already present in idents[]
1655 foreach (id; *idents)
1657 if (id == sm.ident)
1658 return 0;
1660 // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
1661 debug
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);
1673 return 0;
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;
1689 assert(cb);
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());
1705 (*exps)[i] = se;
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);
1714 return ex;
1716 if (e.ident == Id.compiles)
1718 /* Determine if all the objects - types, expressions, or symbols -
1719 * compile without error
1721 if (!dim)
1722 return False();
1724 foreach (o; *e.args)
1726 uint errors = global.startGagging();
1727 Scope* sc2 = sc.push();
1728 sc2.tinst = null;
1729 sc2.minst = null;
1730 sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
1732 bool err = false;
1734 auto t = isType(o);
1735 auto ex = isExpression(o);
1736 if (t)
1738 Dsymbol s;
1739 t.resolve(e.loc, sc2, ex, t, s);
1740 if (t)
1742 t.typeSemantic(e.loc, sc2);
1743 if (t.ty == Terror)
1744 err = true;
1746 else if (s && s.errors)
1747 err = true;
1749 if (ex)
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)
1761 err = true;
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
1767 sc2.detach();
1769 if (global.endGagging(errors) || err)
1771 return False();
1774 return True();
1776 if (e.ident == Id.isSame)
1778 /* Determine if two symbols are the same
1780 if (dim != 2)
1781 return dimError(2);
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
1790 Objects ob1;
1791 ob1.push((*e.args)[0]);
1792 Objects ob2;
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)
1799 return False();
1800 foreach (immutable i; 0 .. ob1.dim)
1801 if (!ob1[i].isSame(ob2[i], sc))
1802 return False();
1803 return True();
1805 if (e.ident == Id.getUnitTests)
1807 if (dim != 1)
1808 return dimError(1);
1810 auto o = (*e.args)[0];
1811 auto s = getDsymbolWithoutExpCtx(o);
1812 if (!s)
1814 e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate",
1815 o.toChars());
1816 return ErrorExp.get();
1818 if (auto imp = s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990
1819 s = imp.mod;
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)
1847 return;
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);
1855 exps.push(e);
1859 sds.members.foreachDsymbol(&symbolDg);
1861 auto te = new TupleExp(e.loc, exps);
1862 return te.expressionSemantic(sc);
1864 if (e.ident == Id.getVirtualIndex)
1866 if (dim != 1)
1867 return dimError(1);
1869 auto o = (*e.args)[0];
1870 auto s = getDsymbolWithoutExpCtx(o);
1872 auto fd = s ? s.isFuncDeclaration() : null;
1873 if (!fd)
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)
1888 if (dim != 1)
1889 return dimError(1);
1891 auto o = (*e.args)[0];
1892 Type t = isType(o);
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)
1909 if (dim != 1)
1910 return dimError(1);
1912 auto o = (*e.args)[0];
1913 Type t = isType(o);
1914 if (!t)
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)
1926 if (dim != 1)
1927 return dimError(1);
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();
1936 se = se.toUTF8(sc);
1938 const slice = se.peekString();
1939 Expression r = target.getTargetInfo(slice.ptr, e.loc); // BUG: reliance on terminating 0
1940 if (!r)
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)
1950 if (dim != 1)
1951 return dimError(1);
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())
1986 if (d.inuse)
1988 d.error("circular reference in `__traits(GetCppNamespaces,...)`");
1989 return ErrorExp.get();
1991 d.inuse = 1;
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())
2010 return true;
2012 auto se = ns.exp.toStringExp();
2013 // extern(C++, (emptyTuple))
2014 // struct D {}
2015 // will produce a blank ident
2016 if (!se.len)
2017 continue;
2018 es.insert(0, se);
2020 return false;
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)
2029 continue;
2030 //if (!p.toParent().cppnamespace)
2031 // continue;
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();
2037 size_t i = 0;
2038 while(i < outer.dim && ((*inner)[i]) == (*outer)[i])
2039 i++;
2041 foreach_reverse (ns; (*inner)[][i .. $])
2042 exps.insert(0, ns);
2043 continue;
2046 if (p.isNspace())
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())
2053 d.inuse = 0;
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)
2060 //No args are valid
2061 if (e.args)
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();
2071 if (!fd)
2073 e.error("`__traits(parameters)` may only be used inside a function");
2074 return ErrorExp.get();
2077 auto tf = fd.type.isTypeFunction();
2078 assert(tf);
2079 auto exps = new Expressions(0);
2080 int addParameterDG(size_t idx, Parameter x)
2082 assert(x.ident);
2083 exps.push(new IdentifierExp(e.loc, x.ident));
2084 return 0;
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);
2098 if (!seed.length)
2099 return null;
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);
2107 else
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())
2124 return fd;
2128 else if (auto ea = isExpression(oarg))
2130 if (ea.op == EXP.function_)
2132 if (auto fe = ea.isFuncExp())
2133 return fe.fd;
2136 return null;
2139 auto l1 = isLambda(o1);
2140 auto l2 = isLambda(o2);
2142 if (l1 && l2)
2144 import dmd.lambdacomp : isSameFuncLiteral;
2145 if (isSameFuncLiteral(l1, l2, sc))
2146 return true;
2149 // issue 12001, allow isSame, <BasicType>, <BasicType>
2150 Type t1 = isType(o1);
2151 Type t2 = isType(o2);
2152 if (t1 && t2 && t1.equals(t2))
2153 return true;
2155 auto s1 = getDsymbol(o1);
2156 auto s2 = getDsymbol(o2);
2157 //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars());
2158 version (none)
2160 printf("o1: %p\n", o1);
2161 printf("o2: %p\n", o2);
2162 if (!s1)
2164 if (auto ea = isExpression(o1))
2165 printf("%s\n", ea.toChars());
2166 if (auto ta = isType(o1))
2167 printf("%s\n", ta.toChars());
2168 return false;
2170 else
2171 printf("%s %s\n", s1.kind(), s1.toChars());
2173 if (!s1 && !s2)
2175 auto ea1 = isExpression(o1);
2176 auto ea2 = isExpression(o2);
2177 if (ea1 && ea2)
2179 if (ea1.equals(ea2))
2180 return true;
2183 if (!s1 || !s2)
2184 return false;
2186 s1 = s1.toAlias();
2187 s2 = s2.toAlias();
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))
2203 return true;
2205 if (s1 == s2)
2206 return true;
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();
2211 if (!overSet1)
2212 return false;
2214 auto overSet2 = s2.isOverloadSet();
2215 if (!overSet2)
2216 return false;
2218 if (overSet1.a.dim != overSet2.a.dim)
2219 return false;
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
2224 Lnext:
2225 foreach(overload1; overSet1.a)
2227 foreach(overload2; overSet2.a)
2229 if (overload1 == overload2)
2230 continue Lnext;
2232 return false;
2234 return true;