xref: /netbsd/external/gpl3/gcc/dist/gcc/d/dmd/cond.c (revision 7327edaf)
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         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 
wrapAndCall(Loc loc,Statement * s)135 static 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 
createForeach(StaticForeach * sfe,Loc loc,Parameters * parameters,Statement * s)159 static 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 
createTupleType(Loc loc,Expressions * e)194 static 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 
createTuple(Loc loc,TypeStruct * type,Expressions * e)220 static 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 
lowerNonArrayAggregate(StaticForeach * sfe,Scope * sc)250 static 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 
staticForeachPrepare(StaticForeach * sfe,Scope * sc)392 void 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 
staticForeachReady(StaticForeach * sfe)426 bool 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 
DVCondition(Module * mod,unsigned level,Identifier * ident)434 DVCondition::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 
syntaxCopy()442 Condition *DVCondition::syntaxCopy()
443 {
444     return this;        // don't need to copy
445 }
446 
447 /* ============================================================ */
448 
setGlobalLevel(unsigned level)449 void DebugCondition::setGlobalLevel(unsigned level)
450 {
451     global.params.debuglevel = level;
452 }
453 
addGlobalIdent(const char * ident)454 void 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 
DebugCondition(Module * mod,unsigned level,Identifier * ident)462 DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
463     : DVCondition(mod, level, ident)
464 {
465 }
466 
467 // Helper for printing dependency information
printDepsConditional(Scope * sc,DVCondition * condition,const char * depType)468 void 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 
include(Scope * sc,ScopeDsymbol *)488 int 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 
setGlobalLevel(unsigned level)520 void VersionCondition::setGlobalLevel(unsigned level)
521 {
522     global.params.versionlevel = level;
523 }
524 
isReserved(const char * ident)525 static 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 
checkReserved(Loc loc,const char * ident)642 void 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 
addGlobalIdent(const char * ident)648 void VersionCondition::addGlobalIdent(const char *ident)
649 {
650     checkReserved(Loc(), ident);
651     addPredefinedGlobalIdent(ident);
652 }
653 
addPredefinedGlobalIdent(const char * ident)654 void 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 
VersionCondition(Module * mod,unsigned level,Identifier * ident)662 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
663     : DVCondition(mod, level, ident)
664 {
665 }
666 
include(Scope * sc,ScopeDsymbol *)667 int 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 
StaticIfCondition(Loc loc,Expression * exp)701 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
702     : Condition(loc)
703 {
704     this->exp = exp;
705 }
706 
syntaxCopy()707 Condition *StaticIfCondition::syntaxCopy()
708 {
709     return new StaticIfCondition(loc, exp->syntaxCopy());
710 }
711 
include(Scope * sc,ScopeDsymbol * sds)712 int 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 
747 Lerror:
748     if (!global.gag)
749         inc = 2;                // so we don't see the error message again
750     return 0;
751 }
752