]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
2 | /* Compiler implementation of the D programming language | |
a3b38b77 | 3 | * Copyright (C) 1999-2021 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 | ||
b4c522fa IB |
29 | bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors); |
30 | ||
5bc13e52 | 31 | int findCondition(Identifiers *ids, Identifier *ident) |
b4c522fa IB |
32 | { |
33 | if (ids) | |
34 | { | |
2cbc99d1 | 35 | for (size_t i = 0; i < ids->length; i++) |
b4c522fa | 36 | { |
5bc13e52 | 37 | Identifier *id = (*ids)[i]; |
b4c522fa | 38 | |
5bc13e52 | 39 | if (id == ident) |
b4c522fa IB |
40 | return true; |
41 | } | |
42 | } | |
43 | ||
44 | return false; | |
45 | } | |
46 | ||
47 | /* ============================================================ */ | |
48 | ||
49 | Condition::Condition(Loc loc) | |
50 | { | |
51 | this->loc = loc; | |
52 | inc = 0; | |
53 | } | |
54 | ||
55 | /* ============================================================ */ | |
56 | ||
5b74dd0a IB |
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 | ||
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 | ||
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(); | |
a3b38b77 | 88 | el = expressionSemantic(el, sc); |
5b74dd0a IB |
89 | sc = sc->endCTFE(); |
90 | el = el->optimize(WANTvalue); | |
91 | el = el->ctfeInterpret(); | |
92 | if (el->op == TOKint64) | |
93 | { | |
ce56fd94 IB |
94 | Expressions *es; |
95 | if (ArrayLiteralExp *ale = aggr->isArrayLiteralExp()) | |
5b74dd0a | 96 | { |
ce56fd94 IB |
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 | } | |
5b74dd0a IB |
111 | } |
112 | sfe->aggrfe->aggr = new TupleExp(aggr->loc, es); | |
a3b38b77 | 113 | sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc); |
5b74dd0a | 114 | sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue); |
68f46862 | 115 | sfe->aggrfe->aggr = sfe->aggrfe->aggr->ctfeInterpret(); |
5b74dd0a IB |
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 | ||
133 | static Expression *wrapAndCall(Loc loc, Statement *s) | |
134 | { | |
c3a2ba10 | 135 | TypeFunction *tf = new TypeFunction(ParameterList(), NULL, LINKdefault, 0); |
5b74dd0a IB |
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 | ||
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 | { | |
2cbc99d1 | 165 | assert(sfe->rangefe && parameters->length == 1); |
5b74dd0a IB |
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 | ||
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; | |
68f46862 IB |
202 | if (global.params.useTypeInfo && Type::dtypeinfo) |
203 | r->vtinfo = TypeInfoStructDeclaration::create(r); // prevent typeinfo from going to object file | |
5b74dd0a IB |
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 | ||
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 | ||
248 | static void lowerNonArrayAggregate(StaticForeach *sfe, Scope *sc) | |
249 | { | |
2cbc99d1 | 250 | size_t nvars = sfe->aggrfe ? sfe->aggrfe->parameters->length : 1; |
5b74dd0a IB |
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; | |
dddea6d4 | 261 | params->push(new Parameter(p->storageClass, p->type, p->ident, NULL, NULL)); |
5b74dd0a IB |
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(); | |
2cbc99d1 | 278 | for (size_t j = 0; j < pparams[0]->length; j++) |
5b74dd0a IB |
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(); | |
a3b38b77 | 296 | sfe->rangefe->lwr = expressionSemantic(sfe->rangefe->lwr, sc); |
5b74dd0a | 297 | sfe->rangefe->lwr = resolveProperties(sc, sfe->rangefe->lwr); |
a3b38b77 | 298 | sfe->rangefe->upr = expressionSemantic(sfe->rangefe->upr, sc); |
5b74dd0a IB |
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(); | |
68f46862 IB |
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 | } | |
ce56fd94 IB |
331 | |
332 | Expression *aggr; | |
333 | Type *indexty; | |
334 | ||
68f46862 | 335 | if (sfe->rangefe && (indexty = ety)->isintegral()) |
ce56fd94 IB |
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(); | |
a3b38b77 | 369 | aggr = expressionSemantic(aggr, sc); |
ce56fd94 IB |
370 | aggr = resolveProperties(sc, aggr); |
371 | sc = sc->endCTFE(); | |
372 | aggr = aggr->optimize(WANTvalue); | |
373 | aggr = aggr->ctfeInterpret(); | |
374 | } | |
5b74dd0a IB |
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 | ||
390 | void staticForeachPrepare(StaticForeach *sfe, Scope *sc) | |
391 | { | |
392 | assert(sc); | |
393 | if (sfe->aggrfe) | |
394 | { | |
395 | sc = sc->startCTFE(); | |
a3b38b77 | 396 | sfe->aggrfe->aggr = expressionSemantic(sfe->aggrfe->aggr, sc); |
5b74dd0a IB |
397 | sc = sc->endCTFE(); |
398 | sfe->aggrfe->aggr = sfe->aggrfe->aggr->optimize(WANTvalue); | |
5b74dd0a IB |
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 | ||
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 | ||
b4c522fa IB |
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 | ||
440 | Condition *DVCondition::syntaxCopy() | |
441 | { | |
442 | return this; // don't need to copy | |
443 | } | |
444 | ||
445 | /* ============================================================ */ | |
446 | ||
b4c522fa IB |
447 | void DebugCondition::addGlobalIdent(const char *ident) |
448 | { | |
5bc13e52 IB |
449 | if (!global.debugids) |
450 | global.debugids = new Identifiers(); | |
451 | global.debugids->push(Identifier::idPool(ident)); | |
b4c522fa IB |
452 | } |
453 | ||
454 | ||
455 | DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) | |
456 | : DVCondition(mod, level, ident) | |
457 | { | |
458 | } | |
459 | ||
460 | // Helper for printing dependency information | |
461 | void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType) | |
462 | { | |
d8930b13 | 463 | if (!global.params.moduleDeps || global.params.moduleDepsFile.length) |
b4c522fa IB |
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 | ||
d3da83f6 | 481 | int DebugCondition::include(Scope *sc) |
b4c522fa IB |
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 | } | |
5bc13e52 | 495 | else if (findCondition(global.debugids, ident)) |
b4c522fa IB |
496 | inc = 1; |
497 | else | |
498 | { if (!mod->debugidsNot) | |
5bc13e52 IB |
499 | mod->debugidsNot = new Identifiers(); |
500 | mod->debugidsNot->push(ident); | |
b4c522fa IB |
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 | ||
b4c522fa IB |
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", | |
9503d7b1 IB |
540 | "PlayStation", |
541 | "PlayStation4", | |
b4c522fa IB |
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", | |
9503d7b1 | 568 | "MSP430", |
b4c522fa IB |
569 | "NVPTX", |
570 | "NVPTX64", | |
9503d7b1 IB |
571 | "RISCV32", |
572 | "RISCV64", | |
b4c522fa IB |
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", | |
9503d7b1 IB |
593 | "CRuntime_Musl", |
594 | "CRuntime_UClibc", | |
595 | "CppRuntime_Clang", | |
596 | "CppRuntime_DigitalMars", | |
597 | "CppRuntime_Gcc", | |
598 | "CppRuntime_Microsoft", | |
599 | "CppRuntime_Sun", | |
b4c522fa IB |
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 | ||
630 | void checkReserved(Loc loc, const char *ident) | |
631 | { | |
632 | if (isReserved(ident)) | |
a3b38b77 | 633 | error(loc, "version identifier `%s` is reserved and cannot be set", ident); |
b4c522fa IB |
634 | } |
635 | ||
636 | void VersionCondition::addGlobalIdent(const char *ident) | |
637 | { | |
638 | checkReserved(Loc(), ident); | |
639 | addPredefinedGlobalIdent(ident); | |
640 | } | |
641 | ||
642 | void VersionCondition::addPredefinedGlobalIdent(const char *ident) | |
643 | { | |
5bc13e52 IB |
644 | if (!global.versionids) |
645 | global.versionids = new Identifiers(); | |
646 | global.versionids->push(Identifier::idPool(ident)); | |
b4c522fa IB |
647 | } |
648 | ||
649 | ||
650 | VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) | |
651 | : DVCondition(mod, level, ident) | |
652 | { | |
653 | } | |
654 | ||
d3da83f6 | 655 | int VersionCondition::include(Scope *sc) |
b4c522fa IB |
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 | } | |
5bc13e52 | 670 | else if (findCondition(global.versionids, ident)) |
b4c522fa IB |
671 | inc = 1; |
672 | else | |
673 | { | |
674 | if (!mod->versionidsNot) | |
5bc13e52 IB |
675 | mod->versionidsNot = new Identifiers(); |
676 | mod->versionidsNot->push(ident); | |
b4c522fa IB |
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 | ||
689 | StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) | |
690 | : Condition(loc) | |
691 | { | |
692 | this->exp = exp; | |
b4c522fa IB |
693 | } |
694 | ||
695 | Condition *StaticIfCondition::syntaxCopy() | |
696 | { | |
697 | return new StaticIfCondition(loc, exp->syntaxCopy()); | |
698 | } | |
699 | ||
d3da83f6 | 700 | int StaticIfCondition::include(Scope *sc) |
b4c522fa IB |
701 | { |
702 | if (inc == 0) | |
703 | { | |
b4c522fa IB |
704 | if (!sc) |
705 | { | |
706 | error(loc, "static if conditional cannot be at global scope"); | |
707 | inc = 2; | |
708 | return 0; | |
709 | } | |
710 | ||
b4c522fa | 711 | sc = sc->push(sc->scopesym); |
b4c522fa IB |
712 | |
713 | bool errors = false; | |
27d8c351 IB |
714 | |
715 | if (!exp) | |
716 | goto Lerror; | |
717 | ||
b4c522fa IB |
718 | bool result = evalStaticCondition(sc, exp, exp, errors); |
719 | sc->pop(); | |
b4c522fa IB |
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 | } |