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