Home | History | Annotate | Line # | Download | only in dmd
      1  1.1  mrg /**
      2  1.1  mrg  * Evaluate compile-time conditionals, such as `static if` `version` and `debug`.
      3  1.1  mrg  *
      4  1.1  mrg  * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation)
      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/cond.d, _cond.d)
     10  1.1  mrg  * Documentation:  https://dlang.org/phobos/dmd_cond.html
     11  1.1  mrg  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cond.d
     12  1.1  mrg  */
     13  1.1  mrg 
     14  1.1  mrg module dmd.cond;
     15  1.1  mrg 
     16  1.1  mrg import core.stdc.string;
     17  1.1  mrg import dmd.arraytypes;
     18  1.1  mrg import dmd.astenums;
     19  1.1  mrg import dmd.ast_node;
     20  1.1  mrg import dmd.dcast;
     21  1.1  mrg import dmd.dmodule;
     22  1.1  mrg import dmd.dscope;
     23  1.1  mrg import dmd.dsymbol;
     24  1.1  mrg import dmd.errors;
     25  1.1  mrg import dmd.expression;
     26  1.1  mrg import dmd.expressionsem;
     27  1.1  mrg import dmd.globals;
     28  1.1  mrg import dmd.identifier;
     29  1.1  mrg import dmd.mtype;
     30  1.1  mrg import dmd.typesem;
     31  1.1  mrg import dmd.common.outbuffer;
     32  1.1  mrg import dmd.root.rootobject;
     33  1.1  mrg import dmd.root.string;
     34  1.1  mrg import dmd.tokens;
     35  1.1  mrg import dmd.utils;
     36  1.1  mrg import dmd.visitor;
     37  1.1  mrg import dmd.id;
     38  1.1  mrg import dmd.statement;
     39  1.1  mrg import dmd.declaration;
     40  1.1  mrg import dmd.dstruct;
     41  1.1  mrg import dmd.func;
     42  1.1  mrg 
     43  1.1  mrg /***********************************************************
     44  1.1  mrg  */
     45  1.1  mrg 
     46  1.1  mrg enum Include : ubyte
     47  1.1  mrg {
     48  1.1  mrg     notComputed,        /// not computed yet
     49  1.1  mrg     yes,                /// include the conditional code
     50  1.1  mrg     no,                 /// do not include the conditional code
     51  1.1  mrg }
     52  1.1  mrg 
     53  1.1  mrg extern (C++) abstract class Condition : ASTNode
     54  1.1  mrg {
     55  1.1  mrg     Loc loc;
     56  1.1  mrg 
     57  1.1  mrg     Include inc;
     58  1.1  mrg 
     59  1.1  mrg     override final DYNCAST dyncast() const
     60  1.1  mrg     {
     61  1.1  mrg         return DYNCAST.condition;
     62  1.1  mrg     }
     63  1.1  mrg 
     64  1.1  mrg     extern (D) this(const ref Loc loc)
     65  1.1  mrg     {
     66  1.1  mrg         this.loc = loc;
     67  1.1  mrg     }
     68  1.1  mrg 
     69  1.1  mrg     abstract Condition syntaxCopy();
     70  1.1  mrg 
     71  1.1  mrg     abstract int include(Scope* sc);
     72  1.1  mrg 
     73  1.1  mrg     inout(DebugCondition) isDebugCondition() inout
     74  1.1  mrg     {
     75  1.1  mrg         return null;
     76  1.1  mrg     }
     77  1.1  mrg 
     78  1.1  mrg     inout(VersionCondition) isVersionCondition() inout
     79  1.1  mrg     {
     80  1.1  mrg         return null;
     81  1.1  mrg     }
     82  1.1  mrg 
     83  1.1  mrg     override void accept(Visitor v)
     84  1.1  mrg     {
     85  1.1  mrg         v.visit(this);
     86  1.1  mrg     }
     87  1.1  mrg }
     88  1.1  mrg 
     89  1.1  mrg /***********************************************************
     90  1.1  mrg  * Implements common functionality for StaticForeachDeclaration and
     91  1.1  mrg  * StaticForeachStatement This performs the necessary lowerings before
     92  1.1  mrg  * dmd.statementsem.makeTupleForeach can be used to expand the
     93  1.1  mrg  * corresponding `static foreach` declaration or statement.
     94  1.1  mrg  */
     95  1.1  mrg 
     96  1.1  mrg extern (C++) final class StaticForeach : RootObject
     97  1.1  mrg {
     98  1.1  mrg     extern(D) static immutable tupleFieldName = "tuple"; // used in lowering
     99  1.1  mrg 
    100  1.1  mrg     Loc loc;
    101  1.1  mrg 
    102  1.1  mrg     /***************
    103  1.1  mrg      * Not `null` iff the `static foreach` is over an aggregate. In
    104  1.1  mrg      * this case, it contains the corresponding ForeachStatement. For
    105  1.1  mrg      * StaticForeachDeclaration, the body is `null`.
    106  1.1  mrg     */
    107  1.1  mrg     ForeachStatement aggrfe;
    108  1.1  mrg     /***************
    109  1.1  mrg      * Not `null` iff the `static foreach` is over a range. Exactly
    110  1.1  mrg      * one of the `aggrefe` and `rangefe` fields is not null. See
    111  1.1  mrg      * `aggrfe` field for more details.
    112  1.1  mrg      */
    113  1.1  mrg     ForeachRangeStatement rangefe;
    114  1.1  mrg 
    115  1.1  mrg     /***************
    116  1.1  mrg      * true if it is necessary to expand a tuple into multiple
    117  1.1  mrg      * variables (see lowerNonArrayAggregate).
    118  1.1  mrg      */
    119  1.1  mrg     bool needExpansion = false;
    120  1.1  mrg 
    121  1.1  mrg     extern (D) this(const ref Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe)
    122  1.1  mrg     {
    123  1.1  mrg         assert(!!aggrfe ^ !!rangefe);
    124  1.1  mrg 
    125  1.1  mrg         this.loc = loc;
    126  1.1  mrg         this.aggrfe = aggrfe;
    127  1.1  mrg         this.rangefe = rangefe;
    128  1.1  mrg     }
    129  1.1  mrg 
    130  1.1  mrg     StaticForeach syntaxCopy()
    131  1.1  mrg     {
    132  1.1  mrg         return new StaticForeach(
    133  1.1  mrg             loc,
    134  1.1  mrg             aggrfe ? aggrfe.syntaxCopy() : null,
    135  1.1  mrg             rangefe ? rangefe.syntaxCopy() : null
    136  1.1  mrg         );
    137  1.1  mrg     }
    138  1.1  mrg 
    139  1.1  mrg     /*****************************************
    140  1.1  mrg      * Turn an aggregate which is an array into an expression tuple
    141  1.1  mrg      * of its elements. I.e., lower
    142  1.1  mrg      *     static foreach (x; [1, 2, 3, 4]) { ... }
    143  1.1  mrg      * to
    144  1.1  mrg      *     static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
    145  1.1  mrg      */
    146  1.1  mrg     private extern(D) void lowerArrayAggregate(Scope* sc)
    147  1.1  mrg     {
    148  1.1  mrg         auto aggr = aggrfe.aggr;
    149  1.1  mrg         Expression el = new ArrayLengthExp(aggr.loc, aggr);
    150  1.1  mrg         sc = sc.startCTFE();
    151  1.1  mrg         el = el.expressionSemantic(sc);
    152  1.1  mrg         sc = sc.endCTFE();
    153  1.1  mrg         el = el.optimize(WANTvalue);
    154  1.1  mrg         el = el.ctfeInterpret();
    155  1.1  mrg         if (el.op == EXP.int64)
    156  1.1  mrg         {
    157  1.1  mrg             Expressions *es = void;
    158  1.1  mrg             if (auto ale = aggr.isArrayLiteralExp())
    159  1.1  mrg             {
    160  1.1  mrg                 // Directly use the elements of the array for the TupleExp creation
    161  1.1  mrg                 es = ale.elements;
    162  1.1  mrg             }
    163  1.1  mrg             else
    164  1.1  mrg             {
    165  1.1  mrg                 const length = cast(size_t)el.toInteger();
    166  1.1  mrg                 es = new Expressions(length);
    167  1.1  mrg                 foreach (i; 0 .. length)
    168  1.1  mrg                 {
    169  1.1  mrg                     auto index = new IntegerExp(loc, i, Type.tsize_t);
    170  1.1  mrg                     auto value = new IndexExp(aggr.loc, aggr, index);
    171  1.1  mrg                     (*es)[i] = value;
    172  1.1  mrg                 }
    173  1.1  mrg             }
    174  1.1  mrg             aggrfe.aggr = new TupleExp(aggr.loc, es);
    175  1.1  mrg             aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
    176  1.1  mrg             aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
    177  1.1  mrg             aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
    178  1.1  mrg         }
    179  1.1  mrg         else
    180  1.1  mrg         {
    181  1.1  mrg             aggrfe.aggr = ErrorExp.get();
    182  1.1  mrg         }
    183  1.1  mrg     }
    184  1.1  mrg 
    185  1.1  mrg     /*****************************************
    186  1.1  mrg      * Wrap a statement into a function literal and call it.
    187  1.1  mrg      *
    188  1.1  mrg      * Params:
    189  1.1  mrg      *     loc = The source location.
    190  1.1  mrg      *     s  = The statement.
    191  1.1  mrg      * Returns:
    192  1.1  mrg      *     AST of the expression `(){ s; }()` with location loc.
    193  1.1  mrg      */
    194  1.1  mrg     private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s)
    195  1.1  mrg     {
    196  1.1  mrg         auto tf = new TypeFunction(ParameterList(), null, LINK.default_, 0);
    197  1.1  mrg         auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null);
    198  1.1  mrg         fd.fbody = s;
    199  1.1  mrg         auto fe = new FuncExp(loc, fd);
    200  1.1  mrg         auto ce = new CallExp(loc, fe, new Expressions());
    201  1.1  mrg         return ce;
    202  1.1  mrg     }
    203  1.1  mrg 
    204  1.1  mrg     /*****************************************
    205  1.1  mrg      * Create a `foreach` statement from `aggrefe/rangefe` with given
    206  1.1  mrg      * `foreach` variables and body `s`.
    207  1.1  mrg      *
    208  1.1  mrg      * Params:
    209  1.1  mrg      *     loc = The source location.
    210  1.1  mrg      *     parameters = The foreach variables.
    211  1.1  mrg      *     s = The `foreach` body.
    212  1.1  mrg      * Returns:
    213  1.1  mrg      *     `foreach (parameters; aggregate) s;` or
    214  1.1  mrg      *     `foreach (parameters; lower .. upper) s;`
    215  1.1  mrg      *     Where aggregate/lower, upper are as for the current StaticForeach.
    216  1.1  mrg      */
    217  1.1  mrg     private extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s)
    218  1.1  mrg     {
    219  1.1  mrg         if (aggrfe)
    220  1.1  mrg         {
    221  1.1  mrg             return new ForeachStatement(loc, aggrfe.op, parameters, aggrfe.aggr.syntaxCopy(), s, loc);
    222  1.1  mrg         }
    223  1.1  mrg         else
    224  1.1  mrg         {
    225  1.1  mrg             assert(rangefe && parameters.dim == 1);
    226  1.1  mrg             return new ForeachRangeStatement(loc, rangefe.op, (*parameters)[0], rangefe.lwr.syntaxCopy(), rangefe.upr.syntaxCopy(), s, loc);
    227  1.1  mrg         }
    228  1.1  mrg     }
    229  1.1  mrg 
    230  1.1  mrg     /*****************************************
    231  1.1  mrg      * For a `static foreach` with multiple loop variables, the
    232  1.1  mrg      * aggregate is lowered to an array of tuples. As D does not have
    233  1.1  mrg      * built-in tuples, we need a suitable tuple type. This generates
    234  1.1  mrg      * a `struct` that serves as the tuple type. This type is only
    235  1.1  mrg      * used during CTFE and hence its typeinfo will not go to the
    236  1.1  mrg      * object file.
    237  1.1  mrg      *
    238  1.1  mrg      * Params:
    239  1.1  mrg      *     loc = The source location.
    240  1.1  mrg      *     e = The expressions we wish to store in the tuple.
    241  1.1  mrg      *     sc  = The current scope.
    242  1.1  mrg      * Returns:
    243  1.1  mrg      *     A struct type of the form
    244  1.1  mrg      *         struct Tuple
    245  1.1  mrg      *         {
    246  1.1  mrg      *             typeof(AliasSeq!(e)) tuple;
    247  1.1  mrg      *         }
    248  1.1  mrg      */
    249  1.1  mrg 
    250  1.1  mrg     private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc)
    251  1.1  mrg     {   // TODO: move to druntime?
    252  1.1  mrg         auto sid = Identifier.generateId("Tuple");
    253  1.1  mrg         auto sdecl = new StructDeclaration(loc, sid, false);
    254  1.1  mrg         sdecl.storage_class |= STC.static_;
    255  1.1  mrg         sdecl.members = new Dsymbols();
    256  1.1  mrg         auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length);
    257  1.1  mrg         auto ty = new TypeTypeof(loc, new TupleExp(loc, e));
    258  1.1  mrg         sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0));
    259  1.1  mrg         auto r = cast(TypeStruct)sdecl.type;
    260  1.1  mrg         if (global.params.useTypeInfo && Type.dtypeinfo)
    261  1.1  mrg             r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file
    262  1.1  mrg         return r;
    263  1.1  mrg     }
    264  1.1  mrg 
    265  1.1  mrg     /*****************************************
    266  1.1  mrg      * Create the AST for an instantiation of a suitable tuple type.
    267  1.1  mrg      *
    268  1.1  mrg      * Params:
    269  1.1  mrg      *     loc = The source location.
    270  1.1  mrg      *     type = A Tuple type, created with createTupleType.
    271  1.1  mrg      *     e = The expressions we wish to store in the tuple.
    272  1.1  mrg      * Returns:
    273  1.1  mrg      *     An AST for the expression `Tuple(e)`.
    274  1.1  mrg      */
    275  1.1  mrg 
    276  1.1  mrg     private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e)
    277  1.1  mrg     {   // TODO: move to druntime?
    278  1.1  mrg         return new CallExp(loc, new TypeExp(loc, type), e);
    279  1.1  mrg     }
    280  1.1  mrg 
    281  1.1  mrg 
    282  1.1  mrg     /*****************************************
    283  1.1  mrg      * Lower any aggregate that is not an array to an array using a
    284  1.1  mrg      * regular foreach loop within CTFE.  If there are multiple
    285  1.1  mrg      * `static foreach` loop variables, an array of tuples is
    286  1.1  mrg      * generated. In thise case, the field `needExpansion` is set to
    287  1.1  mrg      * true to indicate that the static foreach loop expansion will
    288  1.1  mrg      * need to expand the tuples into multiple variables.
    289  1.1  mrg      *
    290  1.1  mrg      * For example, `static foreach (x; range) { ... }` is lowered to:
    291  1.1  mrg      *
    292  1.1  mrg      *     static foreach (x; {
    293  1.1  mrg      *         typeof({
    294  1.1  mrg      *             foreach (x; range) return x;
    295  1.1  mrg      *         }())[] __res;
    296  1.1  mrg      *         foreach (x; range) __res ~= x;
    297  1.1  mrg      *         return __res;
    298  1.1  mrg      *     }()) { ... }
    299  1.1  mrg      *
    300  1.1  mrg      * Finally, call `lowerArrayAggregate` to turn the produced
    301  1.1  mrg      * array into an expression tuple.
    302  1.1  mrg      *
    303  1.1  mrg      * Params:
    304  1.1  mrg      *     sc = The current scope.
    305  1.1  mrg      */
    306  1.1  mrg 
    307  1.1  mrg     private void lowerNonArrayAggregate(Scope* sc)
    308  1.1  mrg     {
    309  1.1  mrg         auto nvars = aggrfe ? aggrfe.parameters.dim : 1;
    310  1.1  mrg         auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc;
    311  1.1  mrg         // We need three sets of foreach loop variables because the
    312  1.1  mrg         // lowering contains three foreach loops.
    313  1.1  mrg         Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()];
    314  1.1  mrg         foreach (i; 0 .. nvars)
    315  1.1  mrg         {
    316  1.1  mrg             foreach (params; pparams)
    317  1.1  mrg             {
    318  1.1  mrg                 auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm;
    319  1.1  mrg                 params.push(new Parameter(p.storageClass, p.type, p.ident, null, null));
    320  1.1  mrg             }
    321  1.1  mrg         }
    322  1.1  mrg         Expression[2] res;
    323  1.1  mrg         TypeStruct tplty = null;
    324  1.1  mrg         if (nvars == 1) // only one `static foreach` variable, generate identifiers.
    325  1.1  mrg         {
    326  1.1  mrg             foreach (i; 0 .. 2)
    327  1.1  mrg             {
    328  1.1  mrg                 res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident);
    329  1.1  mrg             }
    330  1.1  mrg         }
    331  1.1  mrg         else // multiple `static foreach` variables, generate tuples.
    332  1.1  mrg         {
    333  1.1  mrg             foreach (i; 0 .. 2)
    334  1.1  mrg             {
    335  1.1  mrg                 auto e = new Expressions(pparams[0].dim);
    336  1.1  mrg                 foreach (j, ref elem; *e)
    337  1.1  mrg                 {
    338  1.1  mrg                     auto p = (*pparams[i])[j];
    339  1.1  mrg                     elem = new IdentifierExp(aloc, p.ident);
    340  1.1  mrg                 }
    341  1.1  mrg                 if (!tplty)
    342  1.1  mrg                 {
    343  1.1  mrg                     tplty = createTupleType(aloc, e, sc);
    344  1.1  mrg                 }
    345  1.1  mrg                 res[i] = createTuple(aloc, tplty, e);
    346  1.1  mrg             }
    347  1.1  mrg             needExpansion = true; // need to expand the tuples later
    348  1.1  mrg         }
    349  1.1  mrg         // generate remaining code for the new aggregate which is an
    350  1.1  mrg         // array (see documentation comment).
    351  1.1  mrg         if (rangefe)
    352  1.1  mrg         {
    353  1.1  mrg             sc = sc.startCTFE();
    354  1.1  mrg             rangefe.lwr = rangefe.lwr.expressionSemantic(sc);
    355  1.1  mrg             rangefe.lwr = resolveProperties(sc, rangefe.lwr);
    356  1.1  mrg             rangefe.upr = rangefe.upr.expressionSemantic(sc);
    357  1.1  mrg             rangefe.upr = resolveProperties(sc, rangefe.upr);
    358  1.1  mrg             sc = sc.endCTFE();
    359  1.1  mrg             rangefe.lwr = rangefe.lwr.optimize(WANTvalue);
    360  1.1  mrg             rangefe.lwr = rangefe.lwr.ctfeInterpret();
    361  1.1  mrg             rangefe.upr = rangefe.upr.optimize(WANTvalue);
    362  1.1  mrg             rangefe.upr = rangefe.upr.ctfeInterpret();
    363  1.1  mrg         }
    364  1.1  mrg         auto s1 = new Statements();
    365  1.1  mrg         auto sfe = new Statements();
    366  1.1  mrg         if (tplty) sfe.push(new ExpStatement(loc, tplty.sym));
    367  1.1  mrg         sfe.push(new ReturnStatement(aloc, res[0]));
    368  1.1  mrg         s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe)));
    369  1.1  mrg         s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0)));
    370  1.1  mrg         Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
    371  1.1  mrg         auto aty = ety.arrayOf();
    372  1.1  mrg         auto idres = Identifier.generateId("__res");
    373  1.1  mrg         auto vard = new VarDeclaration(aloc, aty, idres, null);
    374  1.1  mrg         auto s2 = new Statements();
    375  1.1  mrg 
    376  1.1  mrg         // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
    377  1.1  mrg         // an empty foreach to expose them.
    378  1.1  mrg         uint olderrors = global.startGagging();
    379  1.1  mrg         ety = ety.typeSemantic(aloc, sc);
    380  1.1  mrg         if (global.endGagging(olderrors))
    381  1.1  mrg             s2.push(createForeach(aloc, pparams[1], null));
    382  1.1  mrg         else
    383  1.1  mrg         {
    384  1.1  mrg             s2.push(new ExpStatement(aloc, vard));
    385  1.1  mrg             auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
    386  1.1  mrg             s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass)));
    387  1.1  mrg             s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
    388  1.1  mrg         }
    389  1.1  mrg 
    390  1.1  mrg         Expression aggr = void;
    391  1.1  mrg         Type indexty = void;
    392  1.1  mrg 
    393  1.1  mrg         if (rangefe && (indexty = ety).isintegral())
    394  1.1  mrg         {
    395  1.1  mrg             rangefe.lwr.type = indexty;
    396  1.1  mrg             rangefe.upr.type = indexty;
    397  1.1  mrg             auto lwrRange = getIntRange(rangefe.lwr);
    398  1.1  mrg             auto uprRange = getIntRange(rangefe.upr);
    399  1.1  mrg 
    400  1.1  mrg             const lwr = rangefe.lwr.toInteger();
    401  1.1  mrg             auto  upr = rangefe.upr.toInteger();
    402  1.1  mrg             size_t length = 0;
    403  1.1  mrg 
    404  1.1  mrg             if (lwrRange.imin <= uprRange.imax)
    405  1.1  mrg                     length = cast(size_t) (upr - lwr);
    406  1.1  mrg 
    407  1.1  mrg             auto exps = new Expressions(length);
    408  1.1  mrg 
    409  1.1  mrg             if (rangefe.op == TOK.foreach_)
    410  1.1  mrg             {
    411  1.1  mrg                 foreach (i; 0 .. length)
    412  1.1  mrg                     (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
    413  1.1  mrg             }
    414  1.1  mrg             else
    415  1.1  mrg             {
    416  1.1  mrg                 --upr;
    417  1.1  mrg                 foreach (i; 0 .. length)
    418  1.1  mrg                     (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
    419  1.1  mrg             }
    420  1.1  mrg             aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps);
    421  1.1  mrg         }
    422  1.1  mrg         else
    423  1.1  mrg         {
    424  1.1  mrg             aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
    425  1.1  mrg             sc = sc.startCTFE();
    426  1.1  mrg             aggr = aggr.expressionSemantic(sc);
    427  1.1  mrg             aggr = resolveProperties(sc, aggr);
    428  1.1  mrg             sc = sc.endCTFE();
    429  1.1  mrg             aggr = aggr.optimize(WANTvalue);
    430  1.1  mrg             aggr = aggr.ctfeInterpret();
    431  1.1  mrg         }
    432  1.1  mrg 
    433  1.1  mrg         assert(!!aggrfe ^ !!rangefe);
    434  1.1  mrg         aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr,
    435  1.1  mrg                                       aggrfe ? aggrfe._body : rangefe._body,
    436  1.1  mrg                                       aggrfe ? aggrfe.endloc : rangefe.endloc);
    437  1.1  mrg         rangefe = null;
    438  1.1  mrg         lowerArrayAggregate(sc); // finally, turn generated array into expression tuple
    439  1.1  mrg     }
    440  1.1  mrg 
    441  1.1  mrg     /*****************************************
    442  1.1  mrg      * Perform `static foreach` lowerings that are necessary in order
    443  1.1  mrg      * to finally expand the `static foreach` using
    444  1.1  mrg      * `dmd.statementsem.makeTupleForeach`.
    445  1.1  mrg      */
    446  1.1  mrg     extern(D) void prepare(Scope* sc)
    447  1.1  mrg     {
    448  1.1  mrg         assert(sc);
    449  1.1  mrg 
    450  1.1  mrg         if (aggrfe)
    451  1.1  mrg         {
    452  1.1  mrg             sc = sc.startCTFE();
    453  1.1  mrg             aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
    454  1.1  mrg             sc = sc.endCTFE();
    455  1.1  mrg         }
    456  1.1  mrg 
    457  1.1  mrg         if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
    458  1.1  mrg         {
    459  1.1  mrg             return;
    460  1.1  mrg         }
    461  1.1  mrg 
    462  1.1  mrg         if (!ready())
    463  1.1  mrg         {
    464  1.1  mrg             if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray)
    465  1.1  mrg             {
    466  1.1  mrg                 lowerArrayAggregate(sc);
    467  1.1  mrg             }
    468  1.1  mrg             else
    469  1.1  mrg             {
    470  1.1  mrg                 lowerNonArrayAggregate(sc);
    471  1.1  mrg             }
    472  1.1  mrg         }
    473  1.1  mrg     }
    474  1.1  mrg 
    475  1.1  mrg     /*****************************************
    476  1.1  mrg      * Returns:
    477  1.1  mrg      *     `true` iff ready to call `dmd.statementsem.makeTupleForeach`.
    478  1.1  mrg      */
    479  1.1  mrg     extern(D) bool ready()
    480  1.1  mrg     {
    481  1.1  mrg         return aggrfe && aggrfe.aggr && aggrfe.aggr.type && aggrfe.aggr.type.toBasetype().ty == Ttuple;
    482  1.1  mrg     }
    483  1.1  mrg }
    484  1.1  mrg 
    485  1.1  mrg /***********************************************************
    486  1.1  mrg  */
    487  1.1  mrg extern (C++) class DVCondition : Condition
    488  1.1  mrg {
    489  1.1  mrg     uint level;
    490  1.1  mrg     Identifier ident;
    491  1.1  mrg     Module mod;
    492  1.1  mrg 
    493  1.1  mrg     extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
    494  1.1  mrg     {
    495  1.1  mrg         super(loc);
    496  1.1  mrg         this.mod = mod;
    497  1.1  mrg         this.level = level;
    498  1.1  mrg         this.ident = ident;
    499  1.1  mrg     }
    500  1.1  mrg 
    501  1.1  mrg     override final DVCondition syntaxCopy()
    502  1.1  mrg     {
    503  1.1  mrg         return this; // don't need to copy
    504  1.1  mrg     }
    505  1.1  mrg 
    506  1.1  mrg     override void accept(Visitor v)
    507  1.1  mrg     {
    508  1.1  mrg         v.visit(this);
    509  1.1  mrg     }
    510  1.1  mrg }
    511  1.1  mrg 
    512  1.1  mrg /***********************************************************
    513  1.1  mrg  */
    514  1.1  mrg extern (C++) final class DebugCondition : DVCondition
    515  1.1  mrg {
    516  1.1  mrg     /**
    517  1.1  mrg      * Add an user-supplied identifier to the list of global debug identifiers
    518  1.1  mrg      *
    519  1.1  mrg      * Can be called from either the driver or a `debug = Ident;` statement.
    520  1.1  mrg      * Unlike version identifier, there isn't any reserved debug identifier
    521  1.1  mrg      * so no validation takes place.
    522  1.1  mrg      *
    523  1.1  mrg      * Params:
    524  1.1  mrg      *   ident = identifier to add
    525  1.1  mrg      */
    526  1.1  mrg     deprecated("Kept for C++ compat - Use the string overload instead")
    527  1.1  mrg     static void addGlobalIdent(const(char)* ident)
    528  1.1  mrg     {
    529  1.1  mrg         addGlobalIdent(ident[0 .. ident.strlen]);
    530  1.1  mrg     }
    531  1.1  mrg 
    532  1.1  mrg     /// Ditto
    533  1.1  mrg     extern(D) static void addGlobalIdent(string ident)
    534  1.1  mrg     {
    535  1.1  mrg         // Overload necessary for string literals
    536  1.1  mrg         addGlobalIdent(cast(const(char)[])ident);
    537  1.1  mrg     }
    538  1.1  mrg 
    539  1.1  mrg 
    540  1.1  mrg     /// Ditto
    541  1.1  mrg     extern(D) static void addGlobalIdent(const(char)[] ident)
    542  1.1  mrg     {
    543  1.1  mrg         if (!global.debugids)
    544  1.1  mrg             global.debugids = new Identifiers();
    545  1.1  mrg         global.debugids.push(Identifier.idPool(ident));
    546  1.1  mrg     }
    547  1.1  mrg 
    548  1.1  mrg 
    549  1.1  mrg     /**
    550  1.1  mrg      * Instantiate a new `DebugCondition`
    551  1.1  mrg      *
    552  1.1  mrg      * Params:
    553  1.1  mrg      *   mod = Module this node belongs to
    554  1.1  mrg      *   level = Minimum global level this condition needs to pass.
    555  1.1  mrg      *           Only used if `ident` is `null`.
    556  1.1  mrg      *   ident = Identifier required for this condition to pass.
    557  1.1  mrg      *           If `null`, this conditiion will use an integer level.
    558  1.1  mrg      *  loc = Location in the source file
    559  1.1  mrg      */
    560  1.1  mrg     extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
    561  1.1  mrg     {
    562  1.1  mrg         super(loc, mod, level, ident);
    563  1.1  mrg     }
    564  1.1  mrg 
    565  1.1  mrg     override int include(Scope* sc)
    566  1.1  mrg     {
    567  1.1  mrg         //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
    568  1.1  mrg         if (inc == Include.notComputed)
    569  1.1  mrg         {
    570  1.1  mrg             inc = Include.no;
    571  1.1  mrg             bool definedInModule = false;
    572  1.1  mrg             if (ident)
    573  1.1  mrg             {
    574  1.1  mrg                 if (findCondition(mod.debugids, ident))
    575  1.1  mrg                 {
    576  1.1  mrg                     inc = Include.yes;
    577  1.1  mrg                     definedInModule = true;
    578  1.1  mrg                 }
    579  1.1  mrg                 else if (findCondition(global.debugids, ident))
    580  1.1  mrg                     inc = Include.yes;
    581  1.1  mrg                 else
    582  1.1  mrg                 {
    583  1.1  mrg                     if (!mod.debugidsNot)
    584  1.1  mrg                         mod.debugidsNot = new Identifiers();
    585  1.1  mrg                     mod.debugidsNot.push(ident);
    586  1.1  mrg                 }
    587  1.1  mrg             }
    588  1.1  mrg             else if (level <= global.params.debuglevel || level <= mod.debuglevel)
    589  1.1  mrg                 inc = Include.yes;
    590  1.1  mrg             if (!definedInModule)
    591  1.1  mrg                 printDepsConditional(sc, this, "depsDebug ");
    592  1.1  mrg         }
    593  1.1  mrg         return (inc == Include.yes);
    594  1.1  mrg     }
    595  1.1  mrg 
    596  1.1  mrg     override inout(DebugCondition) isDebugCondition() inout
    597  1.1  mrg     {
    598  1.1  mrg         return this;
    599  1.1  mrg     }
    600  1.1  mrg 
    601  1.1  mrg     override void accept(Visitor v)
    602  1.1  mrg     {
    603  1.1  mrg         v.visit(this);
    604  1.1  mrg     }
    605  1.1  mrg 
    606  1.1  mrg     override const(char)* toChars() const
    607  1.1  mrg     {
    608  1.1  mrg         return ident ? ident.toChars() : "debug".ptr;
    609  1.1  mrg     }
    610  1.1  mrg }
    611  1.1  mrg 
    612  1.1  mrg /**
    613  1.1  mrg  * Node to represent a version condition
    614  1.1  mrg  *
    615  1.1  mrg  * A version condition is of the form:
    616  1.1  mrg  * ---
    617  1.1  mrg  * version (Identifier)
    618  1.1  mrg  * ---
    619  1.1  mrg  * In user code.
    620  1.1  mrg  * This class also provides means to add version identifier
    621  1.1  mrg  * to the list of global (cross module) identifiers.
    622  1.1  mrg  */
    623  1.1  mrg extern (C++) final class VersionCondition : DVCondition
    624  1.1  mrg {
    625  1.1  mrg     /**
    626  1.1  mrg      * Check if a given version identifier is reserved.
    627  1.1  mrg      *
    628  1.1  mrg      * Params:
    629  1.1  mrg      *   ident = identifier being checked
    630  1.1  mrg      *
    631  1.1  mrg      * Returns:
    632  1.1  mrg      *   `true` if it is reserved, `false` otherwise
    633  1.1  mrg      */
    634  1.1  mrg     extern(D) private static bool isReserved(const(char)[] ident)
    635  1.1  mrg     {
    636  1.1  mrg         // This list doesn't include "D_*" versions, see the last return
    637  1.1  mrg         switch (ident)
    638  1.1  mrg         {
    639  1.1  mrg             case "AArch64":
    640  1.1  mrg             case "AIX":
    641  1.1  mrg             case "all":
    642  1.1  mrg             case "Alpha":
    643  1.1  mrg             case "Alpha_HardFloat":
    644  1.1  mrg             case "Alpha_SoftFloat":
    645  1.1  mrg             case "Android":
    646  1.1  mrg             case "ARM":
    647  1.1  mrg             case "ARM_HardFloat":
    648  1.1  mrg             case "ARM_SoftFloat":
    649  1.1  mrg             case "ARM_SoftFP":
    650  1.1  mrg             case "ARM_Thumb":
    651  1.1  mrg             case "AsmJS":
    652  1.1  mrg             case "assert":
    653  1.1  mrg             case "AVR":
    654  1.1  mrg             case "BigEndian":
    655  1.1  mrg             case "BSD":
    656  1.1  mrg             case "CppRuntime_Clang":
    657  1.1  mrg             case "CppRuntime_DigitalMars":
    658  1.1  mrg             case "CppRuntime_Gcc":
    659  1.1  mrg             case "CppRuntime_Microsoft":
    660  1.1  mrg             case "CppRuntime_Sun":
    661  1.1  mrg             case "CRuntime_Bionic":
    662  1.1  mrg             case "CRuntime_DigitalMars":
    663  1.1  mrg             case "CRuntime_Glibc":
    664  1.1  mrg             case "CRuntime_Microsoft":
    665  1.1  mrg             case "CRuntime_Musl":
    666  1.1  mrg             case "CRuntime_Newlib":
    667  1.1  mrg             case "CRuntime_UClibc":
    668  1.1  mrg             case "CRuntime_WASI":
    669  1.1  mrg             case "Cygwin":
    670  1.1  mrg             case "DigitalMars":
    671  1.1  mrg             case "DragonFlyBSD":
    672  1.1  mrg             case "Emscripten":
    673  1.1  mrg             case "ELFv1":
    674  1.1  mrg             case "ELFv2":
    675  1.1  mrg             case "Epiphany":
    676  1.1  mrg             case "FreeBSD":
    677  1.1  mrg             case "FreeStanding":
    678  1.1  mrg             case "GNU":
    679  1.1  mrg             case "Haiku":
    680  1.1  mrg             case "HPPA":
    681  1.1  mrg             case "HPPA64":
    682  1.1  mrg             case "Hurd":
    683  1.1  mrg             case "IA64":
    684  1.1  mrg             case "iOS":
    685  1.1  mrg             case "LDC":
    686  1.1  mrg             case "linux":
    687  1.1  mrg             case "LittleEndian":
    688  1.1  mrg             case "MinGW":
    689  1.1  mrg             case "MIPS32":
    690  1.1  mrg             case "MIPS64":
    691  1.1  mrg             case "MIPS_EABI":
    692  1.1  mrg             case "MIPS_HardFloat":
    693  1.1  mrg             case "MIPS_N32":
    694  1.1  mrg             case "MIPS_N64":
    695  1.1  mrg             case "MIPS_O32":
    696  1.1  mrg             case "MIPS_O64":
    697  1.1  mrg             case "MIPS_SoftFloat":
    698  1.1  mrg             case "MSP430":
    699  1.1  mrg             case "NetBSD":
    700  1.1  mrg             case "none":
    701  1.1  mrg             case "NVPTX":
    702  1.1  mrg             case "NVPTX64":
    703  1.1  mrg             case "OpenBSD":
    704  1.1  mrg             case "OSX":
    705  1.1  mrg             case "PlayStation":
    706  1.1  mrg             case "PlayStation4":
    707  1.1  mrg             case "Posix":
    708  1.1  mrg             case "PPC":
    709  1.1  mrg             case "PPC64":
    710  1.1  mrg             case "PPC_HardFloat":
    711  1.1  mrg             case "PPC_SoftFloat":
    712  1.1  mrg             case "RISCV32":
    713  1.1  mrg             case "RISCV64":
    714  1.1  mrg             case "S390":
    715  1.1  mrg             case "S390X":
    716  1.1  mrg             case "SDC":
    717  1.1  mrg             case "SH":
    718  1.1  mrg             case "SkyOS":
    719  1.1  mrg             case "Solaris":
    720  1.1  mrg             case "SPARC":
    721  1.1  mrg             case "SPARC64":
    722  1.1  mrg             case "SPARC_HardFloat":
    723  1.1  mrg             case "SPARC_SoftFloat":
    724  1.1  mrg             case "SPARC_V8Plus":
    725  1.1  mrg             case "SystemZ":
    726  1.1  mrg             case "SysV3":
    727  1.1  mrg             case "SysV4":
    728  1.1  mrg             case "TVOS":
    729  1.1  mrg             case "unittest":
    730  1.1  mrg             case "WASI":
    731  1.1  mrg             case "WatchOS":
    732  1.1  mrg             case "WebAssembly":
    733  1.1  mrg             case "Win32":
    734  1.1  mrg             case "Win64":
    735  1.1  mrg             case "Windows":
    736  1.1  mrg             case "X86":
    737  1.1  mrg             case "X86_64":
    738  1.1  mrg                 return true;
    739  1.1  mrg 
    740  1.1  mrg             default:
    741  1.1  mrg                 // Anything that starts with "D_" is reserved
    742  1.1  mrg                 return (ident.length >= 2 && ident[0 .. 2] == "D_");
    743  1.1  mrg         }
    744  1.1  mrg     }
    745  1.1  mrg 
    746  1.1  mrg     /**
    747  1.1  mrg      * Raises an error if a version identifier is reserved.
    748  1.1  mrg      *
    749  1.1  mrg      * Called when setting a version identifier, e.g. `-version=identifier`
    750  1.1  mrg      * parameter to the compiler or `version = Foo` in user code.
    751  1.1  mrg      *
    752  1.1  mrg      * Params:
    753  1.1  mrg      *   loc = Where the identifier is set
    754  1.1  mrg      *   ident = identifier being checked (ident[$] must be '\0')
    755  1.1  mrg      */
    756  1.1  mrg     extern(D) static void checkReserved(const ref Loc loc, const(char)[] ident)
    757  1.1  mrg     {
    758  1.1  mrg         if (isReserved(ident))
    759  1.1  mrg             error(loc, "version identifier `%s` is reserved and cannot be set",
    760  1.1  mrg                   ident.ptr);
    761  1.1  mrg     }
    762  1.1  mrg 
    763  1.1  mrg     /**
    764  1.1  mrg      * Add an user-supplied global identifier to the list
    765  1.1  mrg      *
    766  1.1  mrg      * Only called from the driver for `-version=Ident` parameters.
    767  1.1  mrg      * Will raise an error if the identifier is reserved.
    768  1.1  mrg      *
    769  1.1  mrg      * Params:
    770  1.1  mrg      *   ident = identifier to add
    771  1.1  mrg      */
    772  1.1  mrg     deprecated("Kept for C++ compat - Use the string overload instead")
    773  1.1  mrg     static void addGlobalIdent(const(char)* ident)
    774  1.1  mrg     {
    775  1.1  mrg         addGlobalIdent(ident[0 .. ident.strlen]);
    776  1.1  mrg     }
    777  1.1  mrg 
    778  1.1  mrg     /// Ditto
    779  1.1  mrg     extern(D) static void addGlobalIdent(string ident)
    780  1.1  mrg     {
    781  1.1  mrg         // Overload necessary for string literals
    782  1.1  mrg         addGlobalIdent(cast(const(char)[])ident);
    783  1.1  mrg     }
    784  1.1  mrg 
    785  1.1  mrg 
    786  1.1  mrg     /// Ditto
    787  1.1  mrg     extern(D) static void addGlobalIdent(const(char)[] ident)
    788  1.1  mrg     {
    789  1.1  mrg         checkReserved(Loc.initial, ident);
    790  1.1  mrg         addPredefinedGlobalIdent(ident);
    791  1.1  mrg     }
    792  1.1  mrg 
    793  1.1  mrg     /**
    794  1.1  mrg      * Add any global identifier to the list, without checking
    795  1.1  mrg      * if it's predefined
    796  1.1  mrg      *
    797  1.1  mrg      * Only called from the driver after platform detection,
    798  1.1  mrg      * and internally.
    799  1.1  mrg      *
    800  1.1  mrg      * Params:
    801  1.1  mrg      *   ident = identifier to add (ident[$] must be '\0')
    802  1.1  mrg      */
    803  1.1  mrg     deprecated("Kept for C++ compat - Use the string overload instead")
    804  1.1  mrg     static void addPredefinedGlobalIdent(const(char)* ident)
    805  1.1  mrg     {
    806  1.1  mrg         addPredefinedGlobalIdent(ident.toDString());
    807  1.1  mrg     }
    808  1.1  mrg 
    809  1.1  mrg     /// Ditto
    810  1.1  mrg     extern(D) static void addPredefinedGlobalIdent(string ident)
    811  1.1  mrg     {
    812  1.1  mrg         // Forward: Overload necessary for string literal
    813  1.1  mrg         addPredefinedGlobalIdent(cast(const(char)[])ident);
    814  1.1  mrg     }
    815  1.1  mrg 
    816  1.1  mrg 
    817  1.1  mrg     /// Ditto
    818  1.1  mrg     extern(D) static void addPredefinedGlobalIdent(const(char)[] ident)
    819  1.1  mrg     {
    820  1.1  mrg         if (!global.versionids)
    821  1.1  mrg             global.versionids = new Identifiers();
    822  1.1  mrg         global.versionids.push(Identifier.idPool(ident));
    823  1.1  mrg     }
    824  1.1  mrg 
    825  1.1  mrg     /**
    826  1.1  mrg      * Instantiate a new `VersionCondition`
    827  1.1  mrg      *
    828  1.1  mrg      * Params:
    829  1.1  mrg      *   mod = Module this node belongs to
    830  1.1  mrg      *   level = Minimum global level this condition needs to pass.
    831  1.1  mrg      *           Only used if `ident` is `null`.
    832  1.1  mrg      *   ident = Identifier required for this condition to pass.
    833  1.1  mrg      *           If `null`, this conditiion will use an integer level.
    834  1.1  mrg      *  loc = Location in the source file
    835  1.1  mrg      */
    836  1.1  mrg     extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident)
    837  1.1  mrg     {
    838  1.1  mrg         super(loc, mod, level, ident);
    839  1.1  mrg     }
    840  1.1  mrg 
    841  1.1  mrg     override int include(Scope* sc)
    842  1.1  mrg     {
    843  1.1  mrg         //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
    844  1.1  mrg         //if (ident) printf("\tident = '%s'\n", ident.toChars());
    845  1.1  mrg         if (inc == Include.notComputed)
    846  1.1  mrg         {
    847  1.1  mrg             inc = Include.no;
    848  1.1  mrg             bool definedInModule = false;
    849  1.1  mrg             if (ident)
    850  1.1  mrg             {
    851  1.1  mrg                 if (findCondition(mod.versionids, ident))
    852  1.1  mrg                 {
    853  1.1  mrg                     inc = Include.yes;
    854  1.1  mrg                     definedInModule = true;
    855  1.1  mrg                 }
    856  1.1  mrg                 else if (findCondition(global.versionids, ident))
    857  1.1  mrg                     inc = Include.yes;
    858  1.1  mrg                 else
    859  1.1  mrg                 {
    860  1.1  mrg                     if (!mod.versionidsNot)
    861  1.1  mrg                         mod.versionidsNot = new Identifiers();
    862  1.1  mrg                     mod.versionidsNot.push(ident);
    863  1.1  mrg                 }
    864  1.1  mrg             }
    865  1.1  mrg             else if (level <= global.params.versionlevel || level <= mod.versionlevel)
    866  1.1  mrg                 inc = Include.yes;
    867  1.1  mrg             if (!definedInModule &&
    868  1.1  mrg                 (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
    869  1.1  mrg             {
    870  1.1  mrg                 printDepsConditional(sc, this, "depsVersion ");
    871  1.1  mrg             }
    872  1.1  mrg         }
    873  1.1  mrg         return (inc == Include.yes);
    874  1.1  mrg     }
    875  1.1  mrg 
    876  1.1  mrg     override inout(VersionCondition) isVersionCondition() inout
    877  1.1  mrg     {
    878  1.1  mrg         return this;
    879  1.1  mrg     }
    880  1.1  mrg 
    881  1.1  mrg     override void accept(Visitor v)
    882  1.1  mrg     {
    883  1.1  mrg         v.visit(this);
    884  1.1  mrg     }
    885  1.1  mrg 
    886  1.1  mrg     override const(char)* toChars() const
    887  1.1  mrg     {
    888  1.1  mrg         return ident ? ident.toChars() : "version".ptr;
    889  1.1  mrg     }
    890  1.1  mrg }
    891  1.1  mrg 
    892  1.1  mrg /***********************************************************
    893  1.1  mrg  */
    894  1.1  mrg extern (C++) final class StaticIfCondition : Condition
    895  1.1  mrg {
    896  1.1  mrg     Expression exp;
    897  1.1  mrg 
    898  1.1  mrg     extern (D) this(const ref Loc loc, Expression exp)
    899  1.1  mrg     {
    900  1.1  mrg         super(loc);
    901  1.1  mrg         this.exp = exp;
    902  1.1  mrg     }
    903  1.1  mrg 
    904  1.1  mrg     override StaticIfCondition syntaxCopy()
    905  1.1  mrg     {
    906  1.1  mrg         return new StaticIfCondition(loc, exp.syntaxCopy());
    907  1.1  mrg     }
    908  1.1  mrg 
    909  1.1  mrg     override int include(Scope* sc)
    910  1.1  mrg     {
    911  1.1  mrg         // printf("StaticIfCondition::include(sc = %p) this=%p inc = %d\n", sc, this, inc);
    912  1.1  mrg 
    913  1.1  mrg         int errorReturn()
    914  1.1  mrg         {
    915  1.1  mrg             if (!global.gag)
    916  1.1  mrg                 inc = Include.no; // so we don't see the error message again
    917  1.1  mrg             return 0;
    918  1.1  mrg         }
    919  1.1  mrg 
    920  1.1  mrg         if (inc == Include.notComputed)
    921  1.1  mrg         {
    922  1.1  mrg             if (!sc)
    923  1.1  mrg             {
    924  1.1  mrg                 error(loc, "`static if` conditional cannot be at global scope");
    925  1.1  mrg                 inc = Include.no;
    926  1.1  mrg                 return 0;
    927  1.1  mrg             }
    928  1.1  mrg 
    929  1.1  mrg             import dmd.staticcond;
    930  1.1  mrg             bool errors;
    931  1.1  mrg 
    932  1.1  mrg             if (!exp)
    933  1.1  mrg                 return errorReturn();
    934  1.1  mrg 
    935  1.1  mrg             bool result = evalStaticCondition(sc, exp, exp, errors);
    936  1.1  mrg 
    937  1.1  mrg             // Prevent repeated condition evaluation.
    938  1.1  mrg             // See: fail_compilation/fail7815.d
    939  1.1  mrg             if (inc != Include.notComputed)
    940  1.1  mrg                 return (inc == Include.yes);
    941  1.1  mrg             if (errors)
    942  1.1  mrg                 return errorReturn();
    943  1.1  mrg             if (result)
    944  1.1  mrg                 inc = Include.yes;
    945  1.1  mrg             else
    946  1.1  mrg                 inc = Include.no;
    947  1.1  mrg         }
    948  1.1  mrg         return (inc == Include.yes);
    949  1.1  mrg     }
    950  1.1  mrg 
    951  1.1  mrg     override void accept(Visitor v)
    952  1.1  mrg     {
    953  1.1  mrg         v.visit(this);
    954  1.1  mrg     }
    955  1.1  mrg 
    956  1.1  mrg     override const(char)* toChars() const
    957  1.1  mrg     {
    958  1.1  mrg         return exp ? exp.toChars() : "static if".ptr;
    959  1.1  mrg     }
    960  1.1  mrg }
    961  1.1  mrg 
    962  1.1  mrg 
    963  1.1  mrg /****************************************
    964  1.1  mrg  * Find `ident` in an array of identifiers.
    965  1.1  mrg  * Params:
    966  1.1  mrg  *      ids = array of identifiers
    967  1.1  mrg  *      ident = identifier to search for
    968  1.1  mrg  * Returns:
    969  1.1  mrg  *      true if found
    970  1.1  mrg  */
    971  1.1  mrg bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure
    972  1.1  mrg {
    973  1.1  mrg     if (ids)
    974  1.1  mrg     {
    975  1.1  mrg         foreach (id; *ids)
    976  1.1  mrg         {
    977  1.1  mrg             if (id == ident)
    978  1.1  mrg                 return true;
    979  1.1  mrg         }
    980  1.1  mrg     }
    981  1.1  mrg     return false;
    982  1.1  mrg }
    983  1.1  mrg 
    984  1.1  mrg // Helper for printing dependency information
    985  1.1  mrg private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType)
    986  1.1  mrg {
    987  1.1  mrg     if (!global.params.moduleDeps || global.params.moduleDepsFile)
    988  1.1  mrg         return;
    989  1.1  mrg     OutBuffer* ob = global.params.moduleDeps;
    990  1.1  mrg     Module imod = sc ? sc._module : condition.mod;
    991  1.1  mrg     if (!imod)
    992  1.1  mrg         return;
    993  1.1  mrg     ob.writestring(depType);
    994  1.1  mrg     ob.writestring(imod.toPrettyChars());
    995  1.1  mrg     ob.writestring(" (");
    996  1.1  mrg     escapePath(ob, imod.srcfile.toChars());
    997  1.1  mrg     ob.writestring(") : ");
    998  1.1  mrg     if (condition.ident)
    999  1.1  mrg         ob.writestring(condition.ident.toString());
   1000  1.1  mrg     else
   1001  1.1  mrg         ob.print(condition.level);
   1002  1.1  mrg     ob.writeByte('\n');
   1003  1.1  mrg }
   1004