]>
git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/cond.c
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2020 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
11 #include "root/dsystem.h" // strcmp()
16 #include "aggregate.h"
17 #include "declaration.h"
18 #include "identifier.h"
19 #include "expression.h"
25 #include "statement.h"
26 #include "arraytypes.h"
29 Expression
*semantic(Expression
*e
, Scope
*sc
);
30 bool evalStaticCondition(Scope
*sc
, Expression
*exp
, Expression
*e
, bool &errors
);
32 int findCondition(Strings
*ids
, Identifier
*ident
)
36 for (size_t i
= 0; i
< ids
->dim
; i
++)
38 const char *id
= (*ids
)[i
];
40 if (strcmp(id
, ident
->toChars()) == 0)
48 /* ============================================================ */
50 Condition::Condition(Loc loc
)
56 /* ============================================================ */
58 StaticForeach::StaticForeach(Loc loc
, ForeachStatement
*aggrfe
, ForeachRangeStatement
*rangefe
)
60 assert(!!aggrfe
^ !!rangefe
);
62 this->aggrfe
= aggrfe
;
63 this->rangefe
= rangefe
;
64 this->needExpansion
= false;
67 StaticForeach
*StaticForeach::syntaxCopy()
69 return new StaticForeach(
71 aggrfe
? (ForeachStatement
*)aggrfe
->syntaxCopy() : NULL
,
72 rangefe
? (ForeachRangeStatement
*)rangefe
->syntaxCopy() : NULL
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]) { ... }
81 * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... }
84 static void lowerArrayAggregate(StaticForeach
*sfe
, Scope
*sc
)
86 Expression
*aggr
= sfe
->aggrfe
->aggr
;
87 Expression
*el
= new ArrayLengthExp(aggr
->loc
, aggr
);
89 el
= semantic(el
, sc
);
91 el
= el
->optimize(WANTvalue
);
92 el
= el
->ctfeInterpret();
93 if (el
->op
== TOKint64
)
95 dinteger_t length
= el
->toInteger();
96 Expressions
*es
= new Expressions();
97 for (size_t i
= 0; i
< length
; i
++)
99 IntegerExp
*index
= new IntegerExp(sfe
->loc
, i
, Type::tsize_t
);
100 Expression
*value
= new IndexExp(aggr
->loc
, aggr
, index
);
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
);
109 sfe
->aggrfe
->aggr
= new ErrorExp();
113 /*****************************************
114 * Wrap a statement into a function literal and call it.
117 * loc = The source location.
120 * AST of the expression `(){ s; }()` with location loc.
123 static Expression
*wrapAndCall(Loc loc
, Statement
*s
)
125 TypeFunction
*tf
= new TypeFunction(new Parameters(), NULL
, 0, LINKdefault
, 0);
126 FuncLiteralDeclaration
*fd
= new FuncLiteralDeclaration(loc
, loc
, tf
, TOKreserved
, NULL
);
128 FuncExp
*fe
= new FuncExp(loc
, fd
);
129 Expression
*ce
= new CallExp(loc
, fe
, new Expressions());
133 /*****************************************
134 * Create a `foreach` statement from `aggrefe/rangefe` with given
135 * `foreach` variables and body `s`.
138 * loc = The source location.
139 * parameters = The foreach variables.
140 * s = The `foreach` body.
142 * `foreach (parameters; aggregate) s;` or
143 * `foreach (parameters; lower .. upper) s;`
144 * Where aggregate/lower, upper are as for the current StaticForeach.
147 static Statement
*createForeach(StaticForeach
*sfe
, Loc loc
, Parameters
*parameters
, Statement
*s
)
151 return new ForeachStatement(loc
, sfe
->aggrfe
->op
, parameters
, sfe
->aggrfe
->aggr
->syntaxCopy(), s
, loc
);
155 assert(sfe
->rangefe
&& parameters
->dim
== 1);
156 return new ForeachRangeStatement(loc
, sfe
->rangefe
->op
, (*parameters
)[0],
157 sfe
->rangefe
->lwr
->syntaxCopy(),
158 sfe
->rangefe
->upr
->syntaxCopy(), s
, loc
);
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
171 * loc = The source location.
172 * e = The expressions we wish to store in the tuple.
173 * sc = The current scope.
175 * A struct type of the form
178 * typeof(AliasSeq!(e)) tuple;
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
196 /*****************************************
197 * Create the AST for an instantiation of a suitable tuple type.
200 * loc = The source location.
201 * type = A Tuple type, created with createTupleType.
202 * e = The expressions we wish to store in the tuple.
204 * An AST for the expression `Tuple(e)`.
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
);
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.
220 * For example, `static foreach (x; range) { ... }` is lowered to:
222 * static foreach (x; {
224 * foreach (x; range) return x;
226 * foreach (x; range) __res ~= x;
230 * Finally, call `lowerArrayAggregate` to turn the produced
231 * array into an expression tuple.
234 * sc = The current scope.
237 static void lowerNonArrayAggregate(StaticForeach
*sfe
, Scope
*sc
)
239 size_t nvars
= sfe
->aggrfe
? sfe
->aggrfe
->parameters
->dim
: 1;
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
++)
246 for (size_t j
= 0; j
< 3; j
++)
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
));
254 TypeStruct
*tplty
= NULL
;
255 if (nvars
== 1) // only one `static foreach` variable, generate identifiers.
257 for (size_t i
= 0; i
< 2; i
++)
259 res
[i
] = new IdentifierExp(aloc
, (*pparams
[i
])[0]->ident
);
262 else // multiple `static foreach` variables, generate tuples.
264 for (size_t i
= 0; i
< 2; i
++)
266 Expressions
*e
= new Expressions();
267 for (size_t j
= 0; j
< pparams
[0]->dim
; j
++)
269 Parameter
*p
= (*pparams
[i
])[j
];
270 e
->push(new IdentifierExp(aloc
, p
->ident
));
274 tplty
= createTupleType(aloc
, e
);
276 res
[i
] = createTuple(aloc
, tplty
, e
);
278 sfe
->needExpansion
= true; // need to expand the tuples later
280 // generate remaining code for the new aggregate which is an
281 // array (see documentation comment).
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
);
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();
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
);
315 aggr
= aggr
->optimize(WANTvalue
);
316 aggr
= aggr
->ctfeInterpret();
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
);
323 lowerArrayAggregate(sfe
, sc
); // finally, turn generated array into expression tuple
326 /*****************************************
327 * Perform `static foreach` lowerings that are necessary in order
328 * to finally expand the `static foreach` using
329 * `ddmd.statementsem.makeTupleForeach`.
332 void staticForeachPrepare(StaticForeach
*sfe
, Scope
*sc
)
337 sc
= sc
->startCTFE();
338 sfe
->aggrfe
->aggr
= semantic(sfe
->aggrfe
->aggr
, sc
);
340 sfe
->aggrfe
->aggr
= sfe
->aggrfe
->aggr
->optimize(WANTvalue
);
341 Type
*tab
= sfe
->aggrfe
->aggr
->type
->toBasetype();
342 if (tab
->ty
!= Ttuple
)
344 sfe
->aggrfe
->aggr
= sfe
->aggrfe
->aggr
->ctfeInterpret();
348 if (sfe
->aggrfe
&& sfe
->aggrfe
->aggr
->type
->toBasetype()->ty
== Terror
)
353 if (!staticForeachReady(sfe
))
355 if (sfe
->aggrfe
&& sfe
->aggrfe
->aggr
->type
->toBasetype()->ty
== Tarray
)
357 lowerArrayAggregate(sfe
, sc
);
361 lowerNonArrayAggregate(sfe
, sc
);
366 /*****************************************
368 * `true` iff ready to call `ddmd.statementsem.makeTupleForeach`.
371 bool staticForeachReady(StaticForeach
*sfe
)
373 return sfe
->aggrfe
&& sfe
->aggrfe
->aggr
&& sfe
->aggrfe
->aggr
->type
&&
374 sfe
->aggrfe
->aggr
->type
->toBasetype()->ty
== Ttuple
;
377 /* ============================================================ */
379 DVCondition::DVCondition(Module
*mod
, unsigned level
, Identifier
*ident
)
387 Condition
*DVCondition::syntaxCopy()
389 return this; // don't need to copy
392 /* ============================================================ */
394 void DebugCondition::setGlobalLevel(unsigned level
)
396 global
.params
.debuglevel
= level
;
399 void DebugCondition::addGlobalIdent(const char *ident
)
401 if (!global
.params
.debugids
)
402 global
.params
.debugids
= new Strings();
403 global
.params
.debugids
->push(ident
);
407 DebugCondition::DebugCondition(Module
*mod
, unsigned level
, Identifier
*ident
)
408 : DVCondition(mod
, level
, ident
)
412 // Helper for printing dependency information
413 void printDepsConditional(Scope
*sc
, DVCondition
* condition
, const char* depType
)
415 if (!global
.params
.moduleDeps
|| global
.params
.moduleDepsFile
)
417 OutBuffer
*ob
= global
.params
.moduleDeps
;
418 Module
* imod
= sc
? sc
->instantiatingModule() : condition
->mod
;
421 ob
->writestring(depType
);
422 ob
->writestring(imod
->toPrettyChars());
423 ob
->writestring(" (");
424 escapePath(ob
, imod
->srcfile
->toChars());
425 ob
->writestring(") : ");
426 if (condition
->ident
)
427 ob
->printf("%s\n", condition
->ident
->toChars());
429 ob
->printf("%d\n", condition
->level
);
433 int DebugCondition::include(Scope
*sc
, ScopeDsymbol
*)
435 //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
439 bool definedInModule
= false;
442 if (findCondition(mod
->debugids
, ident
))
445 definedInModule
= true;
447 else if (findCondition(global
.params
.debugids
, ident
))
450 { if (!mod
->debugidsNot
)
451 mod
->debugidsNot
= new Strings();
452 mod
->debugidsNot
->push(ident
->toChars());
455 else if (level
<= global
.params
.debuglevel
|| level
<= mod
->debuglevel
)
457 if (!definedInModule
)
458 printDepsConditional(sc
, this, "depsDebug ");
463 /* ============================================================ */
465 void VersionCondition::setGlobalLevel(unsigned level
)
467 global
.params
.versionlevel
= level
;
470 static bool isReserved(const char *ident
)
472 static const char* reserved
[] =
547 "CRuntime_Digitalmars",
549 "CRuntime_Microsoft",
553 "CppRuntime_DigitalMars",
555 "CppRuntime_Microsoft",
560 "D_InlineAsm_X86_64",
576 for (unsigned i
= 0; reserved
[i
]; i
++)
578 if (strcmp(ident
, reserved
[i
]) == 0)
582 if (ident
[0] == 'D' && ident
[1] == '_')
587 void checkReserved(Loc loc
, const char *ident
)
589 if (isReserved(ident
))
590 error(loc
, "version identifier '%s' is reserved and cannot be set", ident
);
593 void VersionCondition::addGlobalIdent(const char *ident
)
595 checkReserved(Loc(), ident
);
596 addPredefinedGlobalIdent(ident
);
599 void VersionCondition::addPredefinedGlobalIdent(const char *ident
)
601 if (!global
.params
.versionids
)
602 global
.params
.versionids
= new Strings();
603 global
.params
.versionids
->push(ident
);
607 VersionCondition::VersionCondition(Module
*mod
, unsigned level
, Identifier
*ident
)
608 : DVCondition(mod
, level
, ident
)
612 int VersionCondition::include(Scope
*sc
, ScopeDsymbol
*)
614 //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
615 //if (ident) printf("\tident = '%s'\n", ident->toChars());
619 bool definedInModule
=false;
622 if (findCondition(mod
->versionids
, ident
))
625 definedInModule
= true;
627 else if (findCondition(global
.params
.versionids
, ident
))
631 if (!mod
->versionidsNot
)
632 mod
->versionidsNot
= new Strings();
633 mod
->versionidsNot
->push(ident
->toChars());
636 else if (level
<= global
.params
.versionlevel
|| level
<= mod
->versionlevel
)
638 if (!definedInModule
&& (!ident
|| (!isReserved(ident
->toChars()) && ident
!= Id::_unittest
&& ident
!= Id::_assert
)))
639 printDepsConditional(sc
, this, "depsVersion ");
644 /**************************** StaticIfCondition *******************************/
646 StaticIfCondition::StaticIfCondition(Loc loc
, Expression
*exp
)
652 Condition
*StaticIfCondition::syntaxCopy()
654 return new StaticIfCondition(loc
, exp
->syntaxCopy());
657 int StaticIfCondition::include(Scope
*sc
, ScopeDsymbol
*sds
)
663 error(loc
, "static if conditional cannot be at global scope");
668 sc
= sc
->push(sc
->scopesym
);
669 sc
->sds
= sds
; // sds gets any addMember()
672 bool result
= evalStaticCondition(sc
, exp
, exp
, errors
);
675 // Prevent repeated condition evaluation.
676 // See: fail_compilation/fail7815.d
690 inc
= 2; // so we don't see the error message again