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