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