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