]> git.ipfire.org Git - people/ms/gcc.git/blame - gcc/d/dmd/traits.d
d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[people/ms/gcc.git] / gcc / d / dmd / traits.d
CommitLineData
5fee5ec3
IB
1/**
2 * Handle introspection functionality of the `__traits()` construct.
3 *
4 * Specification: $(LINK2 https://dlang.org/spec/traits.html, Traits)
5 *
f99303eb 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
c43b5909
IB
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5fee5ec3
IB
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
12 */
13
14module dmd.traits;
15
16import core.stdc.stdio;
17
18import dmd.aggregate;
19import dmd.arraytypes;
20import dmd.astcodegen;
21import dmd.astenums;
22import dmd.attrib;
23import dmd.canthrow;
24import dmd.dclass;
25import dmd.declaration;
26import dmd.dimport;
27import dmd.dmangle;
28import dmd.dmodule;
29import dmd.dscope;
30import dmd.dsymbol;
31import dmd.dsymbolsem;
32import dmd.dtemplate;
33import dmd.errors;
34import dmd.expression;
35import dmd.expressionsem;
36import dmd.func;
37import dmd.globals;
38import dmd.hdrgen;
39import dmd.id;
40import dmd.identifier;
f99303eb 41import dmd.location;
5fee5ec3
IB
42import dmd.mtype;
43import dmd.nogc;
44import dmd.parse;
45import dmd.root.array;
46import dmd.root.speller;
47import dmd.root.stringtable;
48import dmd.target;
49import dmd.tokens;
50import dmd.typesem;
51import dmd.visitor;
52import dmd.root.rootobject;
0fb57034 53import dmd.common.outbuffer;
5fee5ec3
IB
54import dmd.root.string;
55
56enum LOGSEMANTIC = false;
57
58/************************ TraitsExp ************************************/
59
60/**************************************
61 * Convert `Expression` or `Type` to corresponding `Dsymbol`, additionally
62 * stripping off expression contexts.
63 *
64 * Some symbol related `__traits` ignore arguments expression contexts.
65 * For example:
66 * ----
67 * struct S { void f() {} }
68 * S s;
69 * pragma(msg, __traits(isNested, s.f));
70 * // s.f is `DotVarExp`, but `__traits(isNested)`` needs a `FuncDeclaration`.
71 * ----
72 *
73 * This is used for that common `__traits` behavior.
74 *
75 * Input:
76 * oarg object to get the symbol for
77 * Returns:
78 * Dsymbol the corresponding symbol for oarg
79 */
80private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
81{
82 if (auto e = isExpression(oarg))
83 {
235d5a96
IB
84 if (auto dve = e.isDotVarExp())
85 return dve.var;
86 if (auto dte = e.isDotTemplateExp())
87 return dte.td;
5fee5ec3
IB
88 }
89 return getDsymbol(oarg);
90}
91
5fee5ec3
IB
92/**
93 * get an array of size_t values that indicate possible pointer words in memory
94 * if interpreted as the type given as argument
fbdaa581 95 * Returns: the size of the type in bytes, ulong.max on error
5fee5ec3 96 */
fbdaa581 97ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
5fee5ec3 98{
fbdaa581 99 ulong sz;
5fee5ec3
IB
100 if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
101 sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
102 else
103 sz = t.size(loc);
104 if (sz == SIZE_INVALID)
fbdaa581 105 return ulong.max;
5fee5ec3
IB
106
107 const sz_size_t = Type.tsize_t.size(loc);
108 if (sz > sz.max - sz_size_t)
109 {
110 error(loc, "size overflow for type `%s`", t.toChars());
fbdaa581 111 return ulong.max;
5fee5ec3
IB
112 }
113
fbdaa581
IB
114 ulong bitsPerWord = sz_size_t * 8;
115 ulong cntptr = (sz + sz_size_t - 1) / sz_size_t;
116 ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
5fee5ec3
IB
117
118 data.setDim(cast(size_t)cntdata);
119 data.zero();
120
121 extern (C++) final class PointerBitmapVisitor : Visitor
122 {
123 alias visit = Visitor.visit;
124 public:
8da8c7d3 125 extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) scope
5fee5ec3
IB
126 {
127 this.data = _data;
128 this.sz_size_t = _sz_size_t;
129 }
130
fbdaa581 131 void setpointer(ulong off)
5fee5ec3 132 {
fbdaa581 133 ulong ptroff = off / sz_size_t;
5fee5ec3
IB
134 (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t));
135 }
136
137 override void visit(Type t)
138 {
139 Type tb = t.toBasetype();
140 if (tb != t)
141 tb.accept(this);
142 }
143
144 override void visit(TypeError t)
145 {
146 visit(cast(Type)t);
147 }
148
149 override void visit(TypeNext t)
150 {
151 assert(0);
152 }
153
154 override void visit(TypeBasic t)
155 {
156 if (t.ty == Tvoid)
157 setpointer(offset);
158 }
159
160 override void visit(TypeVector t)
161 {
162 }
163
164 override void visit(TypeArray t)
165 {
166 assert(0);
167 }
168
169 override void visit(TypeSArray t)
170 {
fbdaa581
IB
171 ulong arrayoff = offset;
172 ulong nextsize = t.next.size();
5fee5ec3
IB
173 if (nextsize == SIZE_INVALID)
174 error = true;
fbdaa581
IB
175 ulong dim = t.dim.toInteger();
176 for (ulong i = 0; i < dim; i++)
5fee5ec3
IB
177 {
178 offset = arrayoff + i * nextsize;
179 t.next.accept(this);
180 }
181 offset = arrayoff;
182 }
183
184 override void visit(TypeDArray t)
185 {
186 setpointer(offset + sz_size_t);
187 }
188
189 // dynamic array is {length,ptr}
190 override void visit(TypeAArray t)
191 {
192 setpointer(offset);
193 }
194
195 override void visit(TypePointer t)
196 {
197 if (t.nextOf().ty != Tfunction) // don't mark function pointers
198 setpointer(offset);
199 }
200
201 override void visit(TypeReference t)
202 {
203 setpointer(offset);
204 }
205
206 override void visit(TypeClass t)
207 {
208 setpointer(offset);
209 }
210
211 override void visit(TypeFunction t)
212 {
213 }
214
215 override void visit(TypeDelegate t)
216 {
217 setpointer(offset);
218 }
219
220 // delegate is {context, function}
221 override void visit(TypeQualified t)
222 {
223 assert(0);
224 }
225
226 // assume resolved
227 override void visit(TypeIdentifier t)
228 {
229 assert(0);
230 }
231
232 override void visit(TypeInstance t)
233 {
234 assert(0);
235 }
236
237 override void visit(TypeTypeof t)
238 {
239 assert(0);
240 }
241
242 override void visit(TypeReturn t)
243 {
244 assert(0);
245 }
246
247 override void visit(TypeEnum t)
248 {
249 visit(cast(Type)t);
250 }
251
252 override void visit(TypeTuple t)
253 {
254 visit(cast(Type)t);
255 }
256
257 override void visit(TypeSlice t)
258 {
259 assert(0);
260 }
261
262 override void visit(TypeNull t)
263 {
264 // always a null pointer
265 }
266
267 override void visit(TypeStruct t)
268 {
fbdaa581 269 ulong structoff = offset;
5fee5ec3
IB
270 foreach (v; t.sym.fields)
271 {
272 offset = structoff + v.offset;
273 if (v.type.ty == Tclass)
274 setpointer(offset);
275 else
276 v.type.accept(this);
277 }
278 offset = structoff;
279 }
280
281 // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
282 void visitClass(TypeClass t)
283 {
fbdaa581 284 ulong classoff = offset;
5fee5ec3
IB
285 // skip vtable-ptr and monitor
286 if (t.sym.baseClass)
287 visitClass(cast(TypeClass)t.sym.baseClass.type);
288 foreach (v; t.sym.fields)
289 {
290 offset = classoff + v.offset;
291 v.type.accept(this);
292 }
293 offset = classoff;
294 }
295
fbdaa581
IB
296 Array!(ulong)* data;
297 ulong offset;
298 ulong sz_size_t;
5fee5ec3
IB
299 bool error;
300 }
301
302 scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t);
303 if (t.ty == Tclass)
304 pbv.visitClass(cast(TypeClass)t);
305 else
306 t.accept(pbv);
fbdaa581 307 return pbv.error ? ulong.max : sz;
5fee5ec3
IB
308}
309
310/**
311 * get an array of size_t values that indicate possible pointer words in memory
312 * if interpreted as the type given as argument
313 * the first array element is the size of the type for independent interpretation
314 * of the array
315 * following elements bits represent one word (4/8 bytes depending on the target
316 * architecture). If set the corresponding memory might contain a pointer/reference.
317 *
318 * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
319 */
320private Expression pointerBitmap(TraitsExp e)
321{
6d799f0a 322 if (!e.args || e.args.length != 1)
5fee5ec3
IB
323 {
324 error(e.loc, "a single type expected for trait pointerBitmap");
325 return ErrorExp.get();
326 }
327
328 Type t = getType((*e.args)[0]);
329 if (!t)
330 {
331 error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
332 return ErrorExp.get();
333 }
334
fbdaa581
IB
335 Array!(ulong) data;
336 ulong sz = getTypePointerBitmap(e.loc, t, &data);
337 if (sz == ulong.max)
5fee5ec3
IB
338 return ErrorExp.get();
339
6d799f0a 340 auto exps = new Expressions(data.length + 1);
5fee5ec3 341 (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t);
6d799f0a 342 foreach (size_t i; 1 .. exps.length)
5fee5ec3
IB
343 (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t);
344
6d799f0a 345 auto ale = new ArrayLiteralExp(e.loc, Type.tsize_t.sarrayOf(data.length + 1), exps);
5fee5ec3
IB
346 return ale;
347}
348
349Expression semanticTraits(TraitsExp e, Scope* sc)
350{
351 static if (LOGSEMANTIC)
352 {
353 printf("TraitsExp::semantic() %s\n", e.toChars());
354 }
355
356 if (e.ident != Id.compiles &&
357 e.ident != Id.isSame &&
358 e.ident != Id.identifier &&
359 e.ident != Id.getProtection && e.ident != Id.getVisibility &&
360 e.ident != Id.getAttributes)
361 {
362 // Pretend we're in a deprecated scope so that deprecation messages
363 // aren't triggered when checking if a symbol is deprecated
364 const save = sc.stc;
365 if (e.ident == Id.isDeprecated)
366 sc.stc |= STC.deprecated_;
367 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 1))
368 {
369 sc.stc = save;
370 return ErrorExp.get();
371 }
372 sc.stc = save;
373 }
6d799f0a 374 size_t dim = e.args ? e.args.length : 0;
5fee5ec3
IB
375
376 Expression dimError(int expected)
377 {
378 e.error("expected %d arguments for `%s` but had %d", expected, e.ident.toChars(), cast(int)dim);
379 return ErrorExp.get();
380 }
381
382 static IntegerExp True()
383 {
384 return IntegerExp.createBool(true);
385 }
386
387 static IntegerExp False()
388 {
389 return IntegerExp.createBool(false);
390 }
391
392 /********
393 * Gets the function type from a given AST node
394 * if the node is a function of some sort.
395 * Params:
396 * o = an AST node to check for a `TypeFunction`
397 * fdp = if `o` is a FuncDeclaration then fdp is set to that, otherwise `null`
398 * Returns:
399 * a type node if `o` is a declaration of
400 * a delegate, function, function-pointer or a variable of the former.
401 * Otherwise, `null`.
402 */
403 static TypeFunction toTypeFunction(RootObject o, out FuncDeclaration fdp)
404 {
405 Type t;
406 if (auto s = getDsymbolWithoutExpCtx(o))
407 {
408 if (auto fd = s.isFuncDeclaration())
409 {
410 t = fd.type;
411 fdp = fd;
412 }
413 else if (auto vd = s.isVarDeclaration())
414 t = vd.type;
415 else
416 t = isType(o);
417 }
418 else
419 t = isType(o);
420
421 if (t)
422 {
423 if (auto tf = t.isFunction_Delegate_PtrToFunction())
424 return tf;
425 }
426
427 return null;
428 }
429
430 IntegerExp isX(T)(bool delegate(T) fp)
431 {
432 if (!dim)
433 return False();
434 foreach (o; *e.args)
435 {
436 static if (is(T == Type))
437 auto y = getType(o);
438
439 static if (is(T : Dsymbol))
440 {
441 auto s = getDsymbolWithoutExpCtx(o);
442 if (!s)
443 return False();
444 }
445 static if (is(T == Dsymbol))
446 alias y = s;
447 static if (is(T == Declaration))
448 auto y = s.isDeclaration();
449 static if (is(T == FuncDeclaration))
450 auto y = s.isFuncDeclaration();
451
452 if (!y || !fp(y))
453 return False();
454 }
455 return True();
456 }
457
458 alias isTypeX = isX!Type;
459 alias isDsymX = isX!Dsymbol;
460 alias isDeclX = isX!Declaration;
461 alias isFuncX = isX!FuncDeclaration;
462
463 Expression isPkgX(bool function(Package) fp)
464 {
465 return isDsymX((Dsymbol sym) {
466 Package p = resolveIsPackage(sym);
467 return (p !is null) && fp(p);
468 });
469 }
470
471 if (e.ident == Id.isArithmetic)
472 {
473 return isTypeX(t => t.isintegral() || t.isfloating());
474 }
475 if (e.ident == Id.isFloating)
476 {
477 return isTypeX(t => t.isfloating());
478 }
479 if (e.ident == Id.isIntegral)
480 {
481 return isTypeX(t => t.isintegral());
482 }
483 if (e.ident == Id.isScalar)
484 {
485 return isTypeX(t => t.isscalar());
486 }
487 if (e.ident == Id.isUnsigned)
488 {
489 return isTypeX(t => t.isunsigned());
490 }
491 if (e.ident == Id.isAssociativeArray)
492 {
493 return isTypeX(t => t.toBasetype().ty == Taarray);
494 }
495 if (e.ident == Id.isDeprecated)
496 {
1027dc45
IB
497 if (isTypeX(t => t.iscomplex() || t.isimaginary()).toBool().hasValue(true))
498 return True();
5fee5ec3
IB
499 return isDsymX(t => t.isDeprecated());
500 }
501 if (e.ident == Id.isFuture)
502 {
503 return isDeclX(t => t.isFuture());
504 }
505 if (e.ident == Id.isStaticArray)
506 {
507 return isTypeX(t => t.toBasetype().ty == Tsarray);
508 }
509 if (e.ident == Id.isAbstractClass)
510 {
511 return isTypeX(t => t.toBasetype().ty == Tclass &&
512 (cast(TypeClass)t.toBasetype()).sym.isAbstract());
513 }
514 if (e.ident == Id.isFinalClass)
515 {
516 return isTypeX(t => t.toBasetype().ty == Tclass &&
517 ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0);
518 }
519 if (e.ident == Id.isTemplate)
520 {
521 if (dim != 1)
522 return dimError(1);
523
524 return isDsymX((s)
525 {
526 if (!s.toAlias().isOverloadable())
527 return false;
528 return overloadApply(s,
529 sm => sm.isTemplateDeclaration() !is null) != 0;
530 });
531 }
532 if (e.ident == Id.isPOD)
533 {
534 if (dim != 1)
535 return dimError(1);
536
537 auto o = (*e.args)[0];
538 auto t = isType(o);
539 if (!t)
540 {
541 e.error("type expected as second argument of __traits `%s` instead of `%s`",
542 e.ident.toChars(), o.toChars());
543 return ErrorExp.get();
544 }
545
546 Type tb = t.baseElemOf();
547 if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
548 {
549 return sd.isPOD() ? True() : False();
550 }
551 return True();
552 }
553 if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit)
554 {
555 if (dim != 1)
556 return dimError(1);
557
558 auto o = (*e.args)[0];
559 auto t = isType(o);
560 if (!t)
561 {
562 e.error("type expected as second argument of __traits `%s` instead of `%s`",
563 e.ident.toChars(), o.toChars());
564 return ErrorExp.get();
565 }
566
567 Type tb = t.baseElemOf();
568 if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
569 {
570 return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
571 : (sd.hasCopyCtor ? True() : False());
572 }
573 return False();
574 }
575 if (e.ident == Id.isCopyable)
576 {
577 if (dim != 1)
578 return dimError(1);
579
580 auto o = (*e.args)[0];
581 auto t = isType(o);
582 if (!t)
583 {
584 e.error("type expected as second argument of __traits `%s` instead of `%s`",
585 e.ident.toChars(), o.toChars());
586 return ErrorExp.get();
587 }
588
589 t = t.toBasetype(); // get the base in case `t` is an `enum`
590
591 if (auto ts = t.isTypeStruct())
592 {
593 ts.sym.dsymbolSemantic(sc);
594 }
595
596 return isCopyable(t) ? True() : False();
597 }
598
599 if (e.ident == Id.isNested)
600 {
601 if (dim != 1)
602 return dimError(1);
603
604 auto o = (*e.args)[0];
605 auto s = getDsymbolWithoutExpCtx(o);
606 if (!s)
607 {
608 }
609 else if (auto ad = s.isAggregateDeclaration())
610 {
611 return ad.isNested() ? True() : False();
612 }
613 else if (auto fd = s.isFuncDeclaration())
614 {
615 return fd.isNested() ? True() : False();
616 }
617
618 e.error("aggregate or function expected instead of `%s`", o.toChars());
619 return ErrorExp.get();
620 }
621 if (e.ident == Id.isDisabled)
622 {
623 if (dim != 1)
624 return dimError(1);
625
626 return isDeclX(f => f.isDisabled());
627 }
628 if (e.ident == Id.isAbstractFunction)
629 {
630 if (dim != 1)
631 return dimError(1);
632
633 return isFuncX(f => f.isAbstract());
634 }
635 if (e.ident == Id.isVirtualFunction)
636 {
8da8c7d3
IB
637 // @@@DEPRECATED2.121@@@
638 // Deprecated in 2.101 - Can be removed from 2.121
639 e.deprecation("`traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead");
640
5fee5ec3
IB
641 if (dim != 1)
642 return dimError(1);
643
644 return isFuncX(f => f.isVirtual());
645 }
646 if (e.ident == Id.isVirtualMethod)
647 {
648 if (dim != 1)
649 return dimError(1);
650
651 return isFuncX(f => f.isVirtualMethod());
652 }
653 if (e.ident == Id.isFinalFunction)
654 {
655 if (dim != 1)
656 return dimError(1);
657
658 return isFuncX(f => f.isFinalFunc());
659 }
660 if (e.ident == Id.isOverrideFunction)
661 {
662 if (dim != 1)
663 return dimError(1);
664
665 return isFuncX(f => f.isOverride());
666 }
667 if (e.ident == Id.isStaticFunction)
668 {
669 if (dim != 1)
670 return dimError(1);
671
672 return isFuncX(f => !f.needThis() && !f.isNested());
673 }
674 if (e.ident == Id.isModule)
675 {
676 if (dim != 1)
677 return dimError(1);
678
679 return isPkgX(p => p.isModule() || p.isPackageMod());
680 }
681 if (e.ident == Id.isPackage)
682 {
683 if (dim != 1)
684 return dimError(1);
685
686 return isPkgX(p => p.isModule() is null);
687 }
688 if (e.ident == Id.isRef)
689 {
690 if (dim != 1)
691 return dimError(1);
692
693 return isDeclX(d => d.isRef());
694 }
695 if (e.ident == Id.isOut)
696 {
697 if (dim != 1)
698 return dimError(1);
699
700 return isDeclX(d => d.isOut());
701 }
702 if (e.ident == Id.isLazy)
703 {
704 if (dim != 1)
705 return dimError(1);
706
707 return isDeclX(d => (d.storage_class & STC.lazy_) != 0);
708 }
709 if (e.ident == Id.identifier)
710 {
711 // Get identifier for symbol as a string literal
712 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
713 * a symbol should not be folded to a constant.
714 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
715 */
716 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 2))
717 return ErrorExp.get();
718 if (dim != 1)
719 return dimError(1);
720
721 auto o = (*e.args)[0];
722 Identifier id;
723 if (auto po = isParameter(o))
724 {
725 if (!po.ident)
726 {
727 e.error("argument `%s` has no identifier", po.type.toChars());
728 return ErrorExp.get();
729 }
730 id = po.ident;
731 }
732 else
733 {
734 Dsymbol s = getDsymbolWithoutExpCtx(o);
735 if (!s || !s.ident)
736 {
737 e.error("argument `%s` has no identifier", o.toChars());
738 return ErrorExp.get();
739 }
740 id = s.ident;
741 }
742
743 auto se = new StringExp(e.loc, id.toString());
744 return se.expressionSemantic(sc);
745 }
8da8c7d3
IB
746 if (e.ident == Id.fullyQualifiedName) // https://dlang.org/spec/traits.html#fullyQualifiedName
747 {
748 if (dim != 1)
749 return dimError(1);
750
751 Scope* sc2 = sc.push();
752 sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
753 bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
754 sc2.pop();
755 if (!ok)
756 return ErrorExp.get();
757
758 const(char)[] fqn;
759 auto o = (*e.args)[0];
760 if (auto s = getDsymbolWithoutExpCtx(o))
761 {
762 if (s.semanticRun == PASS.initial)
763 s.dsymbolSemantic(null);
764
765 fqn = s.toPrettyChars().toDString();
766 }
767 else if (auto t = getType(o))
768 {
769 fqn = t.toPrettyChars(true).toDString();
770 }
771 else
772 {
773 if (!isError(o))
774 e.error("argument `%s` has no identifier", o.toChars());
775 return ErrorExp.get();
776 }
777 assert(fqn);
778 auto se = new StringExp(e.loc, fqn);
779 return se.expressionSemantic(sc);
780
781 }
5fee5ec3
IB
782 if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
783 {
784 if (dim != 1)
785 return dimError(1);
786
787 Scope* sc2 = sc.push();
788 sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
789 bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
790 sc2.pop();
791 if (!ok)
792 return ErrorExp.get();
793
794 auto o = (*e.args)[0];
795 auto s = getDsymbolWithoutExpCtx(o);
796 if (!s)
797 {
798 if (!isError(o))
799 e.error("argument `%s` has no visibility", o.toChars());
800 return ErrorExp.get();
801 }
235d5a96 802 if (s.semanticRun == PASS.initial)
5fee5ec3
IB
803 s.dsymbolSemantic(null);
804
805 auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names)
806 assert(protName);
807 auto se = new StringExp(e.loc, protName);
808 return se.expressionSemantic(sc);
809 }
810 if (e.ident == Id.parent)
811 {
812 if (dim != 1)
813 return dimError(1);
814
815 auto o = (*e.args)[0];
816 auto s = getDsymbolWithoutExpCtx(o);
817 if (s)
818 {
819 // https://issues.dlang.org/show_bug.cgi?id=12496
820 // Consider:
821 // class T1
822 // {
823 // class C(uint value) { }
824 // }
825 // __traits(parent, T1.C!2)
826 if (auto ad = s.isAggregateDeclaration()) // `s` is `C`
827 {
828 if (ad.isNested()) // `C` is nested
829 {
830 if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not
831 {
832 if (p.isTemplateInstance()) // `C!2` is a template instance
833 {
834 s = p; // `C!2`'s parent is `T1`
835 auto td = (cast(TemplateInstance)p).tempdecl;
836 if (td)
837 s = td; // get the declaration context just in case there's two contexts
838 }
839 }
840 }
841 }
842
843 if (auto fd = s.isFuncDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=8943
844 s = fd.toAliasFunc();
845 if (!s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=8922
846 s = s.toParent();
847 }
848 if (!s || s.isImport())
849 {
850 e.error("argument `%s` has no parent", o.toChars());
851 return ErrorExp.get();
852 }
853
854 if (auto f = s.isFuncDeclaration())
855 {
856 if (auto td = getFuncTemplateDecl(f))
857 {
858 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
859 td = td.overroot; // then get the start
860 Expression ex = new TemplateExp(e.loc, td, f);
861 ex = ex.expressionSemantic(sc);
862 return ex;
863 }
864 if (auto fld = f.isFuncLiteralDeclaration())
865 {
866 // Directly translate to VarExp instead of FuncExp
867 Expression ex = new VarExp(e.loc, fld, true);
868 return ex.expressionSemantic(sc);
869 }
870 }
871 return symbolToExp(s, e.loc, sc, false);
872 }
873 if (e.ident == Id.child)
874 {
875 if (dim != 2)
876 return dimError(2);
877
878 Expression ex;
879 auto op = (*e.args)[0];
880 if (auto symp = getDsymbol(op))
881 ex = new DsymbolExp(e.loc, symp);
882 else if (auto exp = op.isExpression())
883 ex = exp;
884 else
885 {
886 e.error("symbol or expression expected as first argument of __traits `child` instead of `%s`", op.toChars());
887 return ErrorExp.get();
888 }
889
890 ex = ex.expressionSemantic(sc);
891 auto oc = (*e.args)[1];
892 auto symc = getDsymbol(oc);
893 if (!symc)
894 {
895 e.error("symbol expected as second argument of __traits `child` instead of `%s`", oc.toChars());
896 return ErrorExp.get();
897 }
898
899 if (auto d = symc.isDeclaration())
900 ex = new DotVarExp(e.loc, ex, d);
901 else if (auto td = symc.isTemplateDeclaration())
902 ex = new DotExp(e.loc, ex, new TemplateExp(e.loc, td));
903 else if (auto ti = symc.isScopeDsymbol())
904 ex = new DotExp(e.loc, ex, new ScopeExp(e.loc, ti));
905 else
906 assert(0);
907
908 ex = ex.expressionSemantic(sc);
909 return ex;
910 }
911 if (e.ident == Id.toType)
912 {
913 if (dim != 1)
914 return dimError(1);
915
916 auto ex = isExpression((*e.args)[0]);
917 if (!ex)
918 {
919 e.error("expression expected as second argument of __traits `%s`", e.ident.toChars());
920 return ErrorExp.get();
921 }
922 ex = ex.ctfeInterpret();
923
924 StringExp se = semanticString(sc, ex, "__traits(toType, string)");
925 if (!se)
926 {
927 return ErrorExp.get();
928 }
929 Type t = decoToType(se.toUTF8(sc).peekString());
930 if (!t)
931 {
932 e.error("cannot determine `%s`", e.toChars());
933 return ErrorExp.get();
934 }
935 return (new TypeExp(e.loc, t)).expressionSemantic(sc);
936 }
937 if (e.ident == Id.hasMember ||
938 e.ident == Id.getMember ||
939 e.ident == Id.getOverloads ||
940 e.ident == Id.getVirtualMethods ||
941 e.ident == Id.getVirtualFunctions)
942 {
943 if (dim != 2 && !(dim == 3 && e.ident == Id.getOverloads))
944 return dimError(2);
945
946 auto o = (*e.args)[0];
947 auto ex = isExpression((*e.args)[1]);
948 if (!ex)
949 {
950 e.error("expression expected as second argument of __traits `%s`", e.ident.toChars());
951 return ErrorExp.get();
952 }
953 ex = ex.ctfeInterpret();
954
955 bool includeTemplates = false;
956 if (dim == 3 && e.ident == Id.getOverloads)
957 {
958 auto b = isExpression((*e.args)[2]);
959 b = b.ctfeInterpret();
960 if (!b.type.equals(Type.tbool))
961 {
962 e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars());
963 return ErrorExp.get();
964 }
d7569187 965 includeTemplates = b.toBool().get();
5fee5ec3
IB
966 }
967
968 StringExp se = ex.toStringExp();
969 if (!se || se.len == 0)
970 {
971 e.error("string expected as second argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars());
972 return ErrorExp.get();
973 }
974 se = se.toUTF8(sc);
975
976 if (se.sz != 1)
977 {
978 e.error("string must be chars");
979 return ErrorExp.get();
980 }
981 auto id = Identifier.idPool(se.peekString());
982
983 /* Prefer a Type, because getDsymbol(Type) can lose type modifiers.
984 Then a Dsymbol, because it might need some runtime contexts.
985 */
986
987 Dsymbol sym = getDsymbol(o);
988 if (auto t = isType(o))
989 ex = typeDotIdExp(e.loc, t, id);
990 else if (sym)
991 {
992 if (e.ident == Id.hasMember)
993 {
994 if (auto sm = sym.search(e.loc, id))
995 return True();
996 }
997 ex = new DsymbolExp(e.loc, sym);
998 ex = new DotIdExp(e.loc, ex, id);
999 }
1000 else if (auto ex2 = isExpression(o))
1001 ex = new DotIdExp(e.loc, ex2, id);
1002 else
1003 {
1004 e.error("invalid first argument");
1005 return ErrorExp.get();
1006 }
1007
1008 // ignore symbol visibility and disable access checks for these traits
1009 Scope* scx = sc.push();
1010 scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck;
1011 scope (exit) scx.pop();
1012
1013 if (e.ident == Id.hasMember)
1014 {
1015 /* Take any errors as meaning it wasn't found
1016 */
1017 ex = ex.trySemantic(scx);
1018 return ex ? True() : False();
1019 }
1020 else if (e.ident == Id.getMember)
1021 {
235d5a96 1022 if (auto die = ex.isDotIdExp())
5fee5ec3 1023 // Prevent semantic() from replacing Symbol with its initializer
235d5a96 1024 die.wantsym = true;
5fee5ec3
IB
1025 ex = ex.expressionSemantic(scx);
1026 return ex;
1027 }
1028 else if (e.ident == Id.getVirtualFunctions ||
1029 e.ident == Id.getVirtualMethods ||
1030 e.ident == Id.getOverloads)
1031 {
1032 uint errors = global.errors;
1033 Expression eorig = ex;
1034 ex = ex.expressionSemantic(scx);
1035 if (errors < global.errors)
1036 e.error("`%s` cannot be resolved", eorig.toChars());
1037
8da8c7d3
IB
1038 if (e.ident == Id.getVirtualFunctions)
1039 {
1040 // @@@DEPRECATED2.121@@@
1041 // Deprecated in 2.101 - Can be removed from 2.121
1042 e.deprecation("`traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead");
1043 }
1044
5fee5ec3
IB
1045 /* Create tuple of functions of ex
1046 */
1047 auto exps = new Expressions();
1048 Dsymbol f;
1049 if (auto ve = ex.isVarExp)
1050 {
1051 if (ve.var.isFuncDeclaration() || ve.var.isOverDeclaration())
1052 f = ve.var;
1053 ex = null;
1054 }
1055 else if (auto dve = ex.isDotVarExp)
1056 {
1057 if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration())
1058 f = dve.var;
9c7d5e88 1059 if (dve.e1.op == EXP.dotType || dve.e1.op == EXP.this_)
5fee5ec3
IB
1060 ex = null;
1061 else
1062 ex = dve.e1;
1063 }
1064 else if (auto te = ex.isTemplateExp)
1065 {
1066 auto td = te.td;
1067 f = td;
1068 if (td && td.funcroot)
1069 f = td.funcroot;
1070 ex = null;
1071 }
1072 else if (auto dte = ex.isDotTemplateExp)
1073 {
1074 auto td = dte.td;
1075 f = td;
1076 if (td && td.funcroot)
1077 f = td.funcroot;
1078 ex = null;
9c7d5e88 1079 if (dte.e1.op != EXP.dotType && dte.e1.op != EXP.this_)
5fee5ec3
IB
1080 ex = dte.e1;
1081 }
1082 bool[string] funcTypeHash;
1083
1084 /* Compute the function signature and insert it in the
1085 * hashtable, if not present. This is needed so that
1086 * traits(getOverlods, F3, "visit") does not count `int visit(int)`
1087 * twice in the following example:
1088 *
1089 * =============================================
1090 * interface F1 { int visit(int);}
1091 * interface F2 { int visit(int); void visit(); }
1092 * interface F3 : F2, F1 {}
1093 *==============================================
1094 */
1095 void insertInterfaceInheritedFunction(FuncDeclaration fd, Expression e)
1096 {
1097 auto signature = fd.type.toString();
1098 //printf("%s - %s\n", fd.toChars, signature);
1099 if (signature !in funcTypeHash)
1100 {
1101 funcTypeHash[signature] = true;
1102 exps.push(e);
1103 }
1104 }
1105
1106 int dg(Dsymbol s)
1107 {
1108 auto fd = s.isFuncDeclaration();
1109 if (!fd)
1110 {
1111 if (includeTemplates)
1112 {
1113 if (auto td = s.isTemplateDeclaration())
1114 {
1115 // if td is part of an overload set we must take a copy
1116 // which shares the same `instances` cache but without
1117 // `overroot` and `overnext` set to avoid overload
1118 // behaviour in the result.
1119 if (td.overnext !is null)
1120 {
1121 if (td.instances is null)
1122 {
1123 // create an empty AA just to copy it
1124 scope ti = new TemplateInstance(Loc.initial, Id.empty, null);
1125 auto tib = TemplateInstanceBox(ti);
1126 td.instances[tib] = null;
1127 td.instances.clear();
1128 }
1129 td = td.syntaxCopy(null);
1130 import core.stdc.string : memcpy;
1131 memcpy(cast(void*) td, cast(void*) s,
1132 __traits(classInstanceSize, TemplateDeclaration));
1133 td.overroot = null;
1134 td.overnext = null;
1135 }
1136
1137 auto e = ex ? new DotTemplateExp(Loc.initial, ex, td)
1138 : new DsymbolExp(Loc.initial, td);
1139 exps.push(e);
1140 }
1141 }
1142 return 0;
1143 }
1144 if (e.ident == Id.getVirtualFunctions && !fd.isVirtual())
1145 return 0;
1146 if (e.ident == Id.getVirtualMethods && !fd.isVirtualMethod())
1147 return 0;
1148
1149 auto fa = new FuncAliasDeclaration(fd.ident, fd, false);
1150 fa.visibility = fd.visibility;
1151
1152 auto e = ex ? new DotVarExp(Loc.initial, ex, fa, false)
1153 : new DsymbolExp(Loc.initial, fa, false);
1154
1155 // if the parent is an interface declaration
1156 // we must check for functions with the same signature
1157 // in different inherited interfaces
1158 if (sym && sym.isInterfaceDeclaration())
1159 insertInterfaceInheritedFunction(fd, e);
1160 else
1161 exps.push(e);
1162 return 0;
1163 }
1164
1165 InterfaceDeclaration ifd = null;
1166 if (sym)
1167 ifd = sym.isInterfaceDeclaration();
1168 // If the symbol passed as a parameter is an
1169 // interface that inherits other interfaces
1170 overloadApply(f, &dg);
1171 if (ifd && ifd.interfaces && f)
1172 {
1173 // check the overloads of each inherited interface individually
1174 foreach (bc; ifd.interfaces)
1175 {
1176 if (auto fd = bc.sym.search(e.loc, f.ident))
1177 overloadApply(fd, &dg);
1178 }
1179 }
1180
1181 auto tup = new TupleExp(e.loc, exps);
1182 return tup.expressionSemantic(scx);
1183 }
1184 else
1185 assert(0);
1186 }
5eb9927a 1187 if (e.ident == Id.classInstanceSize || e.ident == Id.classInstanceAlignment)
5fee5ec3
IB
1188 {
1189 if (dim != 1)
1190 return dimError(1);
1191
1192 auto o = (*e.args)[0];
1193 auto s = getDsymbol(o);
1194 auto cd = s ? s.isClassDeclaration() : null;
1195 if (!cd)
1196 {
1197 e.error("first argument is not a class");
1198 return ErrorExp.get();
1199 }
1200 if (cd.sizeok != Sizeok.done)
1201 {
1202 cd.size(e.loc);
1203 }
1204 if (cd.sizeok != Sizeok.done)
1205 {
1206 e.error("%s `%s` is forward referenced", cd.kind(), cd.toChars());
1207 return ErrorExp.get();
1208 }
1209
5eb9927a 1210 return new IntegerExp(e.loc, e.ident == Id.classInstanceSize ? cd.structsize : cd.alignsize, Type.tsize_t);
5fee5ec3
IB
1211 }
1212 if (e.ident == Id.getAliasThis)
1213 {
1214 if (dim != 1)
1215 return dimError(1);
1216
1217 auto o = (*e.args)[0];
1218 auto s = getDsymbol(o);
1219 auto ad = s ? s.isAggregateDeclaration() : null;
1220
1221 auto exps = new Expressions();
1222 if (ad && ad.aliasthis)
1223 exps.push(new StringExp(e.loc, ad.aliasthis.ident.toString()));
1224 Expression ex = new TupleExp(e.loc, exps);
1225 ex = ex.expressionSemantic(sc);
1226 return ex;
1227 }
1228 if (e.ident == Id.getAttributes)
1229 {
1230 /* Specify 0 for bit 0 of the flags argument to semanticTiargs() so that
1231 * a symbol should not be folded to a constant.
1232 * Bit 1 means don't convert Parameter to Type if Parameter has an identifier
1233 */
1234 if (!TemplateInstance.semanticTiargs(e.loc, sc, e.args, 3))
1235 return ErrorExp.get();
1236
1237 if (dim != 1)
1238 return dimError(1);
1239
1240 auto o = (*e.args)[0];
1241 auto po = isParameter(o);
1242 auto s = getDsymbolWithoutExpCtx(o);
b7a586be 1243 auto typeOfArg = isType(o);
5fee5ec3
IB
1244 UserAttributeDeclaration udad = null;
1245 if (po)
1246 {
1247 udad = po.userAttribDecl;
1248 }
1249 else if (s)
1250 {
6d799f0a
IB
1251 // @@@DEPRECATION 2.100.2
1252 if (auto fd = s.isFuncDeclaration())
1253 {
1254 if (fd.overnext)
1255 {
1256 deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", fd.toChars());
1257 deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");
1258 }
1259 }
1260
1261 // @@@DEPRECATION 2.100.2
1262 if (auto td = s.isTemplateDeclaration())
1263 {
1264 if (td.overnext || td.funcroot)
1265 {
1266 deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `%s`", td.ident.toChars());
1267 deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");
1268 }
1269 }
5fee5ec3
IB
1270 if (s.isImport())
1271 {
1272 s = s.isImport().mod;
1273 }
31350635 1274 //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
5fee5ec3
IB
1275 udad = s.userAttribDecl;
1276 }
b7a586be
IB
1277 else if (typeOfArg)
1278 {
1279 // If there is a type but no symbol, do nothing rather than erroring.
1280 }
5fee5ec3
IB
1281 else
1282 {
1283 version (none)
1284 {
1285 Expression x = isExpression(o);
1286 Type t = isType(o);
1287 if (x)
9c7d5e88 1288 printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars());
5fee5ec3
IB
1289 if (t)
1290 printf("t = %d %s\n", t.ty, t.toChars());
1291 }
1292 e.error("first argument is not a symbol");
1293 return ErrorExp.get();
1294 }
1295
1296 auto exps = udad ? udad.getAttributes() : new Expressions();
1297 auto tup = new TupleExp(e.loc, exps);
1298 return tup.expressionSemantic(sc);
1299 }
1300 if (e.ident == Id.getFunctionAttributes)
1301 {
1302 /* Extract all function attributes as a tuple (const/shared/inout/pure/nothrow/etc) except UDAs.
1303 * https://dlang.org/spec/traits.html#getFunctionAttributes
1304 */
1305 if (dim != 1)
1306 return dimError(1);
1307
1308 FuncDeclaration fd;
1309 TypeFunction tf = toTypeFunction((*e.args)[0], fd);
1310
1311 if (!tf)
1312 {
1313 e.error("first argument is not a function");
1314 return ErrorExp.get();
1315 }
1316
1317 auto mods = new Expressions();
1318
1319 void addToMods(string str)
1320 {
1321 mods.push(new StringExp(Loc.initial, str));
1322 }
1323 tf.modifiersApply(&addToMods);
1324 tf.attributesApply(&addToMods, TRUSTformatSystem);
1325
1326 auto tup = new TupleExp(e.loc, mods);
1327 return tup.expressionSemantic(sc);
1328 }
1329 if (e.ident == Id.isReturnOnStack)
1330 {
1331 /* Extract as a boolean if function return value is on the stack
1332 * https://dlang.org/spec/traits.html#isReturnOnStack
1333 */
1334 if (dim != 1)
1335 return dimError(1);
1336
1337 RootObject o = (*e.args)[0];
1338 FuncDeclaration fd;
1339 TypeFunction tf = toTypeFunction(o, fd);
1340
1341 if (!tf)
1342 {
1343 e.error("argument to `__traits(isReturnOnStack, %s)` is not a function", o.toChars());
1344 return ErrorExp.get();
1345 }
1346
1347 bool value = target.isReturnOnStack(tf, fd && fd.needThis());
1348 return IntegerExp.createBool(value);
1349 }
1350 if (e.ident == Id.getFunctionVariadicStyle)
1351 {
1352 /* Accept a symbol or a type. Returns one of the following:
1353 * "none" not a variadic function
1354 * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments`
1355 * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg
1356 * "typesafe" void typesafe(T[] ...)
1357 */
1358 // get symbol linkage as a string
1359 if (dim != 1)
1360 return dimError(1);
1361
1362 LINK link;
1363 VarArg varargs;
1364 auto o = (*e.args)[0];
1365
1366 FuncDeclaration fd;
1367 TypeFunction tf = toTypeFunction(o, fd);
1368
1369 if (tf)
1370 {
1371 link = tf.linkage;
1372 varargs = tf.parameterList.varargs;
1373 }
1374 else
1375 {
1376 if (!fd)
1377 {
1378 e.error("argument to `__traits(getFunctionVariadicStyle, %s)` is not a function", o.toChars());
1379 return ErrorExp.get();
1380 }
5eb9927a 1381 link = fd._linkage;
5fee5ec3
IB
1382 varargs = fd.getParameterList().varargs;
1383 }
1384 string style;
1385 final switch (varargs)
1386 {
1387 case VarArg.none: style = "none"; break;
1388 case VarArg.variadic: style = (link == LINK.d)
1389 ? "argptr"
1390 : "stdarg"; break;
1391 case VarArg.typesafe: style = "typesafe"; break;
1392 }
1393 auto se = new StringExp(e.loc, style);
1394 return se.expressionSemantic(sc);
1395 }
1396 if (e.ident == Id.getParameterStorageClasses)
1397 {
1398 /* Accept a function symbol or a type, followed by a parameter index.
1399 * Returns a tuple of strings of the parameter's storage classes.
1400 */
1401 // get symbol linkage as a string
1402 if (dim != 2)
1403 return dimError(2);
1404
1405 auto o = (*e.args)[0];
1406 auto o1 = (*e.args)[1];
1407
5fee5ec3 1408 ParameterList fparams;
0fb57034
IB
1409
1410 CallExp ce;
1411 if (auto exp = isExpression(o))
1412 ce = exp.isCallExp();
1413
1414 if (ce)
1415 {
1416 fparams = ce.f.getParameterList();
1417 }
5fee5ec3
IB
1418 else
1419 {
0fb57034
IB
1420 FuncDeclaration fd;
1421 auto tf = toTypeFunction(o, fd);
1422 if (tf)
1423 fparams = tf.parameterList;
1424 else if (fd)
1425 fparams = fd.getParameterList();
1426 else
1427 {
1428 e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function or a function call",
1429 o.toChars(), o1.toChars());
1430 return ErrorExp.get();
1431 }
5fee5ec3
IB
1432 }
1433
1434 // Avoid further analysis for invalid functions leading to misleading error messages
1435 if (!fparams.parameters)
1436 return ErrorExp.get();
1437
1438 StorageClass stc;
1439
1440 // Set stc to storage class of the ith parameter
1441 auto ex = isExpression((*e.args)[1]);
1442 if (!ex)
1443 {
1444 e.error("expression expected as second argument of `__traits(getParameterStorageClasses, %s, %s)`",
1445 o.toChars(), o1.toChars());
1446 return ErrorExp.get();
1447 }
1448 ex = ex.ctfeInterpret();
1449 auto ii = ex.toUInteger();
1450 if (ii >= fparams.length)
1451 {
1452 e.error("parameter index must be in range 0..%u not %s", cast(uint)fparams.length, ex.toChars());
1453 return ErrorExp.get();
1454 }
1455
1456 uint n = cast(uint)ii;
1457 Parameter p = fparams[n];
1458 stc = p.storageClass;
1459
1460 // This mirrors hdrgen.visit(Parameter p)
1461 if (p.type && p.type.mod & MODFlags.shared_)
1462 stc &= ~STC.shared_;
1463
1464 auto exps = new Expressions;
1465
1466 void push(string s)
1467 {
1468 exps.push(new StringExp(e.loc, s));
1469 }
1470
1471 if (stc & STC.auto_)
1472 push("auto");
1473 if (stc & STC.return_)
1474 push("return");
1475
1476 if (stc & STC.out_)
1477 push("out");
1478 else if (stc & STC.in_)
1479 push("in");
1480 else if (stc & STC.ref_)
1481 push("ref");
1482 else if (stc & STC.lazy_)
1483 push("lazy");
1484 else if (stc & STC.alias_)
1485 push("alias");
1486
1487 if (stc & STC.const_)
1488 push("const");
1489 if (stc & STC.immutable_)
1490 push("immutable");
1491 if (stc & STC.wild)
1492 push("inout");
1493 if (stc & STC.shared_)
1494 push("shared");
1495 if (stc & STC.scope_ && !(stc & STC.scopeinferred))
1496 push("scope");
1497
1498 auto tup = new TupleExp(e.loc, exps);
1499 return tup.expressionSemantic(sc);
1500 }
1501 if (e.ident == Id.getLinkage)
1502 {
1503 // get symbol linkage as a string
1504 if (dim != 1)
1505 return dimError(1);
1506
1507 LINK link;
1508 auto o = (*e.args)[0];
1509
1510 FuncDeclaration fd;
1511 TypeFunction tf = toTypeFunction(o, fd);
1512
1513 if (tf)
31350635 1514 {
5eb9927a 1515 link = fd ? fd.toAliasFunc()._linkage : tf.linkage;
31350635 1516 }
5fee5ec3
IB
1517 else
1518 {
1519 auto s = getDsymbol(o);
1520 Declaration d;
1521 AggregateDeclaration agg;
1522 if (!s || ((d = s.isDeclaration()) is null && (agg = s.isAggregateDeclaration()) is null))
1523 {
1524 e.error("argument to `__traits(getLinkage, %s)` is not a declaration", o.toChars());
1525 return ErrorExp.get();
1526 }
1527
1528 if (d !is null)
5eb9927a 1529 link = d._linkage;
5fee5ec3
IB
1530 else
1531 {
1532 // Resolves forward references
1533 if (agg.sizeok != Sizeok.done)
1534 {
1535 agg.size(e.loc);
1536 if (agg.sizeok != Sizeok.done)
1537 {
1538 e.error("%s `%s` is forward referenced", agg.kind(), agg.toChars());
1539 return ErrorExp.get();
1540 }
1541 }
1542
1543 final switch (agg.classKind)
1544 {
1545 case ClassKind.d:
1546 link = LINK.d;
1547 break;
1548 case ClassKind.cpp:
1549 link = LINK.cpp;
1550 break;
1551 case ClassKind.objc:
1552 link = LINK.objc;
1553 break;
1554 case ClassKind.c:
1555 link = LINK.c;
1556 break;
1557 }
1558 }
1559 }
1560 auto linkage = linkageToChars(link);
1561 auto se = new StringExp(e.loc, linkage.toDString());
1562 return se.expressionSemantic(sc);
1563 }
1564 if (e.ident == Id.allMembers ||
1565 e.ident == Id.derivedMembers)
1566 {
1567 if (dim != 1)
1568 return dimError(1);
1569
1570 auto o = (*e.args)[0];
1571 auto s = getDsymbol(o);
1572 if (!s)
1573 {
5eb9927a 1574 e.error("in expression `%s` `%s` can't have members", e.toChars(), o.toChars());
5fee5ec3
IB
1575 e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", o.toChars());
1576
1577 return ErrorExp.get();
1578 }
1579 if (auto imp = s.isImport())
1580 {
1581 // https://issues.dlang.org/show_bug.cgi?id=9692
1582 s = imp.mod;
1583 }
1584
1585 // https://issues.dlang.org/show_bug.cgi?id=16044
1586 if (auto p = s.isPackage())
1587 {
1588 if (auto pm = p.isPackageMod())
1589 s = pm;
1590 }
1591
1592 auto sds = s.isScopeDsymbol();
1593 if (!sds || sds.isTemplateDeclaration())
1594 {
5eb9927a 1595 e.error("in expression `%s` %s `%s` has no members", e.toChars(), s.kind(), s.toChars());
5fee5ec3
IB
1596 e.errorSupplemental("`%s` must evaluate to either a module, a struct, an union, a class, an interface or a template instantiation", s.toChars());
1597 return ErrorExp.get();
1598 }
1599
1600 auto idents = new Identifiers();
1601
1602 int pushIdentsDg(size_t n, Dsymbol sm)
1603 {
1604 if (!sm)
1605 return 1;
1606
1607 // skip local symbols, such as static foreach loop variables
1608 if (auto decl = sm.isDeclaration())
1609 {
1610 if (decl.storage_class & STC.local)
1611 {
1612 return 0;
1613 }
1614 // skip 'this' context pointers
1615 else if (decl.isThisDeclaration())
1616 return 0;
1617 }
1618
1619 // https://issues.dlang.org/show_bug.cgi?id=20915
1620 // skip version and debug identifiers
1621 if (sm.isVersionSymbol() || sm.isDebugSymbol())
1622 return 0;
1623
1624 //printf("\t[%i] %s %s\n", i, sm.kind(), sm.toChars());
1625 if (sm.ident)
1626 {
1627 // https://issues.dlang.org/show_bug.cgi?id=10096
1628 // https://issues.dlang.org/show_bug.cgi?id=10100
1629 // Skip over internal members in __traits(allMembers)
1630 if ((sm.isCtorDeclaration() && sm.ident != Id.ctor) ||
1631 (sm.isDtorDeclaration() && sm.ident != Id.dtor) ||
1632 (sm.isPostBlitDeclaration() && sm.ident != Id.postblit) ||
1633 sm.isInvariantDeclaration() ||
1634 sm.isUnitTestDeclaration())
1635
1636 {
1637 return 0;
1638 }
1639 if (sm.ident == Id.empty)
1640 {
1641 return 0;
1642 }
1643 if (sm.isTypeInfoDeclaration()) // https://issues.dlang.org/show_bug.cgi?id=15177
1644 return 0;
1645 if ((!sds.isModule() && !sds.isPackage()) && sm.isImport()) // https://issues.dlang.org/show_bug.cgi?id=17057
1646 return 0;
1647
1648 //printf("\t%s\n", sm.ident.toChars());
1649
1650 /* Skip if already present in idents[]
1651 */
1652 foreach (id; *idents)
1653 {
1654 if (id == sm.ident)
1655 return 0;
1656
1657 // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop.
1658 debug
1659 {
1660 import core.stdc.string : strcmp;
1661 assert(strcmp(id.toChars(), sm.ident.toChars()) != 0);
1662 }
1663 }
1664 idents.push(sm.ident);
1665 }
1666 else if (auto ed = sm.isEnumDeclaration())
1667 {
1668 ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg);
1669 }
1670 return 0;
1671 }
1672
1673 ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg);
1674 auto cd = sds.isClassDeclaration();
1675 if (cd && e.ident == Id.allMembers)
1676 {
1677 if (cd.semanticRun < PASS.semanticdone)
1678 cd.dsymbolSemantic(null); // https://issues.dlang.org/show_bug.cgi?id=13668
1679 // Try to resolve forward reference
1680
1681 void pushBaseMembersDg(ClassDeclaration cd)
1682 {
6d799f0a 1683 for (size_t i = 0; i < cd.baseclasses.length; i++)
5fee5ec3
IB
1684 {
1685 auto cb = (*cd.baseclasses)[i].sym;
1686 assert(cb);
1687 ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg);
6d799f0a 1688 if (cb.baseclasses.length)
5fee5ec3
IB
1689 pushBaseMembersDg(cb);
1690 }
1691 }
1692
1693 pushBaseMembersDg(cd);
1694 }
1695
1696 // Turn Identifiers into StringExps reusing the allocated array
1697 assert(Expressions.sizeof == Identifiers.sizeof);
1698 auto exps = cast(Expressions*)idents;
1699 foreach (i, id; *idents)
1700 {
1701 auto se = new StringExp(e.loc, id.toString());
1702 (*exps)[i] = se;
1703 }
1704
1705 /* Making this a tuple is more flexible, as it can be statically unrolled.
1706 * To make an array literal, enclose __traits in [ ]:
1707 * [ __traits(allMembers, ...) ]
1708 */
1709 Expression ex = new TupleExp(e.loc, exps);
1710 ex = ex.expressionSemantic(sc);
1711 return ex;
1712 }
1713 if (e.ident == Id.compiles)
1714 {
1715 /* Determine if all the objects - types, expressions, or symbols -
1716 * compile without error
1717 */
1718 if (!dim)
1719 return False();
1720
1721 foreach (o; *e.args)
1722 {
1723 uint errors = global.startGagging();
1724 Scope* sc2 = sc.push();
1725 sc2.tinst = null;
8da8c7d3 1726 sc2.minst = null; // this is why code for these are not emitted to object file
5fee5ec3
IB
1727 sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
1728
1729 bool err = false;
1730
1731 auto t = isType(o);
31350635
IB
1732 auto ex = isExpression(o);
1733 if (t)
5fee5ec3 1734 {
31350635
IB
1735 Dsymbol s;
1736 t.resolve(e.loc, sc2, ex, t, s);
1737 if (t)
5fee5ec3 1738 {
31350635
IB
1739 t.typeSemantic(e.loc, sc2);
1740 if (t.ty == Terror)
5fee5ec3 1741 err = true;
5fee5ec3 1742 }
31350635
IB
1743 else if (s && s.errors)
1744 err = true;
5fee5ec3 1745 }
31350635 1746 if (ex)
5fee5ec3 1747 {
31350635
IB
1748 ex = ex.expressionSemantic(sc2);
1749 ex = resolvePropertiesOnly(sc2, ex);
1750 ex = ex.optimize(WANTvalue);
1751 if (sc2.func && sc2.func.type.ty == Tfunction)
5fee5ec3 1752 {
31350635
IB
1753 const tf = cast(TypeFunction)sc2.func.type;
1754 err |= tf.isnothrow && canThrow(ex, sc2.func, false);
5fee5ec3 1755 }
31350635
IB
1756 ex = checkGC(sc2, ex);
1757 if (ex.op == EXP.error)
1758 err = true;
5fee5ec3
IB
1759 }
1760
1761 // Carefully detach the scope from the parent and throw it away as
1762 // we only need it to evaluate the expression
1763 // https://issues.dlang.org/show_bug.cgi?id=15428
1764 sc2.detach();
1765
1766 if (global.endGagging(errors) || err)
1767 {
1768 return False();
1769 }
1770 }
1771 return True();
1772 }
1773 if (e.ident == Id.isSame)
1774 {
1775 /* Determine if two symbols are the same
1776 */
1777 if (dim != 2)
1778 return dimError(2);
1779
1780 // https://issues.dlang.org/show_bug.cgi?id=20761
1781 // tiarg semantic may expand in place the list of arguments, for example:
1782 //
1783 // before tiarg sema: __traits(isSame, seq!(0,0), seq!(1,1))
1784 // after : __traits(isSame, 0, 0, 1, 1)
1785 //
1786 // so we split in two lists
1787 Objects ob1;
1788 ob1.push((*e.args)[0]);
1789 Objects ob2;
1790 ob2.push((*e.args)[1]);
1791 if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob1, 0))
1792 return ErrorExp.get();
1793 if (!TemplateInstance.semanticTiargs(e.loc, sc, &ob2, 0))
1794 return ErrorExp.get();
6d799f0a 1795 if (ob1.length != ob2.length)
5fee5ec3 1796 return False();
6d799f0a 1797 foreach (immutable i; 0 .. ob1.length)
5fee5ec3
IB
1798 if (!ob1[i].isSame(ob2[i], sc))
1799 return False();
1800 return True();
1801 }
1802 if (e.ident == Id.getUnitTests)
1803 {
1804 if (dim != 1)
1805 return dimError(1);
1806
1807 auto o = (*e.args)[0];
1808 auto s = getDsymbolWithoutExpCtx(o);
1809 if (!s)
1810 {
1811 e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate",
1812 o.toChars());
1813 return ErrorExp.get();
1814 }
1815 if (auto imp = s.isImport()) // https://issues.dlang.org/show_bug.cgi?id=10990
1816 s = imp.mod;
1817
1818 auto sds = s.isScopeDsymbol();
1819 if (!sds || sds.isTemplateDeclaration())
1820 {
1821 e.error("argument `%s` to __traits(getUnitTests) must be a module or aggregate, not a %s",
1822 s.toChars(), s.kind());
1823 return ErrorExp.get();
1824 }
1825
1826 auto exps = new Expressions();
1827 if (global.params.useUnitTests)
1828 {
1829 bool[void*] uniqueUnitTests;
1830
1831 void symbolDg(Dsymbol s)
1832 {
1833 if (auto ad = s.isAttribDeclaration())
1834 {
1835 ad.include(null).foreachDsymbol(&symbolDg);
1836 }
1837 else if (auto tm = s.isTemplateMixin())
1838 {
1839 tm.members.foreachDsymbol(&symbolDg);
1840 }
1841 else if (auto ud = s.isUnitTestDeclaration())
1842 {
1843 if (cast(void*)ud in uniqueUnitTests)
1844 return;
1845
1846 uniqueUnitTests[cast(void*)ud] = true;
1847
1848 auto ad = new FuncAliasDeclaration(ud.ident, ud, false);
1849 ad.visibility = ud.visibility;
1850
1851 auto e = new DsymbolExp(Loc.initial, ad, false);
1852 exps.push(e);
1853 }
1854 }
1855
1856 sds.members.foreachDsymbol(&symbolDg);
1857 }
1858 auto te = new TupleExp(e.loc, exps);
1859 return te.expressionSemantic(sc);
1860 }
1861 if (e.ident == Id.getVirtualIndex)
1862 {
1863 if (dim != 1)
1864 return dimError(1);
1865
1866 auto o = (*e.args)[0];
1867 auto s = getDsymbolWithoutExpCtx(o);
1868
1869 auto fd = s ? s.isFuncDeclaration() : null;
1870 if (!fd)
1871 {
1872 e.error("first argument to __traits(getVirtualIndex) must be a function");
1873 return ErrorExp.get();
1874 }
1875
1876 fd = fd.toAliasFunc(); // Necessary to support multiple overloads.
1877 return new IntegerExp(e.loc, fd.vtblIndex, Type.tptrdiff_t);
1878 }
1879 if (e.ident == Id.getPointerBitmap)
1880 {
1881 return pointerBitmap(e);
1882 }
9c7d5e88
IB
1883 if (e.ident == Id.initSymbol)
1884 {
1885 if (dim != 1)
1886 return dimError(1);
1887
1888 auto o = (*e.args)[0];
1889 Type t = isType(o);
1890 AggregateDeclaration ad = t ? isAggregate(t) : null;
1891
1892 // Interfaces don't have an init symbol and hence cause linker errors
1893 if (!ad || ad.isInterfaceDeclaration())
1894 {
1895 e.error("struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o.toChars());
1896 return ErrorExp.get();
1897 }
1898
1899 Declaration d = new SymbolDeclaration(ad.loc, ad);
1900 d.type = Type.tvoid.arrayOf().constOf();
1901 d.storage_class |= STC.rvalue;
1902 return new VarExp(e.loc, d);
1903 }
5fee5ec3
IB
1904 if (e.ident == Id.isZeroInit)
1905 {
1906 if (dim != 1)
1907 return dimError(1);
1908
1909 auto o = (*e.args)[0];
1910 Type t = isType(o);
1911 if (!t)
1912 {
1913 e.error("type expected as second argument of __traits `%s` instead of `%s`",
1914 e.ident.toChars(), o.toChars());
1915 return ErrorExp.get();
1916 }
1917
6d799f0a
IB
1918 // https://issues.dlang.org/show_bug.cgi?id=23534
1919 //
1920 // For enums, we need to get the enum initializer
1921 // (the first enum member), not the initializer of the
1922 // type of the enum members.
1923 Type tb = t.isTypeEnum ? t : t.baseElemOf();
5fee5ec3
IB
1924 return tb.isZeroInit(e.loc) ? True() : False();
1925 }
1926 if (e.ident == Id.getTargetInfo)
1927 {
1928 if (dim != 1)
1929 return dimError(1);
1930
1931 auto ex = isExpression((*e.args)[0]);
1932 StringExp se = ex ? ex.ctfeInterpret().toStringExp() : null;
1933 if (!ex || !se || se.len == 0)
1934 {
1935 e.error("string expected as argument of __traits `%s` instead of `%s`", e.ident.toChars(), ex.toChars());
1936 return ErrorExp.get();
1937 }
1938 se = se.toUTF8(sc);
1939
1940 const slice = se.peekString();
1941 Expression r = target.getTargetInfo(slice.ptr, e.loc); // BUG: reliance on terminating 0
1942 if (!r)
1943 {
1944 e.error("`getTargetInfo` key `\"%.*s\"` not supported by this implementation",
1945 cast(int)slice.length, slice.ptr);
1946 return ErrorExp.get();
1947 }
1948 return r.expressionSemantic(sc);
1949 }
1950 if (e.ident == Id.getLocation)
1951 {
1952 if (dim != 1)
1953 return dimError(1);
1954 auto arg0 = (*e.args)[0];
1955 Dsymbol s = getDsymbolWithoutExpCtx(arg0);
1956 if (!s || !s.loc.isValid())
1957 {
1958 e.error("can only get the location of a symbol, not `%s`", arg0.toChars());
1959 return ErrorExp.get();
1960 }
1961
1962 const fd = s.isFuncDeclaration();
1963 // FIXME:td.overnext is always set, even when using an index on it
1964 //const td = s.isTemplateDeclaration();
1965 if ((fd && fd.overnext) /*|| (td && td.overnext)*/)
1966 {
1967 e.error("cannot get location of an overload set, " ~
1968 "use `__traits(getOverloads, ..., \"%s\"%s)[N]` " ~
1969 "to get the Nth overload",
1970 arg0.toChars(), /*td ? ", true".ptr :*/ "".ptr);
1971 return ErrorExp.get();
1972 }
1973
1974 auto exps = new Expressions(3);
1975 (*exps)[0] = new StringExp(e.loc, s.loc.filename.toDString());
1976 (*exps)[1] = new IntegerExp(e.loc, s.loc.linnum,Type.tint32);
1977 (*exps)[2] = new IntegerExp(e.loc, s.loc.charnum,Type.tint32);
1978 auto tup = new TupleExp(e.loc, exps);
1979 return tup.expressionSemantic(sc);
1980 }
1981 if (e.ident == Id.getCppNamespaces)
1982 {
1983 auto o = (*e.args)[0];
1984 auto s = getDsymbolWithoutExpCtx(o);
1985 auto exps = new Expressions(0);
1986 if (auto d = s.isDeclaration())
1987 {
1988 if (d.inuse)
1989 {
1990 d.error("circular reference in `__traits(GetCppNamespaces,...)`");
1991 return ErrorExp.get();
1992 }
1993 d.inuse = 1;
1994 }
1995
1996 /**
1997 Prepend the namespaces in the linked list `ns` to `es`.
1998
1999 Returns: true if `ns` contains an `ErrorExp`.
2000 */
2001 bool prependNamespaces(Expressions* es, CPPNamespaceDeclaration ns)
2002 {
2003 // Semantic processing will convert `extern(C++, "a", "b", "c")`
2004 // into `extern(C++, "a") extern(C++, "b") extern(C++, "c")`,
2005 // creating a linked list what `a`'s `cppnamespace` points to `b`,
2006 // and `b`'s points to `c`. Our entry point is `a`.
2007 for (; ns !is null; ns = ns.cppnamespace)
2008 {
2009 ns.dsymbolSemantic(sc);
2010
2011 if (ns.exp.isErrorExp())
2012 return true;
2013
2014 auto se = ns.exp.toStringExp();
2015 // extern(C++, (emptyTuple))
2016 // struct D {}
2017 // will produce a blank ident
2018 if (!se.len)
2019 continue;
2020 es.insert(0, se);
2021 }
2022 return false;
2023 }
2024 for (auto p = s; !p.isModule(); p = p.toParent())
2025 {
2026 p.dsymbolSemantic(sc);
2027 auto pp = p.toParent();
2028 if (pp.isTemplateInstance())
2029 {
2030 if (!p.cppnamespace)
2031 continue;
2032 //if (!p.toParent().cppnamespace)
2033 // continue;
2034 auto inner = new Expressions(0);
2035 auto outer = new Expressions(0);
2036 if (prependNamespaces(inner, p.cppnamespace)) return ErrorExp.get();
2037 if (prependNamespaces(outer, pp.cppnamespace)) return ErrorExp.get();
2038
2039 size_t i = 0;
6d799f0a 2040 while(i < outer.length && ((*inner)[i]) == (*outer)[i])
5fee5ec3
IB
2041 i++;
2042
2043 foreach_reverse (ns; (*inner)[][i .. $])
2044 exps.insert(0, ns);
2045 continue;
2046 }
2047
2048 if (p.isNspace())
2049 exps.insert(0, new StringExp(p.loc, p.ident.toString()));
2050
2051 if (prependNamespaces(exps, p.cppnamespace))
2052 return ErrorExp.get();
2053 }
2054 if (auto d = s.isDeclaration())
2055 d.inuse = 0;
2056 auto tup = new TupleExp(e.loc, exps);
2057 return tup.expressionSemantic(sc);
2058 }
d7569187
IB
2059 //https://issues.dlang.org/show_bug.cgi?id=22291
2060 if (e.ident == Id.parameters)
2061 {
2062 //No args are valid
2063 if (e.args)
2064 {
2065 char[] contents = cast(char[]) e.args.toString();
2066 contents = contents[1..$];
2067 contents[$-1] = '\0';
2068 e.error("`__traits(parameters)` cannot have arguments, but `%s` was supplied", contents.ptr);
2069 return ErrorExp.get();
2070 }
5fee5ec3 2071
235d5a96
IB
2072 auto fd = sc.getEnclosingFunction();
2073 if (!fd)
d7569187
IB
2074 {
2075 e.error("`__traits(parameters)` may only be used inside a function");
2076 return ErrorExp.get();
2077 }
235d5a96
IB
2078
2079 auto tf = fd.type.isTypeFunction();
d7569187
IB
2080 assert(tf);
2081 auto exps = new Expressions(0);
2082 int addParameterDG(size_t idx, Parameter x)
2083 {
2084 assert(x.ident);
2085 exps.push(new IdentifierExp(e.loc, x.ident));
2086 return 0;
2087 }
2088 /*
2089 This is required since not all "parameters" actually have a name
2090 until they (tuples) are expanded e.g. an anonymous tuple parameter's
2091 contents get given names but not the tuple itself.
2092 */
2093 Parameter._foreach(tf.parameterList.parameters, &addParameterDG);
2094 auto tup = new TupleExp(e.loc, exps);
2095 return tup.expressionSemantic(sc);
2096 }
5fee5ec3 2097
f99303eb
IB
2098 /* Can't find the identifier. Try a spell check for a better error message
2099 */
2100 traitNotFound(e);
2101
5fee5ec3
IB
2102 return ErrorExp.get();
2103}
2104
2105/// compare arguments of __traits(isSame)
2106private bool isSame(RootObject o1, RootObject o2, Scope* sc)
2107{
2108 static FuncLiteralDeclaration isLambda(RootObject oarg)
2109 {
2110 if (auto t = isDsymbol(oarg))
2111 {
2112 if (auto td = t.isTemplateDeclaration())
2113 {
6d799f0a 2114 if (td.members && td.members.length == 1)
5fee5ec3
IB
2115 {
2116 if (auto fd = (*td.members)[0].isFuncLiteralDeclaration())
2117 return fd;
2118 }
2119 }
2120 }
2121 else if (auto ea = isExpression(oarg))
2122 {
9c7d5e88 2123 if (ea.op == EXP.function_)
5fee5ec3 2124 {
235d5a96 2125 if (auto fe = ea.isFuncExp())
5fee5ec3
IB
2126 return fe.fd;
2127 }
2128 }
2129 return null;
2130 }
2131
2132 auto l1 = isLambda(o1);
2133 auto l2 = isLambda(o2);
2134
2135 if (l1 && l2)
2136 {
2137 import dmd.lambdacomp : isSameFuncLiteral;
2138 if (isSameFuncLiteral(l1, l2, sc))
2139 return true;
2140 }
2141
2142 // issue 12001, allow isSame, <BasicType>, <BasicType>
2143 Type t1 = isType(o1);
2144 Type t2 = isType(o2);
2145 if (t1 && t2 && t1.equals(t2))
2146 return true;
2147
2148 auto s1 = getDsymbol(o1);
2149 auto s2 = getDsymbol(o2);
2150 //printf("isSame: %s, %s\n", o1.toChars(), o2.toChars());
2151 version (none)
2152 {
2153 printf("o1: %p\n", o1);
2154 printf("o2: %p\n", o2);
2155 if (!s1)
2156 {
2157 if (auto ea = isExpression(o1))
2158 printf("%s\n", ea.toChars());
2159 if (auto ta = isType(o1))
2160 printf("%s\n", ta.toChars());
2161 return false;
2162 }
2163 else
2164 printf("%s %s\n", s1.kind(), s1.toChars());
2165 }
2166 if (!s1 && !s2)
2167 {
2168 auto ea1 = isExpression(o1);
2169 auto ea2 = isExpression(o2);
2170 if (ea1 && ea2)
2171 {
2172 if (ea1.equals(ea2))
2173 return true;
2174 }
2175 }
2176 if (!s1 || !s2)
2177 return false;
2178
2179 s1 = s1.toAlias();
2180 s2 = s2.toAlias();
2181
2182 if (auto fa1 = s1.isFuncAliasDeclaration())
2183 s1 = fa1.toAliasFunc();
2184 if (auto fa2 = s2.isFuncAliasDeclaration())
2185 s2 = fa2.toAliasFunc();
2186
2187 // https://issues.dlang.org/show_bug.cgi?id=11259
2188 // compare import symbol to a package symbol
2189 static bool cmp(Dsymbol s1, Dsymbol s2)
2190 {
2191 auto imp = s1.isImport();
2192 return imp && imp.pkg && imp.pkg == s2.isPackage();
2193 }
2194
2195 if (cmp(s1,s2) || cmp(s2,s1))
2196 return true;
2197
2198 if (s1 == s2)
2199 return true;
2200
2201 // https://issues.dlang.org/show_bug.cgi?id=18771
2202 // OverloadSets are equal if they contain the same functions
2203 auto overSet1 = s1.isOverloadSet();
2204 if (!overSet1)
2205 return false;
2206
2207 auto overSet2 = s2.isOverloadSet();
2208 if (!overSet2)
2209 return false;
2210
6d799f0a 2211 if (overSet1.a.length != overSet2.a.length)
5fee5ec3
IB
2212 return false;
2213
2214 // OverloadSets contain array of Dsymbols => O(n*n)
2215 // to compare for equality as the order of overloads
2216 // might not be the same
2217Lnext:
2218 foreach(overload1; overSet1.a)
2219 {
2220 foreach(overload2; overSet2.a)
2221 {
2222 if (overload1 == overload2)
2223 continue Lnext;
2224 }
2225 return false;
2226 }
2227 return true;
2228}
f99303eb
IB
2229
2230
2231/***********************************
2232 * A trait was not found. Give a decent error message
2233 * by trying a spell check.
2234 * Params:
2235 * e = the offending trait
2236 */
2237private void traitNotFound(TraitsExp e)
2238{
2239 __gshared const StringTable!bool traitsStringTable;
2240 __gshared bool initialized;
2241
2242 if (!initialized)
2243 {
2244 initialized = true; // lazy initialization
2245
2246 // All possible traits
8da8c7d3 2247 __gshared Identifier*[59] idents =
f99303eb
IB
2248 [
2249 &Id.isAbstractClass,
2250 &Id.isArithmetic,
2251 &Id.isAssociativeArray,
2252 &Id.isDisabled,
2253 &Id.isDeprecated,
2254 &Id.isFuture,
2255 &Id.isFinalClass,
2256 &Id.isPOD,
2257 &Id.isNested,
2258 &Id.isFloating,
2259 &Id.isIntegral,
2260 &Id.isScalar,
2261 &Id.isStaticArray,
2262 &Id.isUnsigned,
2263 &Id.isVirtualFunction,
2264 &Id.isVirtualMethod,
2265 &Id.isAbstractFunction,
2266 &Id.isFinalFunction,
2267 &Id.isOverrideFunction,
2268 &Id.isStaticFunction,
2269 &Id.isModule,
2270 &Id.isPackage,
2271 &Id.isRef,
2272 &Id.isOut,
2273 &Id.isLazy,
2274 &Id.isReturnOnStack,
2275 &Id.hasMember,
2276 &Id.identifier,
8da8c7d3 2277 &Id.fullyQualifiedName,
f99303eb
IB
2278 &Id.getProtection,
2279 &Id.getVisibility,
2280 &Id.parent,
2281 &Id.child,
2282 &Id.getLinkage,
2283 &Id.getMember,
2284 &Id.getOverloads,
2285 &Id.getVirtualFunctions,
2286 &Id.getVirtualMethods,
2287 &Id.classInstanceSize,
2288 &Id.classInstanceAlignment,
2289 &Id.allMembers,
2290 &Id.derivedMembers,
2291 &Id.isSame,
2292 &Id.compiles,
2293 &Id.getAliasThis,
2294 &Id.getAttributes,
2295 &Id.getFunctionAttributes,
2296 &Id.getFunctionVariadicStyle,
2297 &Id.getParameterStorageClasses,
2298 &Id.getUnitTests,
2299 &Id.getVirtualIndex,
2300 &Id.getPointerBitmap,
2301 &Id.isZeroInit,
2302 &Id.getTargetInfo,
2303 &Id.getLocation,
2304 &Id.hasPostblit,
2305 &Id.hasCopyConstructor,
2306 &Id.isCopyable,
2307 &Id.parameters,
2308 ];
2309
2310 StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable;
2311 stringTable._init(idents.length);
2312
2313 foreach (id; idents)
2314 {
2315 auto sv = stringTable.insert((*id).toString(), true);
2316 assert(sv);
2317 }
2318 }
2319
2320 static const(char)[] trait_search_fp(const(char)[] seed, out int cost)
2321 {
2322 //printf("trait_search_fp('%s')\n", seed);
2323 if (!seed.length)
2324 return null;
2325 cost = 0; // all the same cost
2326 const sv = traitsStringTable.lookup(seed);
2327 return sv ? sv.toString() : null;
2328 }
2329
2330 if (auto sub = speller!trait_search_fp(e.ident.toString()))
2331 e.error("unrecognized trait `%s`, did you mean `%.*s`?", e.ident.toChars(), cast(int) sub.length, sub.ptr);
2332 else
2333 e.error("unrecognized trait `%s`", e.ident.toChars());
2334}