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