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