1
2/* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/cond.c
9 */
10
11#include "root/dsystem.h"               // strcmp()
12
13#include "mars.h"
14#include "id.h"
15#include "init.h"
16#include "aggregate.h"
17#include "declaration.h"
18#include "identifier.h"
19#include "expression.h"
20#include "cond.h"
21#include "module.h"
22#include "template.h"
23#include "mtype.h"
24#include "scope.h"
25#include "statement.h"
26#include "arraytypes.h"
27#include "tokens.h"
28
29Expression *semantic(Expression *e, Scope *sc);
30bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
31
32int findCondition(Strings *ids, Identifier *ident)
33{
34    if (ids)
35    {
36        for (size_t i = 0; i < ids->dim; i++)
37        {
38            const char *id = (*ids)[i];
39
40            if (strcmp(id, ident->toChars()) == 0)
41                return true;
42        }
43    }
44
45    return false;
46}
47
48/* ============================================================ */
49
50Condition::Condition(Loc loc)
51{
52    this->loc = loc;
53    inc = 0;
54}
55
56/* ============================================================ */
57
58StaticForeach::StaticForeach(Loc loc, ForeachStatement *aggrfe, ForeachRangeStatement *rangefe)
59{
60    assert(!!aggrfe ^ !!rangefe);
61    this->loc = loc;
62    this->aggrfe = aggrfe;
63    this->rangefe = rangefe;
64    this->needExpansion = false;
65}
66
67StaticForeach *StaticForeach::syntaxCopy()
68{
69    return new StaticForeach(
70        loc,
71        aggrfe ? (ForeachStatement *)aggrfe->syntaxCopy() : NULL,
72        rangefe ? (ForeachRangeStatement *)rangefe->syntaxCopy() : NULL
73    );
74}
75
76/*****************************************
77 * Turn an aggregate which is an array into an expression tuple
78 * of its elements. I.e., lower
79 *     static foreach (x; [1, 2, 3, 4]) { ... }
80 * to
81 *     static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
82 */
83
84static void lowerArrayAggregate(StaticForeach *sfe, Scope *sc)
85{
86    Expression *aggr = sfe->aggrfe->aggr;
87    Expression *el = new ArrayLengthExp(aggr->loc, aggr);
88    sc = sc->startCTFE();
89    el = semantic(el, sc);
90    sc = sc->endCTFE();
91    el = el->optimize(WANTvalue);
92    el = el->ctfeInterpret();
93    if (el->op == TOKint64)
94    {
95        Expressions *es;
96        if (aggr->op == TOKarrayliteral)
97        {
98            // Directly use the elements of the array for the TupleExp creation
99            ArrayLiteralExp *ale = (ArrayLiteralExp *)aggr;
100            es = ale->elements;
101        }
102        else
103        {
104            size_t length = (size_t)el->toInteger();
105            es = new Expressions();
106            es->setDim(length);
107            for (size_t i = 0; i < length; i++)
108            {
109                IntegerExp *index = new IntegerExp(sfe->loc, i, Type::tsize_t);
110                Expression *value = new IndexExp(aggr->loc, aggr, index);
111                (*es)[i] = value;
112            }
113        }
114        sfe->aggrfe->aggr = new TupleExp(aggr->loc, es);
115        sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
116        sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
117        sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
118    }
119    else
120    {
121        sfe->aggrfe->aggr = new ErrorExp();
122    }
123}
124
125/*****************************************
126 * Wrap a statement into a function literal and call it.
127 *
128 * Params:
129 *     loc = The source location.
130 *     s  = The statement.
131 * Returns:
132 *     AST of the expression `(){ s; }()` with location loc.
133 */
134
135static Expression *wrapAndCall(Loc loc, Statement *s)
136{
137    TypeFunction *tf = new TypeFunction(new Parameters(), NULL, 0, LINKdefault, 0);
138    FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, NULL);
139    fd->fbody = s;
140    FuncExp *fe = new FuncExp(loc, fd);
141    Expression *ce = new CallExp(loc, fe, new Expressions());
142    return ce;
143}
144
145/*****************************************
146 * Create a `foreach` statement from `aggrefe/rangefe` with given
147 * `foreach` variables and body `s`.
148 *
149 * Params:
150 *     loc = The source location.
151 *     parameters = The foreach variables.
152 *     s = The `foreach` body.
153 * Returns:
154 *     `foreach (parameters; aggregate) s;` or
155 *     `foreach (parameters; lower .. upper) s;`
156 *     Where aggregate/lower, upper are as for the current StaticForeach.
157 */
158
159static Statement *createForeach(StaticForeach *sfe, Loc loc, Parameters *parameters, Statement *s)
160{
161    if (sfe->aggrfe)
162    {
163        return new ForeachStatement(loc, sfe->aggrfe->op, parameters, sfe->aggrfe->aggr->syntaxCopy(), s, loc);
164    }
165    else
166    {
167        assert(sfe->rangefe && parameters->dim == 1);
168        return new ForeachRangeStatement(loc, sfe->rangefe->op, (*parameters)[0],
169                                         sfe->rangefe->lwr->syntaxCopy(),
170                                         sfe->rangefe->upr->syntaxCopy(), s, loc);
171    }
172}
173
174/*****************************************
175 * For a `static foreach` with multiple loop variables, the
176 * aggregate is lowered to an array of tuples. As D does not have
177 * built-in tuples, we need a suitable tuple type. This generates
178 * a `struct` that serves as the tuple type. This type is only
179 * used during CTFE and hence its typeinfo will not go to the
180 * object file.
181 *
182 * Params:
183 *     loc = The source location.
184 *     e = The expressions we wish to store in the tuple.
185 *     sc  = The current scope.
186 * Returns:
187 *     A struct type of the form
188 *         struct Tuple
189 *         {
190 *             typeof(AliasSeq!(e)) tuple;
191 *         }
192 */
193
194static TypeStruct *createTupleType(Loc loc, Expressions *e)
195{   // TODO: move to druntime?
196    Identifier *sid = Identifier::generateId("Tuple");
197    StructDeclaration *sdecl = new StructDeclaration(loc, sid, false);
198    sdecl->storage_class |= STCstatic;
199    sdecl->members = new Dsymbols();
200    Identifier *fid = Identifier::idPool("tuple");
201    Type *ty = new TypeTypeof(loc, new TupleExp(loc, e));
202    sdecl->members->push(new VarDeclaration(loc, ty, fid, NULL));
203    TypeStruct *r = (TypeStruct *)sdecl->type;
204    if (global.params.useTypeInfo && Type::dtypeinfo)
205        r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file
206    return r;
207}
208
209/*****************************************
210 * Create the AST for an instantiation of a suitable tuple type.
211 *
212 * Params:
213 *     loc = The source location.
214 *     type = A Tuple type, created with createTupleType.
215 *     e = The expressions we wish to store in the tuple.
216 * Returns:
217 *     An AST for the expression `Tuple(e)`.
218 */
219
220static Expression *createTuple(Loc loc, TypeStruct *type, Expressions *e)
221{   // TODO: move to druntime?
222    return new CallExp(loc, new TypeExp(loc, type), e);
223}
224
225/*****************************************
226 * Lower any aggregate that is not an array to an array using a
227 * regular foreach loop within CTFE.  If there are multiple
228 * `static foreach` loop variables, an array of tuples is
229 * generated. In thise case, the field `needExpansion` is set to
230 * true to indicate that the static foreach loop expansion will
231 * need to expand the tuples into multiple variables.
232 *
233 * For example, `static foreach (x; range) { ... }` is lowered to:
234 *
235 *     static foreach (x; {
236 *         typeof({
237 *             foreach (x; range) return x;
238 *         }())[] __res;
239 *         foreach (x; range) __res ~= x;
240 *         return __res;
241 *     }()) { ... }
242 *
243 * Finally, call `lowerArrayAggregate` to turn the produced
244 * array into an expression tuple.
245 *
246 * Params:
247 *     sc = The current scope.
248 */
249
250static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc)
251{
252    size_t nvars = sfe->aggrfe ? sfe->aggrfe->parameters->dim : 1;
253    Loc aloc = sfe->aggrfe ? sfe->aggrfe->aggr->loc : sfe->rangefe->lwr->loc;
254    // We need three sets of foreach loop variables because the
255    // lowering contains three foreach loops.
256    Parameters *pparams[3] = {new Parameters(), new Parameters(), new Parameters()};
257    for (size_t i = 0; i < nvars; i++)
258    {
259        for (size_t j = 0; j < 3; j++)
260        {
261            Parameters *params = pparams[j];
262            Parameter *p = sfe->aggrfe ? (*sfe->aggrfe->parameters)[i] : sfe->rangefe->prm;
263            params->push(new Parameter(p->storageClass, p->type, p->ident, NULL));
264        }
265    }
266    Expression *res[2];
267    TypeStruct *tplty = NULL;
268    if (nvars == 1) // only one `static foreach` variable, generate identifiers.
269    {
270        for (size_t i = 0; i < 2; i++)
271        {
272            res[i] = new IdentifierExp(aloc, (*pparams[i])[0]->ident);
273        }
274    }
275    else // multiple `static foreach` variables, generate tuples.
276    {
277        for (size_t i = 0; i < 2; i++)
278        {
279            Expressions *e = new Expressions();
280            for (size_t j = 0; j < pparams[0]->dim; j++)
281            {
282                Parameter *p = (*pparams[i])[j];
283                e->push(new IdentifierExp(aloc, p->ident));
284            }
285            if (!tplty)
286            {
287                tplty = createTupleType(aloc, e);
288            }
289            res[i] = createTuple(aloc, tplty, e);
290        }
291        sfe->needExpansion = true; // need to expand the tuples later
292    }
293    // generate remaining code for the new aggregate which is an
294    // array (see documentation comment).
295    if (sfe->rangefe)
296    {
297        sc = sc->startCTFE();
298        sfe->rangefe->lwr = semantic(sfe->rangefe->lwr, sc);
299        sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
300        sfe->rangefe->upr = semantic(sfe->rangefe->upr, sc);
301        sfe->rangefe->upr = resolveProperties(sc, sfe->rangefe->upr);
302        sc = sc->endCTFE();
303        sfe->rangefe->lwr = sfe->rangefe->lwr->optimize(WANTvalue);
304        sfe->rangefe->lwr = sfe->rangefe->lwr->ctfeInterpret();
305        sfe->rangefe->upr = sfe->rangefe->upr->optimize(WANTvalue);
306        sfe->rangefe->upr = sfe->rangefe->upr->ctfeInterpret();
307    }
308    Statements *s1 = new Statements();
309    Statements *sfebody = new Statements();
310    if (tplty) sfebody->push(new ExpStatement(sfe->loc, tplty->sym));
311    sfebody->push(new ReturnStatement(aloc, res[0]));
312    s1->push(createForeach(sfe, aloc, pparams[0], new CompoundStatement(aloc, sfebody)));
313    s1->push(new ExpStatement(aloc, new AssertExp(aloc, new IntegerExp(aloc, 0, Type::tint32))));
314    Type *ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1)));
315    Type *aty = ety->arrayOf();
316    Identifier *idres = Identifier::generateId("__res");
317    VarDeclaration *vard = new VarDeclaration(aloc, aty, idres, NULL);
318    Statements *s2 = new Statements();
319
320    // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
321    // an empty foreach to expose them.
322    unsigned olderrors = global.startGagging();
323    ety = ety->semantic(aloc, sc);
324    if (global.endGagging(olderrors))
325        s2->push(createForeach(sfe, aloc, pparams[1], NULL));
326    else
327    {
328        s2->push(new ExpStatement(aloc, vard));
329        Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
330        s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass)));
331        s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
332    }
333
334    Expression *aggr;
335    Type *indexty;
336
337    if (sfe->rangefe && (indexty = ety)->isintegral())
338    {
339        sfe->rangefe->lwr->type = indexty;
340        sfe->rangefe->upr->type = indexty;
341        IntRange lwrRange = getIntRange(sfe->rangefe->lwr);
342        IntRange uprRange = getIntRange(sfe->rangefe->upr);
343
344        const dinteger_t lwr = sfe->rangefe->lwr->toInteger();
345        dinteger_t upr = sfe->rangefe->upr->toInteger();
346        size_t length = 0;
347
348        if (lwrRange.imin <= uprRange.imax)
349            length = (size_t)(upr - lwr);
350
351        Expressions *exps = new Expressions();
352        exps->setDim(length);
353
354        if (sfe->rangefe->op == TOKforeach)
355        {
356            for (size_t i = 0; i < length; i++)
357                (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
358        }
359        else
360        {
361            --upr;
362            for (size_t i = 0; i < length; i++)
363                (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
364        }
365        aggr = new ArrayLiteralExp(aloc, indexty->arrayOf(), exps);
366    }
367    else
368    {
369        aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
370        sc = sc->startCTFE();
371        aggr = semantic(aggr, sc);
372        aggr = resolveProperties(sc, aggr);
373        sc = sc->endCTFE();
374        aggr = aggr->optimize(WANTvalue);
375        aggr = aggr->ctfeInterpret();
376    }
377
378    assert(!!sfe->aggrfe ^ !!sfe->rangefe);
379    sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr,
380                                  sfe->aggrfe ? sfe->aggrfe->_body : sfe->rangefe->_body,
381                                  sfe->aggrfe ? sfe->aggrfe->endloc : sfe->rangefe->endloc);
382    sfe->rangefe = NULL;
383    lowerArrayAggregate(sfe, sc); // finally, turn generated array into expression tuple
384}
385
386/*****************************************
387 * Perform `static foreach` lowerings that are necessary in order
388 * to finally expand the `static foreach` using
389 * `ddmd.statementsem.makeTupleForeach`.
390 */
391
392void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
393{
394    assert(sc);
395    if (sfe->aggrfe)
396    {
397        sc = sc->startCTFE();
398        sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
399        sc = sc->endCTFE();
400        sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
401    }
402
403    if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Terror)
404    {
405        return;
406    }
407
408    if (!staticForeachReady(sfe))
409    {
410        if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Tarray)
411        {
412            lowerArrayAggregate(sfe, sc);
413        }
414        else
415        {
416            lowerNonArrayAggregate(sfe, sc);
417        }
418    }
419}
420
421/*****************************************
422 * Returns:
423 *     `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
424 */
425
426bool staticForeachReady(StaticForeach *sfe)
427{
428    return sfe->aggrfe && sfe->aggrfe->aggr && sfe->aggrfe->aggr->type &&
429        sfe->aggrfe->aggr->type->toBasetype()->ty == Ttuple;
430}
431
432/* ============================================================ */
433
434DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
435        : Condition(Loc())
436{
437    this->mod = mod;
438    this->level = level;
439    this->ident = ident;
440}
441
442Condition *DVCondition::syntaxCopy()
443{
444    return this;        // don't need to copy
445}
446
447/* ============================================================ */
448
449void DebugCondition::setGlobalLevel(unsigned level)
450{
451    global.params.debuglevel = level;
452}
453
454void DebugCondition::addGlobalIdent(const char *ident)
455{
456    if (!global.params.debugids)
457        global.params.debugids = new Strings();
458    global.params.debugids->push(ident);
459}
460
461
462DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
463    : DVCondition(mod, level, ident)
464{
465}
466
467// Helper for printing dependency information
468void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType)
469{
470    if (!global.params.moduleDeps || global.params.moduleDepsFile)
471        return;
472    OutBuffer *ob = global.params.moduleDeps;
473    Module* imod = sc ? sc->instantiatingModule() : condition->mod;
474    if (!imod)
475        return;
476    ob->writestring(depType);
477    ob->writestring(imod->toPrettyChars());
478    ob->writestring(" (");
479    escapePath(ob, imod->srcfile->toChars());
480    ob->writestring(") : ");
481    if (condition->ident)
482        ob->printf("%s\n", condition->ident->toChars());
483    else
484        ob->printf("%d\n", condition->level);
485}
486
487
488int DebugCondition::include(Scope *sc, ScopeDsymbol *)
489{
490    //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
491    if (inc == 0)
492    {
493        inc = 2;
494        bool definedInModule = false;
495        if (ident)
496        {
497            if (findCondition(mod->debugids, ident))
498            {
499                inc = 1;
500                definedInModule = true;
501            }
502            else if (findCondition(global.params.debugids, ident))
503                inc = 1;
504            else
505            {   if (!mod->debugidsNot)
506                    mod->debugidsNot = new Strings();
507                mod->debugidsNot->push(ident->toChars());
508            }
509        }
510        else if (level <= global.params.debuglevel || level <= mod->debuglevel)
511            inc = 1;
512        if (!definedInModule)
513            printDepsConditional(sc, this, "depsDebug ");
514    }
515    return (inc == 1);
516}
517
518/* ============================================================ */
519
520void VersionCondition::setGlobalLevel(unsigned level)
521{
522    global.params.versionlevel = level;
523}
524
525static bool isReserved(const char *ident)
526{
527    static const char* reserved[] =
528    {
529        "DigitalMars",
530        "GNU",
531        "LDC",
532        "SDC",
533        "Windows",
534        "Win32",
535        "Win64",
536        "linux",
537        "OSX",
538        "FreeBSD",
539        "OpenBSD",
540        "NetBSD",
541        "DragonFlyBSD",
542        "BSD",
543        "Solaris",
544        "Posix",
545        "AIX",
546        "Haiku",
547        "SkyOS",
548        "SysV3",
549        "SysV4",
550        "Hurd",
551        "Android",
552        "PlayStation",
553        "PlayStation4",
554        "Cygwin",
555        "MinGW",
556        "FreeStanding",
557        "X86",
558        "X86_64",
559        "ARM",
560        "ARM_Thumb",
561        "ARM_SoftFloat",
562        "ARM_SoftFP",
563        "ARM_HardFloat",
564        "AArch64",
565        "Epiphany",
566        "PPC",
567        "PPC_SoftFloat",
568        "PPC_HardFloat",
569        "PPC64",
570        "IA64",
571        "MIPS32",
572        "MIPS64",
573        "MIPS_O32",
574        "MIPS_N32",
575        "MIPS_O64",
576        "MIPS_N64",
577        "MIPS_EABI",
578        "MIPS_SoftFloat",
579        "MIPS_HardFloat",
580        "MSP430",
581        "NVPTX",
582        "NVPTX64",
583        "RISCV32",
584        "RISCV64",
585        "SPARC",
586        "SPARC_V8Plus",
587        "SPARC_SoftFloat",
588        "SPARC_HardFloat",
589        "SPARC64",
590        "S390",
591        "S390X",
592        "HPPA",
593        "HPPA64",
594        "SH",
595        "Alpha",
596        "Alpha_SoftFloat",
597        "Alpha_HardFloat",
598        "LittleEndian",
599        "BigEndian",
600        "ELFv1",
601        "ELFv2",
602        "CRuntime_Digitalmars",
603        "CRuntime_Glibc",
604        "CRuntime_Microsoft",
605        "CRuntime_Musl",
606        "CRuntime_UClibc",
607        "CppRuntime_Clang",
608        "CppRuntime_DigitalMars",
609        "CppRuntime_Gcc",
610        "CppRuntime_Microsoft",
611        "CppRuntime_Sun",
612        "D_Coverage",
613        "D_Ddoc",
614        "D_InlineAsm_X86",
615        "D_InlineAsm_X86_64",
616        "D_LP64",
617        "D_X32",
618        "D_HardFloat",
619        "D_SoftFloat",
620        "D_PIC",
621        "D_SIMD",
622        "D_Version2",
623        "D_NoBoundsChecks",
624        "unittest",
625        "assert",
626        "all",
627        "none",
628        NULL
629    };
630
631    for (unsigned i = 0; reserved[i]; i++)
632    {
633        if (strcmp(ident, reserved[i]) == 0)
634            return true;
635    }
636
637    if (ident[0] == 'D' && ident[1] == '_')
638        return true;
639    return false;
640}
641
642void checkReserved(Loc loc, const char *ident)
643{
644    if (isReserved(ident))
645        error(loc, "version identifier '%s' is reserved and cannot be set", ident);
646}
647
648void VersionCondition::addGlobalIdent(const char *ident)
649{
650    checkReserved(Loc(), ident);
651    addPredefinedGlobalIdent(ident);
652}
653
654void VersionCondition::addPredefinedGlobalIdent(const char *ident)
655{
656    if (!global.params.versionids)
657        global.params.versionids = new Strings();
658    global.params.versionids->push(ident);
659}
660
661
662VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
663    : DVCondition(mod, level, ident)
664{
665}
666
667int VersionCondition::include(Scope *sc, ScopeDsymbol *)
668{
669    //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
670    //if (ident) printf("\tident = '%s'\n", ident->toChars());
671    if (inc == 0)
672    {
673        inc = 2;
674        bool definedInModule=false;
675        if (ident)
676        {
677            if (findCondition(mod->versionids, ident))
678            {
679                inc = 1;
680                definedInModule = true;
681            }
682            else if (findCondition(global.params.versionids, ident))
683                inc = 1;
684            else
685            {
686                if (!mod->versionidsNot)
687                    mod->versionidsNot = new Strings();
688                mod->versionidsNot->push(ident->toChars());
689            }
690        }
691        else if (level <= global.params.versionlevel || level <= mod->versionlevel)
692            inc = 1;
693        if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
694            printDepsConditional(sc, this, "depsVersion ");
695    }
696    return (inc == 1);
697}
698
699/**************************** StaticIfCondition *******************************/
700
701StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
702    : Condition(loc)
703{
704    this->exp = exp;
705}
706
707Condition *StaticIfCondition::syntaxCopy()
708{
709    return new StaticIfCondition(loc, exp->syntaxCopy());
710}
711
712int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
713{
714    if (inc == 0)
715    {
716        if (!sc)
717        {
718            error(loc, "static if conditional cannot be at global scope");
719            inc = 2;
720            return 0;
721        }
722
723        sc = sc->push(sc->scopesym);
724        sc->sds = sds;                  // sds gets any addMember()
725
726        bool errors = false;
727
728        if (!exp)
729            goto Lerror;
730
731        bool result = evalStaticCondition(sc, exp, exp, errors);
732        sc->pop();
733
734        // Prevent repeated condition evaluation.
735        // See: fail_compilation/fail7815.d
736        if (inc != 0)
737            return (inc == 1);
738        if (errors)
739            goto Lerror;
740        if (result)
741            inc = 1;
742        else
743            inc = 2;
744    }
745    return (inc == 1);
746
747Lerror:
748    if (!global.gag)
749        inc = 2;                // so we don't see the error message again
750    return 0;
751}
752