]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/dmd/cond.c
d: Merge upstream dmd 740f3d1ea.
[thirdparty/gcc.git] / gcc / d / dmd / cond.c
CommitLineData
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
29Expression *semantic(Expression *e, Scope *sc);
30bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors);
31
5bc13e52 32int 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
50Condition::Condition(Loc loc)
51{
52 this->loc = loc;
53 inc = 0;
54}
55
56/* ============================================================ */
57
5b74dd0a
IB
58StaticForeach::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
67StaticForeach *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
84static 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
123static 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
147static 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
182static 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
207static 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
237static 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
332void 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
371bool 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
379DVCondition::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
387Condition *DVCondition::syntaxCopy()
388{
389 return this; // don't need to copy
390}
391
392/* ============================================================ */
393
b4c522fa
IB
394void 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
402DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident)
403 : DVCondition(mod, level, ident)
404{
405}
406
407// Helper for printing dependency information
408void 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 428int 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
460static 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
577void 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
583void VersionCondition::addGlobalIdent(const char *ident)
584{
585 checkReserved(Loc(), ident);
586 addPredefinedGlobalIdent(ident);
587}
588
589void 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
597VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident)
598 : DVCondition(mod, level, ident)
599{
600}
601
d3da83f6 602int 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
636StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp)
637 : Condition(loc)
638{
639 this->exp = exp;
b4c522fa
IB
640}
641
642Condition *StaticIfCondition::syntaxCopy()
643{
644 return new StaticIfCondition(loc, exp->syntaxCopy());
645}
646
d3da83f6 647int 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
677Lerror:
678 if (!global.gag)
679 inc = 2; // so we don't see the error message again
680 return 0;
681}