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 
29 Expression *semantic(Expression *e, Scope *sc);
30 bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
31 
findCondition(Strings * ids,Identifier * ident)32 int 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 
Condition(Loc loc)50 Condition::Condition(Loc loc)
51 {
52     this->loc = loc;
53     inc = 0;
54 }
55 
56 /* ============================================================ */
57 
StaticForeach(Loc loc,ForeachStatement * aggrfe,ForeachRangeStatement * rangefe)58 StaticForeach::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 
syntaxCopy()67 StaticForeach *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 
lowerArrayAggregate(StaticForeach * sfe,Scope * sc)84 static 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     }
118     else
119     {
120         sfe->aggrfe->aggr = new ErrorExp();
121     }
122 }
123 
124 /*****************************************
125  * Wrap a statement into a function literal and call it.
126  *
127  * Params:
128  *     loc = The source location.
129  *     s  = The statement.
130  * Returns:
131  *     AST of the expression `(){ s; }()` with location loc.
132  */
133 
wrapAndCall(Loc loc,Statement * s)134 static Expression *wrapAndCall(Loc loc, Statement *s)
135 {
136     TypeFunction *tf = new TypeFunction(new Parameters(), NULL, 0, LINKdefault, 0);
137     FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, loc, tf, TOKreserved, NULL);
138     fd->fbody = s;
139     FuncExp *fe = new FuncExp(loc, fd);
140     Expression *ce = new CallExp(loc, fe, new Expressions());
141     return ce;
142 }
143 
144 /*****************************************
145  * Create a `foreach` statement from `aggrefe/rangefe` with given
146  * `foreach` variables and body `s`.
147  *
148  * Params:
149  *     loc = The source location.
150  *     parameters = The foreach variables.
151  *     s = The `foreach` body.
152  * Returns:
153  *     `foreach (parameters; aggregate) s;` or
154  *     `foreach (parameters; lower .. upper) s;`
155  *     Where aggregate/lower, upper are as for the current StaticForeach.
156  */
157 
createForeach(StaticForeach * sfe,Loc loc,Parameters * parameters,Statement * s)158 static Statement *createForeach(StaticForeach *sfe, Loc loc, Parameters *parameters, Statement *s)
159 {
160     if (sfe->aggrfe)
161     {
162         return new ForeachStatement(loc, sfe->aggrfe->op, parameters, sfe->aggrfe->aggr->syntaxCopy(), s, loc);
163     }
164     else
165     {
166         assert(sfe->rangefe && parameters->dim == 1);
167         return new ForeachRangeStatement(loc, sfe->rangefe->op, (*parameters)[0],
168                                          sfe->rangefe->lwr->syntaxCopy(),
169                                          sfe->rangefe->upr->syntaxCopy(), s, loc);
170     }
171 }
172 
173 /*****************************************
174  * For a `static foreach` with multiple loop variables, the
175  * aggregate is lowered to an array of tuples. As D does not have
176  * built-in tuples, we need a suitable tuple type. This generates
177  * a `struct` that serves as the tuple type. This type is only
178  * used during CTFE and hence its typeinfo will not go to the
179  * object file.
180  *
181  * Params:
182  *     loc = The source location.
183  *     e = The expressions we wish to store in the tuple.
184  *     sc  = The current scope.
185  * Returns:
186  *     A struct type of the form
187  *         struct Tuple
188  *         {
189  *             typeof(AliasSeq!(e)) tuple;
190  *         }
191  */
192 
createTupleType(Loc loc,Expressions * e)193 static TypeStruct *createTupleType(Loc loc, Expressions *e)
194 {   // TODO: move to druntime?
195     Identifier *sid = Identifier::generateId("Tuple");
196     StructDeclaration *sdecl = new StructDeclaration(loc, sid, false);
197     sdecl->storage_class |= STCstatic;
198     sdecl->members = new Dsymbols();
199     Identifier *fid = Identifier::idPool("tuple");
200     Type *ty = new TypeTypeof(loc, new TupleExp(loc, e));
201     sdecl->members->push(new VarDeclaration(loc, ty, fid, NULL));
202     TypeStruct *r = (TypeStruct *)sdecl->type;
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->dim : 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));
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]->dim; 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 = semantic(sfe->rangefe->lwr, sc);
297         sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr);
298         sfe->rangefe->upr = semantic(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     s2->push(new ExpStatement(aloc, vard));
318     Expression *catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]);
319     s2->push(createForeach(sfe, aloc, pparams[1], new ExpStatement(aloc, catass)));
320     s2->push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres)));
321 
322     Expression *aggr;
323     Type *indexty;
324 
325     if (sfe->rangefe && (indexty = ety->semantic(aloc, sc))->isintegral())
326     {
327         sfe->rangefe->lwr->type = indexty;
328         sfe->rangefe->upr->type = indexty;
329         IntRange lwrRange = getIntRange(sfe->rangefe->lwr);
330         IntRange uprRange = getIntRange(sfe->rangefe->upr);
331 
332         const dinteger_t lwr = sfe->rangefe->lwr->toInteger();
333         dinteger_t upr = sfe->rangefe->upr->toInteger();
334         size_t length = 0;
335 
336         if (lwrRange.imin <= uprRange.imax)
337             length = (size_t)(upr - lwr);
338 
339         Expressions *exps = new Expressions();
340         exps->setDim(length);
341 
342         if (sfe->rangefe->op == TOKforeach)
343         {
344             for (size_t i = 0; i < length; i++)
345                 (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty);
346         }
347         else
348         {
349             --upr;
350             for (size_t i = 0; i < length; i++)
351                 (*exps)[i] = new IntegerExp(aloc, upr - i, indexty);
352         }
353         aggr = new ArrayLiteralExp(aloc, indexty->arrayOf(), exps);
354     }
355     else
356     {
357         aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2));
358         sc = sc->startCTFE();
359         aggr = semantic(aggr, sc);
360         aggr = resolveProperties(sc, aggr);
361         sc = sc->endCTFE();
362         aggr = aggr->optimize(WANTvalue);
363         aggr = aggr->ctfeInterpret();
364     }
365 
366     assert(!!sfe->aggrfe ^ !!sfe->rangefe);
367     sfe->aggrfe = new ForeachStatement(sfe->loc, TOKforeach, pparams[2], aggr,
368                                   sfe->aggrfe ? sfe->aggrfe->_body : sfe->rangefe->_body,
369                                   sfe->aggrfe ? sfe->aggrfe->endloc : sfe->rangefe->endloc);
370     sfe->rangefe = NULL;
371     lowerArrayAggregate(sfe, sc); // finally, turn generated array into expression tuple
372 }
373 
374 /*****************************************
375  * Perform `static foreach` lowerings that are necessary in order
376  * to finally expand the `static foreach` using
377  * `ddmd.statementsem.makeTupleForeach`.
378  */
379 
staticForeachPrepare(StaticForeach * sfe,Scope * sc)380 void staticForeachPrepare(StaticForeach *sfe, Scope *sc)
381 {
382     assert(sc);
383     if (sfe->aggrfe)
384     {
385         sc = sc->startCTFE();
386         sfe->aggrfe->aggr = semantic(sfe->aggrfe->aggr, sc);
387         sc = sc->endCTFE();
388         sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue);
389         Type *tab = sfe->aggrfe->aggr->type->toBasetype();
390         if (tab->ty != Ttuple)
391         {
392             sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret();
393         }
394     }
395 
396     if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Terror)
397     {
398         return;
399     }
400 
401     if (!staticForeachReady(sfe))
402     {
403         if (sfe->aggrfe && sfe->aggrfe->aggr->type->toBasetype()->ty == Tarray)
404         {
405             lowerArrayAggregate(sfe, sc);
406         }
407         else
408         {
409             lowerNonArrayAggregate(sfe, sc);
410         }
411     }
412 }
413 
414 /*****************************************
415  * Returns:
416  *     `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
417  */
418 
staticForeachReady(StaticForeach * sfe)419 bool staticForeachReady(StaticForeach *sfe)
420 {
421     return sfe->aggrfe && sfe->aggrfe->aggr && sfe->aggrfe->aggr->type &&
422         sfe->aggrfe->aggr->type->toBasetype()->ty == Ttuple;
423 }
424 
425 /* ============================================================ */
426 
DVCondition(Module * mod,unsigned level,Identifier * ident)427 DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident)
428         : Condition(Loc())
429 {
430     this->mod = mod;
431     this->level = level;
432     this->ident = ident;
433 }
434 
syntaxCopy()435 Condition *DVCondition::syntaxCopy()
436 {
437     return this;        // don't need to copy
438 }
439 
440 /* ============================================================ */
441 
setGlobalLevel(unsigned level)442 void DebugCondition::setGlobalLevel(unsigned level)
443 {
444     global.params.debuglevel = level;
445 }
446 
addGlobalIdent(const char * ident)447 void DebugCondition::addGlobalIdent(const char *ident)
448 {
449     if (!global.params.debugids)
450         global.params.debugids = new Strings();
451     global.params.debugids->push(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)
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,ScopeDsymbol *)481 int DebugCondition::include(Scope *sc, ScopeDsymbol *)
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.params.debugids, ident))
496                 inc = 1;
497             else
498             {   if (!mod->debugidsNot)
499                     mod->debugidsNot = new Strings();
500                 mod->debugidsNot->push(ident->toChars());
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 
setGlobalLevel(unsigned level)513 void VersionCondition::setGlobalLevel(unsigned level)
514 {
515     global.params.versionlevel = level;
516 }
517 
isReserved(const char * ident)518 static bool isReserved(const char *ident)
519 {
520     static const char* reserved[] =
521     {
522         "DigitalMars",
523         "GNU",
524         "LDC",
525         "SDC",
526         "Windows",
527         "Win32",
528         "Win64",
529         "linux",
530         "OSX",
531         "FreeBSD",
532         "OpenBSD",
533         "NetBSD",
534         "DragonFlyBSD",
535         "BSD",
536         "Solaris",
537         "Posix",
538         "AIX",
539         "Haiku",
540         "SkyOS",
541         "SysV3",
542         "SysV4",
543         "Hurd",
544         "Android",
545         "PlayStation",
546         "PlayStation4",
547         "Cygwin",
548         "MinGW",
549         "FreeStanding",
550         "X86",
551         "X86_64",
552         "ARM",
553         "ARM_Thumb",
554         "ARM_SoftFloat",
555         "ARM_SoftFP",
556         "ARM_HardFloat",
557         "AArch64",
558         "Epiphany",
559         "PPC",
560         "PPC_SoftFloat",
561         "PPC_HardFloat",
562         "PPC64",
563         "IA64",
564         "MIPS32",
565         "MIPS64",
566         "MIPS_O32",
567         "MIPS_N32",
568         "MIPS_O64",
569         "MIPS_N64",
570         "MIPS_EABI",
571         "MIPS_SoftFloat",
572         "MIPS_HardFloat",
573         "MSP430",
574         "NVPTX",
575         "NVPTX64",
576         "RISCV32",
577         "RISCV64",
578         "SPARC",
579         "SPARC_V8Plus",
580         "SPARC_SoftFloat",
581         "SPARC_HardFloat",
582         "SPARC64",
583         "S390",
584         "S390X",
585         "HPPA",
586         "HPPA64",
587         "SH",
588         "Alpha",
589         "Alpha_SoftFloat",
590         "Alpha_HardFloat",
591         "LittleEndian",
592         "BigEndian",
593         "ELFv1",
594         "ELFv2",
595         "CRuntime_Digitalmars",
596         "CRuntime_Glibc",
597         "CRuntime_Microsoft",
598         "CRuntime_Musl",
599         "CRuntime_UClibc",
600         "CppRuntime_Clang",
601         "CppRuntime_DigitalMars",
602         "CppRuntime_Gcc",
603         "CppRuntime_Microsoft",
604         "CppRuntime_Sun",
605         "D_Coverage",
606         "D_Ddoc",
607         "D_InlineAsm_X86",
608         "D_InlineAsm_X86_64",
609         "D_LP64",
610         "D_X32",
611         "D_HardFloat",
612         "D_SoftFloat",
613         "D_PIC",
614         "D_SIMD",
615         "D_Version2",
616         "D_NoBoundsChecks",
617         "unittest",
618         "assert",
619         "all",
620         "none",
621         NULL
622     };
623 
624     for (unsigned i = 0; reserved[i]; i++)
625     {
626         if (strcmp(ident, reserved[i]) == 0)
627             return true;
628     }
629 
630     if (ident[0] == 'D' && ident[1] == '_')
631         return true;
632     return false;
633 }
634 
checkReserved(Loc loc,const char * ident)635 void checkReserved(Loc loc, const char *ident)
636 {
637     if (isReserved(ident))
638         error(loc, "version identifier '%s' is reserved and cannot be set", ident);
639 }
640 
addGlobalIdent(const char * ident)641 void VersionCondition::addGlobalIdent(const char *ident)
642 {
643     checkReserved(Loc(), ident);
644     addPredefinedGlobalIdent(ident);
645 }
646 
addPredefinedGlobalIdent(const char * ident)647 void VersionCondition::addPredefinedGlobalIdent(const char *ident)
648 {
649     if (!global.params.versionids)
650         global.params.versionids = new Strings();
651     global.params.versionids->push(ident);
652 }
653 
654 
VersionCondition(Module * mod,unsigned level,Identifier * ident)655 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
656     : DVCondition(mod, level, ident)
657 {
658 }
659 
include(Scope * sc,ScopeDsymbol *)660 int VersionCondition::include(Scope *sc, ScopeDsymbol *)
661 {
662     //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
663     //if (ident) printf("\tident = '%s'\n", ident->toChars());
664     if (inc == 0)
665     {
666         inc = 2;
667         bool definedInModule=false;
668         if (ident)
669         {
670             if (findCondition(mod->versionids, ident))
671             {
672                 inc = 1;
673                 definedInModule = true;
674             }
675             else if (findCondition(global.params.versionids, ident))
676                 inc = 1;
677             else
678             {
679                 if (!mod->versionidsNot)
680                     mod->versionidsNot = new Strings();
681                 mod->versionidsNot->push(ident->toChars());
682             }
683         }
684         else if (level <= global.params.versionlevel || level <= mod->versionlevel)
685             inc = 1;
686         if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert)))
687             printDepsConditional(sc, this, "depsVersion ");
688     }
689     return (inc == 1);
690 }
691 
692 /**************************** StaticIfCondition *******************************/
693 
StaticIfCondition(Loc loc,Expression * exp)694 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
695     : Condition(loc)
696 {
697     this->exp = exp;
698 }
699 
syntaxCopy()700 Condition *StaticIfCondition::syntaxCopy()
701 {
702     return new StaticIfCondition(loc, exp->syntaxCopy());
703 }
704 
include(Scope * sc,ScopeDsymbol * sds)705 int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds)
706 {
707     if (inc == 0)
708     {
709         if (!sc)
710         {
711             error(loc, "static if conditional cannot be at global scope");
712             inc = 2;
713             return 0;
714         }
715 
716         sc = sc->push(sc->scopesym);
717         sc->sds = sds;                  // sds gets any addMember()
718 
719         bool errors = false;
720         bool result = evalStaticCondition(sc, exp, exp, errors);
721         sc->pop();
722 
723         // Prevent repeated condition evaluation.
724         // See: fail_compilation/fail7815.d
725         if (inc != 0)
726             return (inc == 1);
727         if (errors)
728             goto Lerror;
729         if (result)
730             inc = 1;
731         else
732             inc = 2;
733     }
734     return (inc == 1);
735 
736 Lerror:
737     if (!global.gag)
738         inc = 2;                // so we don't see the error message again
739     return 0;
740 }
741