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