1 1.1 mrg /** 2 1.1 mrg * Evaluate compile-time conditionals, such as `static if` `version` and `debug`. 3 1.1 mrg * 4 1.1 mrg * Specification: $(LINK2 https://dlang.org/spec/version.html, Conditional Compilation) 5 1.1 mrg * 6 1.1 mrg * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved 7 1.1 mrg * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 1.1 mrg * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 1.1 mrg * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cond.d, _cond.d) 10 1.1 mrg * Documentation: https://dlang.org/phobos/dmd_cond.html 11 1.1 mrg * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cond.d 12 1.1 mrg */ 13 1.1 mrg 14 1.1 mrg module dmd.cond; 15 1.1 mrg 16 1.1 mrg import core.stdc.string; 17 1.1 mrg import dmd.arraytypes; 18 1.1 mrg import dmd.astenums; 19 1.1 mrg import dmd.ast_node; 20 1.1 mrg import dmd.dcast; 21 1.1 mrg import dmd.dmodule; 22 1.1 mrg import dmd.dscope; 23 1.1 mrg import dmd.dsymbol; 24 1.1 mrg import dmd.errors; 25 1.1 mrg import dmd.expression; 26 1.1 mrg import dmd.expressionsem; 27 1.1 mrg import dmd.globals; 28 1.1 mrg import dmd.identifier; 29 1.1 mrg import dmd.mtype; 30 1.1 mrg import dmd.typesem; 31 1.1 mrg import dmd.common.outbuffer; 32 1.1 mrg import dmd.root.rootobject; 33 1.1 mrg import dmd.root.string; 34 1.1 mrg import dmd.tokens; 35 1.1 mrg import dmd.utils; 36 1.1 mrg import dmd.visitor; 37 1.1 mrg import dmd.id; 38 1.1 mrg import dmd.statement; 39 1.1 mrg import dmd.declaration; 40 1.1 mrg import dmd.dstruct; 41 1.1 mrg import dmd.func; 42 1.1 mrg 43 1.1 mrg /*********************************************************** 44 1.1 mrg */ 45 1.1 mrg 46 1.1 mrg enum Include : ubyte 47 1.1 mrg { 48 1.1 mrg notComputed, /// not computed yet 49 1.1 mrg yes, /// include the conditional code 50 1.1 mrg no, /// do not include the conditional code 51 1.1 mrg } 52 1.1 mrg 53 1.1 mrg extern (C++) abstract class Condition : ASTNode 54 1.1 mrg { 55 1.1 mrg Loc loc; 56 1.1 mrg 57 1.1 mrg Include inc; 58 1.1 mrg 59 1.1 mrg override final DYNCAST dyncast() const 60 1.1 mrg { 61 1.1 mrg return DYNCAST.condition; 62 1.1 mrg } 63 1.1 mrg 64 1.1 mrg extern (D) this(const ref Loc loc) 65 1.1 mrg { 66 1.1 mrg this.loc = loc; 67 1.1 mrg } 68 1.1 mrg 69 1.1 mrg abstract Condition syntaxCopy(); 70 1.1 mrg 71 1.1 mrg abstract int include(Scope* sc); 72 1.1 mrg 73 1.1 mrg inout(DebugCondition) isDebugCondition() inout 74 1.1 mrg { 75 1.1 mrg return null; 76 1.1 mrg } 77 1.1 mrg 78 1.1 mrg inout(VersionCondition) isVersionCondition() inout 79 1.1 mrg { 80 1.1 mrg return null; 81 1.1 mrg } 82 1.1 mrg 83 1.1 mrg override void accept(Visitor v) 84 1.1 mrg { 85 1.1 mrg v.visit(this); 86 1.1 mrg } 87 1.1 mrg } 88 1.1 mrg 89 1.1 mrg /*********************************************************** 90 1.1 mrg * Implements common functionality for StaticForeachDeclaration and 91 1.1 mrg * StaticForeachStatement This performs the necessary lowerings before 92 1.1 mrg * dmd.statementsem.makeTupleForeach can be used to expand the 93 1.1 mrg * corresponding `static foreach` declaration or statement. 94 1.1 mrg */ 95 1.1 mrg 96 1.1 mrg extern (C++) final class StaticForeach : RootObject 97 1.1 mrg { 98 1.1 mrg extern(D) static immutable tupleFieldName = "tuple"; // used in lowering 99 1.1 mrg 100 1.1 mrg Loc loc; 101 1.1 mrg 102 1.1 mrg /*************** 103 1.1 mrg * Not `null` iff the `static foreach` is over an aggregate. In 104 1.1 mrg * this case, it contains the corresponding ForeachStatement. For 105 1.1 mrg * StaticForeachDeclaration, the body is `null`. 106 1.1 mrg */ 107 1.1 mrg ForeachStatement aggrfe; 108 1.1 mrg /*************** 109 1.1 mrg * Not `null` iff the `static foreach` is over a range. Exactly 110 1.1 mrg * one of the `aggrefe` and `rangefe` fields is not null. See 111 1.1 mrg * `aggrfe` field for more details. 112 1.1 mrg */ 113 1.1 mrg ForeachRangeStatement rangefe; 114 1.1 mrg 115 1.1 mrg /*************** 116 1.1 mrg * true if it is necessary to expand a tuple into multiple 117 1.1 mrg * variables (see lowerNonArrayAggregate). 118 1.1 mrg */ 119 1.1 mrg bool needExpansion = false; 120 1.1 mrg 121 1.1 mrg extern (D) this(const ref Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe) 122 1.1 mrg { 123 1.1 mrg assert(!!aggrfe ^ !!rangefe); 124 1.1 mrg 125 1.1 mrg this.loc = loc; 126 1.1 mrg this.aggrfe = aggrfe; 127 1.1 mrg this.rangefe = rangefe; 128 1.1 mrg } 129 1.1 mrg 130 1.1 mrg StaticForeach syntaxCopy() 131 1.1 mrg { 132 1.1 mrg return new StaticForeach( 133 1.1 mrg loc, 134 1.1 mrg aggrfe ? aggrfe.syntaxCopy() : null, 135 1.1 mrg rangefe ? rangefe.syntaxCopy() : null 136 1.1 mrg ); 137 1.1 mrg } 138 1.1 mrg 139 1.1 mrg /***************************************** 140 1.1 mrg * Turn an aggregate which is an array into an expression tuple 141 1.1 mrg * of its elements. I.e., lower 142 1.1 mrg * static foreach (x; [1, 2, 3, 4]) { ... } 143 1.1 mrg * to 144 1.1 mrg * static foreach (x; AliasSeq!(1, 2, 3, 4)) { ... } 145 1.1 mrg */ 146 1.1 mrg private extern(D) void lowerArrayAggregate(Scope* sc) 147 1.1 mrg { 148 1.1 mrg auto aggr = aggrfe.aggr; 149 1.1 mrg Expression el = new ArrayLengthExp(aggr.loc, aggr); 150 1.1 mrg sc = sc.startCTFE(); 151 1.1 mrg el = el.expressionSemantic(sc); 152 1.1 mrg sc = sc.endCTFE(); 153 1.1 mrg el = el.optimize(WANTvalue); 154 1.1 mrg el = el.ctfeInterpret(); 155 1.1 mrg if (el.op == EXP.int64) 156 1.1 mrg { 157 1.1 mrg Expressions *es = void; 158 1.1 mrg if (auto ale = aggr.isArrayLiteralExp()) 159 1.1 mrg { 160 1.1 mrg // Directly use the elements of the array for the TupleExp creation 161 1.1 mrg es = ale.elements; 162 1.1 mrg } 163 1.1 mrg else 164 1.1 mrg { 165 1.1 mrg const length = cast(size_t)el.toInteger(); 166 1.1 mrg es = new Expressions(length); 167 1.1 mrg foreach (i; 0 .. length) 168 1.1 mrg { 169 1.1 mrg auto index = new IntegerExp(loc, i, Type.tsize_t); 170 1.1 mrg auto value = new IndexExp(aggr.loc, aggr, index); 171 1.1 mrg (*es)[i] = value; 172 1.1 mrg } 173 1.1 mrg } 174 1.1 mrg aggrfe.aggr = new TupleExp(aggr.loc, es); 175 1.1 mrg aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc); 176 1.1 mrg aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue); 177 1.1 mrg aggrfe.aggr = aggrfe.aggr.ctfeInterpret(); 178 1.1 mrg } 179 1.1 mrg else 180 1.1 mrg { 181 1.1 mrg aggrfe.aggr = ErrorExp.get(); 182 1.1 mrg } 183 1.1 mrg } 184 1.1 mrg 185 1.1 mrg /***************************************** 186 1.1 mrg * Wrap a statement into a function literal and call it. 187 1.1 mrg * 188 1.1 mrg * Params: 189 1.1 mrg * loc = The source location. 190 1.1 mrg * s = The statement. 191 1.1 mrg * Returns: 192 1.1 mrg * AST of the expression `(){ s; }()` with location loc. 193 1.1 mrg */ 194 1.1 mrg private extern(D) Expression wrapAndCall(const ref Loc loc, Statement s) 195 1.1 mrg { 196 1.1 mrg auto tf = new TypeFunction(ParameterList(), null, LINK.default_, 0); 197 1.1 mrg auto fd = new FuncLiteralDeclaration(loc, loc, tf, TOK.reserved, null); 198 1.1 mrg fd.fbody = s; 199 1.1 mrg auto fe = new FuncExp(loc, fd); 200 1.1 mrg auto ce = new CallExp(loc, fe, new Expressions()); 201 1.1 mrg return ce; 202 1.1 mrg } 203 1.1 mrg 204 1.1 mrg /***************************************** 205 1.1 mrg * Create a `foreach` statement from `aggrefe/rangefe` with given 206 1.1 mrg * `foreach` variables and body `s`. 207 1.1 mrg * 208 1.1 mrg * Params: 209 1.1 mrg * loc = The source location. 210 1.1 mrg * parameters = The foreach variables. 211 1.1 mrg * s = The `foreach` body. 212 1.1 mrg * Returns: 213 1.1 mrg * `foreach (parameters; aggregate) s;` or 214 1.1 mrg * `foreach (parameters; lower .. upper) s;` 215 1.1 mrg * Where aggregate/lower, upper are as for the current StaticForeach. 216 1.1 mrg */ 217 1.1 mrg private extern(D) Statement createForeach(const ref Loc loc, Parameters* parameters, Statement s) 218 1.1 mrg { 219 1.1 mrg if (aggrfe) 220 1.1 mrg { 221 1.1 mrg return new ForeachStatement(loc, aggrfe.op, parameters, aggrfe.aggr.syntaxCopy(), s, loc); 222 1.1 mrg } 223 1.1 mrg else 224 1.1 mrg { 225 1.1 mrg assert(rangefe && parameters.dim == 1); 226 1.1 mrg return new ForeachRangeStatement(loc, rangefe.op, (*parameters)[0], rangefe.lwr.syntaxCopy(), rangefe.upr.syntaxCopy(), s, loc); 227 1.1 mrg } 228 1.1 mrg } 229 1.1 mrg 230 1.1 mrg /***************************************** 231 1.1 mrg * For a `static foreach` with multiple loop variables, the 232 1.1 mrg * aggregate is lowered to an array of tuples. As D does not have 233 1.1 mrg * built-in tuples, we need a suitable tuple type. This generates 234 1.1 mrg * a `struct` that serves as the tuple type. This type is only 235 1.1 mrg * used during CTFE and hence its typeinfo will not go to the 236 1.1 mrg * object file. 237 1.1 mrg * 238 1.1 mrg * Params: 239 1.1 mrg * loc = The source location. 240 1.1 mrg * e = The expressions we wish to store in the tuple. 241 1.1 mrg * sc = The current scope. 242 1.1 mrg * Returns: 243 1.1 mrg * A struct type of the form 244 1.1 mrg * struct Tuple 245 1.1 mrg * { 246 1.1 mrg * typeof(AliasSeq!(e)) tuple; 247 1.1 mrg * } 248 1.1 mrg */ 249 1.1 mrg 250 1.1 mrg private extern(D) TypeStruct createTupleType(const ref Loc loc, Expressions* e, Scope* sc) 251 1.1 mrg { // TODO: move to druntime? 252 1.1 mrg auto sid = Identifier.generateId("Tuple"); 253 1.1 mrg auto sdecl = new StructDeclaration(loc, sid, false); 254 1.1 mrg sdecl.storage_class |= STC.static_; 255 1.1 mrg sdecl.members = new Dsymbols(); 256 1.1 mrg auto fid = Identifier.idPool(tupleFieldName.ptr, tupleFieldName.length); 257 1.1 mrg auto ty = new TypeTypeof(loc, new TupleExp(loc, e)); 258 1.1 mrg sdecl.members.push(new VarDeclaration(loc, ty, fid, null, 0)); 259 1.1 mrg auto r = cast(TypeStruct)sdecl.type; 260 1.1 mrg if (global.params.useTypeInfo && Type.dtypeinfo) 261 1.1 mrg r.vtinfo = TypeInfoStructDeclaration.create(r); // prevent typeinfo from going to object file 262 1.1 mrg return r; 263 1.1 mrg } 264 1.1 mrg 265 1.1 mrg /***************************************** 266 1.1 mrg * Create the AST for an instantiation of a suitable tuple type. 267 1.1 mrg * 268 1.1 mrg * Params: 269 1.1 mrg * loc = The source location. 270 1.1 mrg * type = A Tuple type, created with createTupleType. 271 1.1 mrg * e = The expressions we wish to store in the tuple. 272 1.1 mrg * Returns: 273 1.1 mrg * An AST for the expression `Tuple(e)`. 274 1.1 mrg */ 275 1.1 mrg 276 1.1 mrg private extern(D) Expression createTuple(const ref Loc loc, TypeStruct type, Expressions* e) 277 1.1 mrg { // TODO: move to druntime? 278 1.1 mrg return new CallExp(loc, new TypeExp(loc, type), e); 279 1.1 mrg } 280 1.1 mrg 281 1.1 mrg 282 1.1 mrg /***************************************** 283 1.1 mrg * Lower any aggregate that is not an array to an array using a 284 1.1 mrg * regular foreach loop within CTFE. If there are multiple 285 1.1 mrg * `static foreach` loop variables, an array of tuples is 286 1.1 mrg * generated. In thise case, the field `needExpansion` is set to 287 1.1 mrg * true to indicate that the static foreach loop expansion will 288 1.1 mrg * need to expand the tuples into multiple variables. 289 1.1 mrg * 290 1.1 mrg * For example, `static foreach (x; range) { ... }` is lowered to: 291 1.1 mrg * 292 1.1 mrg * static foreach (x; { 293 1.1 mrg * typeof({ 294 1.1 mrg * foreach (x; range) return x; 295 1.1 mrg * }())[] __res; 296 1.1 mrg * foreach (x; range) __res ~= x; 297 1.1 mrg * return __res; 298 1.1 mrg * }()) { ... } 299 1.1 mrg * 300 1.1 mrg * Finally, call `lowerArrayAggregate` to turn the produced 301 1.1 mrg * array into an expression tuple. 302 1.1 mrg * 303 1.1 mrg * Params: 304 1.1 mrg * sc = The current scope. 305 1.1 mrg */ 306 1.1 mrg 307 1.1 mrg private void lowerNonArrayAggregate(Scope* sc) 308 1.1 mrg { 309 1.1 mrg auto nvars = aggrfe ? aggrfe.parameters.dim : 1; 310 1.1 mrg auto aloc = aggrfe ? aggrfe.aggr.loc : rangefe.lwr.loc; 311 1.1 mrg // We need three sets of foreach loop variables because the 312 1.1 mrg // lowering contains three foreach loops. 313 1.1 mrg Parameters*[3] pparams = [new Parameters(), new Parameters(), new Parameters()]; 314 1.1 mrg foreach (i; 0 .. nvars) 315 1.1 mrg { 316 1.1 mrg foreach (params; pparams) 317 1.1 mrg { 318 1.1 mrg auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm; 319 1.1 mrg params.push(new Parameter(p.storageClass, p.type, p.ident, null, null)); 320 1.1 mrg } 321 1.1 mrg } 322 1.1 mrg Expression[2] res; 323 1.1 mrg TypeStruct tplty = null; 324 1.1 mrg if (nvars == 1) // only one `static foreach` variable, generate identifiers. 325 1.1 mrg { 326 1.1 mrg foreach (i; 0 .. 2) 327 1.1 mrg { 328 1.1 mrg res[i] = new IdentifierExp(aloc, (*pparams[i])[0].ident); 329 1.1 mrg } 330 1.1 mrg } 331 1.1 mrg else // multiple `static foreach` variables, generate tuples. 332 1.1 mrg { 333 1.1 mrg foreach (i; 0 .. 2) 334 1.1 mrg { 335 1.1 mrg auto e = new Expressions(pparams[0].dim); 336 1.1 mrg foreach (j, ref elem; *e) 337 1.1 mrg { 338 1.1 mrg auto p = (*pparams[i])[j]; 339 1.1 mrg elem = new IdentifierExp(aloc, p.ident); 340 1.1 mrg } 341 1.1 mrg if (!tplty) 342 1.1 mrg { 343 1.1 mrg tplty = createTupleType(aloc, e, sc); 344 1.1 mrg } 345 1.1 mrg res[i] = createTuple(aloc, tplty, e); 346 1.1 mrg } 347 1.1 mrg needExpansion = true; // need to expand the tuples later 348 1.1 mrg } 349 1.1 mrg // generate remaining code for the new aggregate which is an 350 1.1 mrg // array (see documentation comment). 351 1.1 mrg if (rangefe) 352 1.1 mrg { 353 1.1 mrg sc = sc.startCTFE(); 354 1.1 mrg rangefe.lwr = rangefe.lwr.expressionSemantic(sc); 355 1.1 mrg rangefe.lwr = resolveProperties(sc, rangefe.lwr); 356 1.1 mrg rangefe.upr = rangefe.upr.expressionSemantic(sc); 357 1.1 mrg rangefe.upr = resolveProperties(sc, rangefe.upr); 358 1.1 mrg sc = sc.endCTFE(); 359 1.1 mrg rangefe.lwr = rangefe.lwr.optimize(WANTvalue); 360 1.1 mrg rangefe.lwr = rangefe.lwr.ctfeInterpret(); 361 1.1 mrg rangefe.upr = rangefe.upr.optimize(WANTvalue); 362 1.1 mrg rangefe.upr = rangefe.upr.ctfeInterpret(); 363 1.1 mrg } 364 1.1 mrg auto s1 = new Statements(); 365 1.1 mrg auto sfe = new Statements(); 366 1.1 mrg if (tplty) sfe.push(new ExpStatement(loc, tplty.sym)); 367 1.1 mrg sfe.push(new ReturnStatement(aloc, res[0])); 368 1.1 mrg s1.push(createForeach(aloc, pparams[0], new CompoundStatement(aloc, sfe))); 369 1.1 mrg s1.push(new ExpStatement(aloc, new AssertExp(aloc, IntegerExp.literal!0))); 370 1.1 mrg Type ety = new TypeTypeof(aloc, wrapAndCall(aloc, new CompoundStatement(aloc, s1))); 371 1.1 mrg auto aty = ety.arrayOf(); 372 1.1 mrg auto idres = Identifier.generateId("__res"); 373 1.1 mrg auto vard = new VarDeclaration(aloc, aty, idres, null); 374 1.1 mrg auto s2 = new Statements(); 375 1.1 mrg 376 1.1 mrg // Run 'typeof' gagged to avoid duplicate errors and if it fails just create 377 1.1 mrg // an empty foreach to expose them. 378 1.1 mrg uint olderrors = global.startGagging(); 379 1.1 mrg ety = ety.typeSemantic(aloc, sc); 380 1.1 mrg if (global.endGagging(olderrors)) 381 1.1 mrg s2.push(createForeach(aloc, pparams[1], null)); 382 1.1 mrg else 383 1.1 mrg { 384 1.1 mrg s2.push(new ExpStatement(aloc, vard)); 385 1.1 mrg auto catass = new CatAssignExp(aloc, new IdentifierExp(aloc, idres), res[1]); 386 1.1 mrg s2.push(createForeach(aloc, pparams[1], new ExpStatement(aloc, catass))); 387 1.1 mrg s2.push(new ReturnStatement(aloc, new IdentifierExp(aloc, idres))); 388 1.1 mrg } 389 1.1 mrg 390 1.1 mrg Expression aggr = void; 391 1.1 mrg Type indexty = void; 392 1.1 mrg 393 1.1 mrg if (rangefe && (indexty = ety).isintegral()) 394 1.1 mrg { 395 1.1 mrg rangefe.lwr.type = indexty; 396 1.1 mrg rangefe.upr.type = indexty; 397 1.1 mrg auto lwrRange = getIntRange(rangefe.lwr); 398 1.1 mrg auto uprRange = getIntRange(rangefe.upr); 399 1.1 mrg 400 1.1 mrg const lwr = rangefe.lwr.toInteger(); 401 1.1 mrg auto upr = rangefe.upr.toInteger(); 402 1.1 mrg size_t length = 0; 403 1.1 mrg 404 1.1 mrg if (lwrRange.imin <= uprRange.imax) 405 1.1 mrg length = cast(size_t) (upr - lwr); 406 1.1 mrg 407 1.1 mrg auto exps = new Expressions(length); 408 1.1 mrg 409 1.1 mrg if (rangefe.op == TOK.foreach_) 410 1.1 mrg { 411 1.1 mrg foreach (i; 0 .. length) 412 1.1 mrg (*exps)[i] = new IntegerExp(aloc, lwr + i, indexty); 413 1.1 mrg } 414 1.1 mrg else 415 1.1 mrg { 416 1.1 mrg --upr; 417 1.1 mrg foreach (i; 0 .. length) 418 1.1 mrg (*exps)[i] = new IntegerExp(aloc, upr - i, indexty); 419 1.1 mrg } 420 1.1 mrg aggr = new ArrayLiteralExp(aloc, indexty.arrayOf(), exps); 421 1.1 mrg } 422 1.1 mrg else 423 1.1 mrg { 424 1.1 mrg aggr = wrapAndCall(aloc, new CompoundStatement(aloc, s2)); 425 1.1 mrg sc = sc.startCTFE(); 426 1.1 mrg aggr = aggr.expressionSemantic(sc); 427 1.1 mrg aggr = resolveProperties(sc, aggr); 428 1.1 mrg sc = sc.endCTFE(); 429 1.1 mrg aggr = aggr.optimize(WANTvalue); 430 1.1 mrg aggr = aggr.ctfeInterpret(); 431 1.1 mrg } 432 1.1 mrg 433 1.1 mrg assert(!!aggrfe ^ !!rangefe); 434 1.1 mrg aggrfe = new ForeachStatement(loc, TOK.foreach_, pparams[2], aggr, 435 1.1 mrg aggrfe ? aggrfe._body : rangefe._body, 436 1.1 mrg aggrfe ? aggrfe.endloc : rangefe.endloc); 437 1.1 mrg rangefe = null; 438 1.1 mrg lowerArrayAggregate(sc); // finally, turn generated array into expression tuple 439 1.1 mrg } 440 1.1 mrg 441 1.1 mrg /***************************************** 442 1.1 mrg * Perform `static foreach` lowerings that are necessary in order 443 1.1 mrg * to finally expand the `static foreach` using 444 1.1 mrg * `dmd.statementsem.makeTupleForeach`. 445 1.1 mrg */ 446 1.1 mrg extern(D) void prepare(Scope* sc) 447 1.1 mrg { 448 1.1 mrg assert(sc); 449 1.1 mrg 450 1.1 mrg if (aggrfe) 451 1.1 mrg { 452 1.1 mrg sc = sc.startCTFE(); 453 1.1 mrg aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc); 454 1.1 mrg sc = sc.endCTFE(); 455 1.1 mrg } 456 1.1 mrg 457 1.1 mrg if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror) 458 1.1 mrg { 459 1.1 mrg return; 460 1.1 mrg } 461 1.1 mrg 462 1.1 mrg if (!ready()) 463 1.1 mrg { 464 1.1 mrg if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray) 465 1.1 mrg { 466 1.1 mrg lowerArrayAggregate(sc); 467 1.1 mrg } 468 1.1 mrg else 469 1.1 mrg { 470 1.1 mrg lowerNonArrayAggregate(sc); 471 1.1 mrg } 472 1.1 mrg } 473 1.1 mrg } 474 1.1 mrg 475 1.1 mrg /***************************************** 476 1.1 mrg * Returns: 477 1.1 mrg * `true` iff ready to call `dmd.statementsem.makeTupleForeach`. 478 1.1 mrg */ 479 1.1 mrg extern(D) bool ready() 480 1.1 mrg { 481 1.1 mrg return aggrfe && aggrfe.aggr && aggrfe.aggr.type && aggrfe.aggr.type.toBasetype().ty == Ttuple; 482 1.1 mrg } 483 1.1 mrg } 484 1.1 mrg 485 1.1 mrg /*********************************************************** 486 1.1 mrg */ 487 1.1 mrg extern (C++) class DVCondition : Condition 488 1.1 mrg { 489 1.1 mrg uint level; 490 1.1 mrg Identifier ident; 491 1.1 mrg Module mod; 492 1.1 mrg 493 1.1 mrg extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) 494 1.1 mrg { 495 1.1 mrg super(loc); 496 1.1 mrg this.mod = mod; 497 1.1 mrg this.level = level; 498 1.1 mrg this.ident = ident; 499 1.1 mrg } 500 1.1 mrg 501 1.1 mrg override final DVCondition syntaxCopy() 502 1.1 mrg { 503 1.1 mrg return this; // don't need to copy 504 1.1 mrg } 505 1.1 mrg 506 1.1 mrg override void accept(Visitor v) 507 1.1 mrg { 508 1.1 mrg v.visit(this); 509 1.1 mrg } 510 1.1 mrg } 511 1.1 mrg 512 1.1 mrg /*********************************************************** 513 1.1 mrg */ 514 1.1 mrg extern (C++) final class DebugCondition : DVCondition 515 1.1 mrg { 516 1.1 mrg /** 517 1.1 mrg * Add an user-supplied identifier to the list of global debug identifiers 518 1.1 mrg * 519 1.1 mrg * Can be called from either the driver or a `debug = Ident;` statement. 520 1.1 mrg * Unlike version identifier, there isn't any reserved debug identifier 521 1.1 mrg * so no validation takes place. 522 1.1 mrg * 523 1.1 mrg * Params: 524 1.1 mrg * ident = identifier to add 525 1.1 mrg */ 526 1.1 mrg deprecated("Kept for C++ compat - Use the string overload instead") 527 1.1 mrg static void addGlobalIdent(const(char)* ident) 528 1.1 mrg { 529 1.1 mrg addGlobalIdent(ident[0 .. ident.strlen]); 530 1.1 mrg } 531 1.1 mrg 532 1.1 mrg /// Ditto 533 1.1 mrg extern(D) static void addGlobalIdent(string ident) 534 1.1 mrg { 535 1.1 mrg // Overload necessary for string literals 536 1.1 mrg addGlobalIdent(cast(const(char)[])ident); 537 1.1 mrg } 538 1.1 mrg 539 1.1 mrg 540 1.1 mrg /// Ditto 541 1.1 mrg extern(D) static void addGlobalIdent(const(char)[] ident) 542 1.1 mrg { 543 1.1 mrg if (!global.debugids) 544 1.1 mrg global.debugids = new Identifiers(); 545 1.1 mrg global.debugids.push(Identifier.idPool(ident)); 546 1.1 mrg } 547 1.1 mrg 548 1.1 mrg 549 1.1 mrg /** 550 1.1 mrg * Instantiate a new `DebugCondition` 551 1.1 mrg * 552 1.1 mrg * Params: 553 1.1 mrg * mod = Module this node belongs to 554 1.1 mrg * level = Minimum global level this condition needs to pass. 555 1.1 mrg * Only used if `ident` is `null`. 556 1.1 mrg * ident = Identifier required for this condition to pass. 557 1.1 mrg * If `null`, this conditiion will use an integer level. 558 1.1 mrg * loc = Location in the source file 559 1.1 mrg */ 560 1.1 mrg extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) 561 1.1 mrg { 562 1.1 mrg super(loc, mod, level, ident); 563 1.1 mrg } 564 1.1 mrg 565 1.1 mrg override int include(Scope* sc) 566 1.1 mrg { 567 1.1 mrg //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); 568 1.1 mrg if (inc == Include.notComputed) 569 1.1 mrg { 570 1.1 mrg inc = Include.no; 571 1.1 mrg bool definedInModule = false; 572 1.1 mrg if (ident) 573 1.1 mrg { 574 1.1 mrg if (findCondition(mod.debugids, ident)) 575 1.1 mrg { 576 1.1 mrg inc = Include.yes; 577 1.1 mrg definedInModule = true; 578 1.1 mrg } 579 1.1 mrg else if (findCondition(global.debugids, ident)) 580 1.1 mrg inc = Include.yes; 581 1.1 mrg else 582 1.1 mrg { 583 1.1 mrg if (!mod.debugidsNot) 584 1.1 mrg mod.debugidsNot = new Identifiers(); 585 1.1 mrg mod.debugidsNot.push(ident); 586 1.1 mrg } 587 1.1 mrg } 588 1.1 mrg else if (level <= global.params.debuglevel || level <= mod.debuglevel) 589 1.1 mrg inc = Include.yes; 590 1.1 mrg if (!definedInModule) 591 1.1 mrg printDepsConditional(sc, this, "depsDebug "); 592 1.1 mrg } 593 1.1 mrg return (inc == Include.yes); 594 1.1 mrg } 595 1.1 mrg 596 1.1 mrg override inout(DebugCondition) isDebugCondition() inout 597 1.1 mrg { 598 1.1 mrg return this; 599 1.1 mrg } 600 1.1 mrg 601 1.1 mrg override void accept(Visitor v) 602 1.1 mrg { 603 1.1 mrg v.visit(this); 604 1.1 mrg } 605 1.1 mrg 606 1.1 mrg override const(char)* toChars() const 607 1.1 mrg { 608 1.1 mrg return ident ? ident.toChars() : "debug".ptr; 609 1.1 mrg } 610 1.1 mrg } 611 1.1 mrg 612 1.1 mrg /** 613 1.1 mrg * Node to represent a version condition 614 1.1 mrg * 615 1.1 mrg * A version condition is of the form: 616 1.1 mrg * --- 617 1.1 mrg * version (Identifier) 618 1.1 mrg * --- 619 1.1 mrg * In user code. 620 1.1 mrg * This class also provides means to add version identifier 621 1.1 mrg * to the list of global (cross module) identifiers. 622 1.1 mrg */ 623 1.1 mrg extern (C++) final class VersionCondition : DVCondition 624 1.1 mrg { 625 1.1 mrg /** 626 1.1 mrg * Check if a given version identifier is reserved. 627 1.1 mrg * 628 1.1 mrg * Params: 629 1.1 mrg * ident = identifier being checked 630 1.1 mrg * 631 1.1 mrg * Returns: 632 1.1 mrg * `true` if it is reserved, `false` otherwise 633 1.1 mrg */ 634 1.1 mrg extern(D) private static bool isReserved(const(char)[] ident) 635 1.1 mrg { 636 1.1 mrg // This list doesn't include "D_*" versions, see the last return 637 1.1 mrg switch (ident) 638 1.1 mrg { 639 1.1 mrg case "AArch64": 640 1.1 mrg case "AIX": 641 1.1 mrg case "all": 642 1.1 mrg case "Alpha": 643 1.1 mrg case "Alpha_HardFloat": 644 1.1 mrg case "Alpha_SoftFloat": 645 1.1 mrg case "Android": 646 1.1 mrg case "ARM": 647 1.1 mrg case "ARM_HardFloat": 648 1.1 mrg case "ARM_SoftFloat": 649 1.1 mrg case "ARM_SoftFP": 650 1.1 mrg case "ARM_Thumb": 651 1.1 mrg case "AsmJS": 652 1.1 mrg case "assert": 653 1.1 mrg case "AVR": 654 1.1 mrg case "BigEndian": 655 1.1 mrg case "BSD": 656 1.1 mrg case "CppRuntime_Clang": 657 1.1 mrg case "CppRuntime_DigitalMars": 658 1.1 mrg case "CppRuntime_Gcc": 659 1.1 mrg case "CppRuntime_Microsoft": 660 1.1 mrg case "CppRuntime_Sun": 661 1.1 mrg case "CRuntime_Bionic": 662 1.1 mrg case "CRuntime_DigitalMars": 663 1.1 mrg case "CRuntime_Glibc": 664 1.1 mrg case "CRuntime_Microsoft": 665 1.1 mrg case "CRuntime_Musl": 666 1.1 mrg case "CRuntime_Newlib": 667 1.1 mrg case "CRuntime_UClibc": 668 1.1 mrg case "CRuntime_WASI": 669 1.1 mrg case "Cygwin": 670 1.1 mrg case "DigitalMars": 671 1.1 mrg case "DragonFlyBSD": 672 1.1 mrg case "Emscripten": 673 1.1 mrg case "ELFv1": 674 1.1 mrg case "ELFv2": 675 1.1 mrg case "Epiphany": 676 1.1 mrg case "FreeBSD": 677 1.1 mrg case "FreeStanding": 678 1.1 mrg case "GNU": 679 1.1 mrg case "Haiku": 680 1.1 mrg case "HPPA": 681 1.1 mrg case "HPPA64": 682 1.1 mrg case "Hurd": 683 1.1 mrg case "IA64": 684 1.1 mrg case "iOS": 685 1.1 mrg case "LDC": 686 1.1 mrg case "linux": 687 1.1 mrg case "LittleEndian": 688 1.1 mrg case "MinGW": 689 1.1 mrg case "MIPS32": 690 1.1 mrg case "MIPS64": 691 1.1 mrg case "MIPS_EABI": 692 1.1 mrg case "MIPS_HardFloat": 693 1.1 mrg case "MIPS_N32": 694 1.1 mrg case "MIPS_N64": 695 1.1 mrg case "MIPS_O32": 696 1.1 mrg case "MIPS_O64": 697 1.1 mrg case "MIPS_SoftFloat": 698 1.1 mrg case "MSP430": 699 1.1 mrg case "NetBSD": 700 1.1 mrg case "none": 701 1.1 mrg case "NVPTX": 702 1.1 mrg case "NVPTX64": 703 1.1 mrg case "OpenBSD": 704 1.1 mrg case "OSX": 705 1.1 mrg case "PlayStation": 706 1.1 mrg case "PlayStation4": 707 1.1 mrg case "Posix": 708 1.1 mrg case "PPC": 709 1.1 mrg case "PPC64": 710 1.1 mrg case "PPC_HardFloat": 711 1.1 mrg case "PPC_SoftFloat": 712 1.1 mrg case "RISCV32": 713 1.1 mrg case "RISCV64": 714 1.1 mrg case "S390": 715 1.1 mrg case "S390X": 716 1.1 mrg case "SDC": 717 1.1 mrg case "SH": 718 1.1 mrg case "SkyOS": 719 1.1 mrg case "Solaris": 720 1.1 mrg case "SPARC": 721 1.1 mrg case "SPARC64": 722 1.1 mrg case "SPARC_HardFloat": 723 1.1 mrg case "SPARC_SoftFloat": 724 1.1 mrg case "SPARC_V8Plus": 725 1.1 mrg case "SystemZ": 726 1.1 mrg case "SysV3": 727 1.1 mrg case "SysV4": 728 1.1 mrg case "TVOS": 729 1.1 mrg case "unittest": 730 1.1 mrg case "WASI": 731 1.1 mrg case "WatchOS": 732 1.1 mrg case "WebAssembly": 733 1.1 mrg case "Win32": 734 1.1 mrg case "Win64": 735 1.1 mrg case "Windows": 736 1.1 mrg case "X86": 737 1.1 mrg case "X86_64": 738 1.1 mrg return true; 739 1.1 mrg 740 1.1 mrg default: 741 1.1 mrg // Anything that starts with "D_" is reserved 742 1.1 mrg return (ident.length >= 2 && ident[0 .. 2] == "D_"); 743 1.1 mrg } 744 1.1 mrg } 745 1.1 mrg 746 1.1 mrg /** 747 1.1 mrg * Raises an error if a version identifier is reserved. 748 1.1 mrg * 749 1.1 mrg * Called when setting a version identifier, e.g. `-version=identifier` 750 1.1 mrg * parameter to the compiler or `version = Foo` in user code. 751 1.1 mrg * 752 1.1 mrg * Params: 753 1.1 mrg * loc = Where the identifier is set 754 1.1 mrg * ident = identifier being checked (ident[$] must be '\0') 755 1.1 mrg */ 756 1.1 mrg extern(D) static void checkReserved(const ref Loc loc, const(char)[] ident) 757 1.1 mrg { 758 1.1 mrg if (isReserved(ident)) 759 1.1 mrg error(loc, "version identifier `%s` is reserved and cannot be set", 760 1.1 mrg ident.ptr); 761 1.1 mrg } 762 1.1 mrg 763 1.1 mrg /** 764 1.1 mrg * Add an user-supplied global identifier to the list 765 1.1 mrg * 766 1.1 mrg * Only called from the driver for `-version=Ident` parameters. 767 1.1 mrg * Will raise an error if the identifier is reserved. 768 1.1 mrg * 769 1.1 mrg * Params: 770 1.1 mrg * ident = identifier to add 771 1.1 mrg */ 772 1.1 mrg deprecated("Kept for C++ compat - Use the string overload instead") 773 1.1 mrg static void addGlobalIdent(const(char)* ident) 774 1.1 mrg { 775 1.1 mrg addGlobalIdent(ident[0 .. ident.strlen]); 776 1.1 mrg } 777 1.1 mrg 778 1.1 mrg /// Ditto 779 1.1 mrg extern(D) static void addGlobalIdent(string ident) 780 1.1 mrg { 781 1.1 mrg // Overload necessary for string literals 782 1.1 mrg addGlobalIdent(cast(const(char)[])ident); 783 1.1 mrg } 784 1.1 mrg 785 1.1 mrg 786 1.1 mrg /// Ditto 787 1.1 mrg extern(D) static void addGlobalIdent(const(char)[] ident) 788 1.1 mrg { 789 1.1 mrg checkReserved(Loc.initial, ident); 790 1.1 mrg addPredefinedGlobalIdent(ident); 791 1.1 mrg } 792 1.1 mrg 793 1.1 mrg /** 794 1.1 mrg * Add any global identifier to the list, without checking 795 1.1 mrg * if it's predefined 796 1.1 mrg * 797 1.1 mrg * Only called from the driver after platform detection, 798 1.1 mrg * and internally. 799 1.1 mrg * 800 1.1 mrg * Params: 801 1.1 mrg * ident = identifier to add (ident[$] must be '\0') 802 1.1 mrg */ 803 1.1 mrg deprecated("Kept for C++ compat - Use the string overload instead") 804 1.1 mrg static void addPredefinedGlobalIdent(const(char)* ident) 805 1.1 mrg { 806 1.1 mrg addPredefinedGlobalIdent(ident.toDString()); 807 1.1 mrg } 808 1.1 mrg 809 1.1 mrg /// Ditto 810 1.1 mrg extern(D) static void addPredefinedGlobalIdent(string ident) 811 1.1 mrg { 812 1.1 mrg // Forward: Overload necessary for string literal 813 1.1 mrg addPredefinedGlobalIdent(cast(const(char)[])ident); 814 1.1 mrg } 815 1.1 mrg 816 1.1 mrg 817 1.1 mrg /// Ditto 818 1.1 mrg extern(D) static void addPredefinedGlobalIdent(const(char)[] ident) 819 1.1 mrg { 820 1.1 mrg if (!global.versionids) 821 1.1 mrg global.versionids = new Identifiers(); 822 1.1 mrg global.versionids.push(Identifier.idPool(ident)); 823 1.1 mrg } 824 1.1 mrg 825 1.1 mrg /** 826 1.1 mrg * Instantiate a new `VersionCondition` 827 1.1 mrg * 828 1.1 mrg * Params: 829 1.1 mrg * mod = Module this node belongs to 830 1.1 mrg * level = Minimum global level this condition needs to pass. 831 1.1 mrg * Only used if `ident` is `null`. 832 1.1 mrg * ident = Identifier required for this condition to pass. 833 1.1 mrg * If `null`, this conditiion will use an integer level. 834 1.1 mrg * loc = Location in the source file 835 1.1 mrg */ 836 1.1 mrg extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) 837 1.1 mrg { 838 1.1 mrg super(loc, mod, level, ident); 839 1.1 mrg } 840 1.1 mrg 841 1.1 mrg override int include(Scope* sc) 842 1.1 mrg { 843 1.1 mrg //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); 844 1.1 mrg //if (ident) printf("\tident = '%s'\n", ident.toChars()); 845 1.1 mrg if (inc == Include.notComputed) 846 1.1 mrg { 847 1.1 mrg inc = Include.no; 848 1.1 mrg bool definedInModule = false; 849 1.1 mrg if (ident) 850 1.1 mrg { 851 1.1 mrg if (findCondition(mod.versionids, ident)) 852 1.1 mrg { 853 1.1 mrg inc = Include.yes; 854 1.1 mrg definedInModule = true; 855 1.1 mrg } 856 1.1 mrg else if (findCondition(global.versionids, ident)) 857 1.1 mrg inc = Include.yes; 858 1.1 mrg else 859 1.1 mrg { 860 1.1 mrg if (!mod.versionidsNot) 861 1.1 mrg mod.versionidsNot = new Identifiers(); 862 1.1 mrg mod.versionidsNot.push(ident); 863 1.1 mrg } 864 1.1 mrg } 865 1.1 mrg else if (level <= global.params.versionlevel || level <= mod.versionlevel) 866 1.1 mrg inc = Include.yes; 867 1.1 mrg if (!definedInModule && 868 1.1 mrg (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert))) 869 1.1 mrg { 870 1.1 mrg printDepsConditional(sc, this, "depsVersion "); 871 1.1 mrg } 872 1.1 mrg } 873 1.1 mrg return (inc == Include.yes); 874 1.1 mrg } 875 1.1 mrg 876 1.1 mrg override inout(VersionCondition) isVersionCondition() inout 877 1.1 mrg { 878 1.1 mrg return this; 879 1.1 mrg } 880 1.1 mrg 881 1.1 mrg override void accept(Visitor v) 882 1.1 mrg { 883 1.1 mrg v.visit(this); 884 1.1 mrg } 885 1.1 mrg 886 1.1 mrg override const(char)* toChars() const 887 1.1 mrg { 888 1.1 mrg return ident ? ident.toChars() : "version".ptr; 889 1.1 mrg } 890 1.1 mrg } 891 1.1 mrg 892 1.1 mrg /*********************************************************** 893 1.1 mrg */ 894 1.1 mrg extern (C++) final class StaticIfCondition : Condition 895 1.1 mrg { 896 1.1 mrg Expression exp; 897 1.1 mrg 898 1.1 mrg extern (D) this(const ref Loc loc, Expression exp) 899 1.1 mrg { 900 1.1 mrg super(loc); 901 1.1 mrg this.exp = exp; 902 1.1 mrg } 903 1.1 mrg 904 1.1 mrg override StaticIfCondition syntaxCopy() 905 1.1 mrg { 906 1.1 mrg return new StaticIfCondition(loc, exp.syntaxCopy()); 907 1.1 mrg } 908 1.1 mrg 909 1.1 mrg override int include(Scope* sc) 910 1.1 mrg { 911 1.1 mrg // printf("StaticIfCondition::include(sc = %p) this=%p inc = %d\n", sc, this, inc); 912 1.1 mrg 913 1.1 mrg int errorReturn() 914 1.1 mrg { 915 1.1 mrg if (!global.gag) 916 1.1 mrg inc = Include.no; // so we don't see the error message again 917 1.1 mrg return 0; 918 1.1 mrg } 919 1.1 mrg 920 1.1 mrg if (inc == Include.notComputed) 921 1.1 mrg { 922 1.1 mrg if (!sc) 923 1.1 mrg { 924 1.1 mrg error(loc, "`static if` conditional cannot be at global scope"); 925 1.1 mrg inc = Include.no; 926 1.1 mrg return 0; 927 1.1 mrg } 928 1.1 mrg 929 1.1 mrg import dmd.staticcond; 930 1.1 mrg bool errors; 931 1.1 mrg 932 1.1 mrg if (!exp) 933 1.1 mrg return errorReturn(); 934 1.1 mrg 935 1.1 mrg bool result = evalStaticCondition(sc, exp, exp, errors); 936 1.1 mrg 937 1.1 mrg // Prevent repeated condition evaluation. 938 1.1 mrg // See: fail_compilation/fail7815.d 939 1.1 mrg if (inc != Include.notComputed) 940 1.1 mrg return (inc == Include.yes); 941 1.1 mrg if (errors) 942 1.1 mrg return errorReturn(); 943 1.1 mrg if (result) 944 1.1 mrg inc = Include.yes; 945 1.1 mrg else 946 1.1 mrg inc = Include.no; 947 1.1 mrg } 948 1.1 mrg return (inc == Include.yes); 949 1.1 mrg } 950 1.1 mrg 951 1.1 mrg override void accept(Visitor v) 952 1.1 mrg { 953 1.1 mrg v.visit(this); 954 1.1 mrg } 955 1.1 mrg 956 1.1 mrg override const(char)* toChars() const 957 1.1 mrg { 958 1.1 mrg return exp ? exp.toChars() : "static if".ptr; 959 1.1 mrg } 960 1.1 mrg } 961 1.1 mrg 962 1.1 mrg 963 1.1 mrg /**************************************** 964 1.1 mrg * Find `ident` in an array of identifiers. 965 1.1 mrg * Params: 966 1.1 mrg * ids = array of identifiers 967 1.1 mrg * ident = identifier to search for 968 1.1 mrg * Returns: 969 1.1 mrg * true if found 970 1.1 mrg */ 971 1.1 mrg bool findCondition(Identifiers* ids, Identifier ident) @safe nothrow pure 972 1.1 mrg { 973 1.1 mrg if (ids) 974 1.1 mrg { 975 1.1 mrg foreach (id; *ids) 976 1.1 mrg { 977 1.1 mrg if (id == ident) 978 1.1 mrg return true; 979 1.1 mrg } 980 1.1 mrg } 981 1.1 mrg return false; 982 1.1 mrg } 983 1.1 mrg 984 1.1 mrg // Helper for printing dependency information 985 1.1 mrg private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[] depType) 986 1.1 mrg { 987 1.1 mrg if (!global.params.moduleDeps || global.params.moduleDepsFile) 988 1.1 mrg return; 989 1.1 mrg OutBuffer* ob = global.params.moduleDeps; 990 1.1 mrg Module imod = sc ? sc._module : condition.mod; 991 1.1 mrg if (!imod) 992 1.1 mrg return; 993 1.1 mrg ob.writestring(depType); 994 1.1 mrg ob.writestring(imod.toPrettyChars()); 995 1.1 mrg ob.writestring(" ("); 996 1.1 mrg escapePath(ob, imod.srcfile.toChars()); 997 1.1 mrg ob.writestring(") : "); 998 1.1 mrg if (condition.ident) 999 1.1 mrg ob.writestring(condition.ident.toString()); 1000 1.1 mrg else 1001 1.1 mrg ob.print(condition.level); 1002 1.1 mrg ob.writeByte('\n'); 1003 1.1 mrg } 1004