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 "declaration.h" 17 #include "identifier.h" 18 #include "expression.h" 19 #include "cond.h" 20 #include "module.h" 21 #include "template.h" 22 #include "mtype.h" 23 #include "scope.h" 24 #include "arraytypes.h" 25 #include "tokens.h" 26 27 Expression *semantic(Expression *e, Scope *sc); 28 bool evalStaticCondition(Scope *sc, Expression *exp, Expression *e, bool &errors); 29 30 int findCondition(Strings *ids, Identifier *ident) 31 { 32 if (ids) 33 { 34 for (size_t i = 0; i < ids->dim; i++) 35 { 36 const char *id = (*ids)[i]; 37 38 if (strcmp(id, ident->toChars()) == 0) 39 return true; 40 } 41 } 42 43 return false; 44 } 45 46 /* ============================================================ */ 47 48 Condition::Condition(Loc loc) 49 { 50 this->loc = loc; 51 inc = 0; 52 } 53 54 /* ============================================================ */ 55 56 DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) 57 : Condition(Loc()) 58 { 59 this->mod = mod; 60 this->level = level; 61 this->ident = ident; 62 } 63 64 Condition *DVCondition::syntaxCopy() 65 { 66 return this; // don't need to copy 67 } 68 69 /* ============================================================ */ 70 71 void DebugCondition::setGlobalLevel(unsigned level) 72 { 73 global.params.debuglevel = level; 74 } 75 76 void DebugCondition::addGlobalIdent(const char *ident) 77 { 78 if (!global.params.debugids) 79 global.params.debugids = new Strings(); 80 global.params.debugids->push(ident); 81 } 82 83 84 DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) 85 : DVCondition(mod, level, ident) 86 { 87 } 88 89 // Helper for printing dependency information 90 void printDepsConditional(Scope *sc, DVCondition* condition, const char* depType) 91 { 92 if (!global.params.moduleDeps || global.params.moduleDepsFile) 93 return; 94 OutBuffer *ob = global.params.moduleDeps; 95 Module* imod = sc ? sc->instantiatingModule() : condition->mod; 96 if (!imod) 97 return; 98 ob->writestring(depType); 99 ob->writestring(imod->toPrettyChars()); 100 ob->writestring(" ("); 101 escapePath(ob, imod->srcfile->toChars()); 102 ob->writestring(") : "); 103 if (condition->ident) 104 ob->printf("%s\n", condition->ident->toChars()); 105 else 106 ob->printf("%d\n", condition->level); 107 } 108 109 110 int DebugCondition::include(Scope *sc, ScopeDsymbol *) 111 { 112 //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); 113 if (inc == 0) 114 { 115 inc = 2; 116 bool definedInModule = false; 117 if (ident) 118 { 119 if (findCondition(mod->debugids, ident)) 120 { 121 inc = 1; 122 definedInModule = true; 123 } 124 else if (findCondition(global.params.debugids, ident)) 125 inc = 1; 126 else 127 { if (!mod->debugidsNot) 128 mod->debugidsNot = new Strings(); 129 mod->debugidsNot->push(ident->toChars()); 130 } 131 } 132 else if (level <= global.params.debuglevel || level <= mod->debuglevel) 133 inc = 1; 134 if (!definedInModule) 135 printDepsConditional(sc, this, "depsDebug "); 136 } 137 return (inc == 1); 138 } 139 140 /* ============================================================ */ 141 142 void VersionCondition::setGlobalLevel(unsigned level) 143 { 144 global.params.versionlevel = level; 145 } 146 147 static bool isReserved(const char *ident) 148 { 149 static const char* reserved[] = 150 { 151 "DigitalMars", 152 "GNU", 153 "LDC", 154 "SDC", 155 "Windows", 156 "Win32", 157 "Win64", 158 "linux", 159 "OSX", 160 "FreeBSD", 161 "OpenBSD", 162 "NetBSD", 163 "DragonFlyBSD", 164 "BSD", 165 "Solaris", 166 "Posix", 167 "AIX", 168 "Haiku", 169 "SkyOS", 170 "SysV3", 171 "SysV4", 172 "Hurd", 173 "Android", 174 "PlayStation", 175 "PlayStation4", 176 "Cygwin", 177 "MinGW", 178 "FreeStanding", 179 "X86", 180 "X86_64", 181 "ARM", 182 "ARM_Thumb", 183 "ARM_SoftFloat", 184 "ARM_SoftFP", 185 "ARM_HardFloat", 186 "AArch64", 187 "Epiphany", 188 "PPC", 189 "PPC_SoftFloat", 190 "PPC_HardFloat", 191 "PPC64", 192 "IA64", 193 "MIPS32", 194 "MIPS64", 195 "MIPS_O32", 196 "MIPS_N32", 197 "MIPS_O64", 198 "MIPS_N64", 199 "MIPS_EABI", 200 "MIPS_SoftFloat", 201 "MIPS_HardFloat", 202 "MSP430", 203 "NVPTX", 204 "NVPTX64", 205 "RISCV32", 206 "RISCV64", 207 "SPARC", 208 "SPARC_V8Plus", 209 "SPARC_SoftFloat", 210 "SPARC_HardFloat", 211 "SPARC64", 212 "S390", 213 "S390X", 214 "HPPA", 215 "HPPA64", 216 "SH", 217 "Alpha", 218 "Alpha_SoftFloat", 219 "Alpha_HardFloat", 220 "LittleEndian", 221 "BigEndian", 222 "ELFv1", 223 "ELFv2", 224 "CRuntime_Digitalmars", 225 "CRuntime_Glibc", 226 "CRuntime_Microsoft", 227 "CRuntime_Musl", 228 "CRuntime_UClibc", 229 "CppRuntime_Clang", 230 "CppRuntime_DigitalMars", 231 "CppRuntime_Gcc", 232 "CppRuntime_Microsoft", 233 "CppRuntime_Sun", 234 "D_Coverage", 235 "D_Ddoc", 236 "D_InlineAsm_X86", 237 "D_InlineAsm_X86_64", 238 "D_LP64", 239 "D_X32", 240 "D_HardFloat", 241 "D_SoftFloat", 242 "D_PIC", 243 "D_SIMD", 244 "D_Version2", 245 "D_NoBoundsChecks", 246 "unittest", 247 "assert", 248 "all", 249 "none", 250 NULL 251 }; 252 253 for (unsigned i = 0; reserved[i]; i++) 254 { 255 if (strcmp(ident, reserved[i]) == 0) 256 return true; 257 } 258 259 if (ident[0] == 'D' && ident[1] == '_') 260 return true; 261 return false; 262 } 263 264 void checkReserved(Loc loc, const char *ident) 265 { 266 if (isReserved(ident)) 267 error(loc, "version identifier '%s' is reserved and cannot be set", ident); 268 } 269 270 void VersionCondition::addGlobalIdent(const char *ident) 271 { 272 checkReserved(Loc(), ident); 273 addPredefinedGlobalIdent(ident); 274 } 275 276 void VersionCondition::addPredefinedGlobalIdent(const char *ident) 277 { 278 if (!global.params.versionids) 279 global.params.versionids = new Strings(); 280 global.params.versionids->push(ident); 281 } 282 283 284 VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) 285 : DVCondition(mod, level, ident) 286 { 287 } 288 289 int VersionCondition::include(Scope *sc, ScopeDsymbol *) 290 { 291 //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); 292 //if (ident) printf("\tident = '%s'\n", ident->toChars()); 293 if (inc == 0) 294 { 295 inc = 2; 296 bool definedInModule=false; 297 if (ident) 298 { 299 if (findCondition(mod->versionids, ident)) 300 { 301 inc = 1; 302 definedInModule = true; 303 } 304 else if (findCondition(global.params.versionids, ident)) 305 inc = 1; 306 else 307 { 308 if (!mod->versionidsNot) 309 mod->versionidsNot = new Strings(); 310 mod->versionidsNot->push(ident->toChars()); 311 } 312 } 313 else if (level <= global.params.versionlevel || level <= mod->versionlevel) 314 inc = 1; 315 if (!definedInModule && (!ident || (!isReserved(ident->toChars()) && ident != Id::_unittest && ident != Id::_assert))) 316 printDepsConditional(sc, this, "depsVersion "); 317 } 318 return (inc == 1); 319 } 320 321 /**************************** StaticIfCondition *******************************/ 322 323 StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) 324 : Condition(loc) 325 { 326 this->exp = exp; 327 this->nest = 0; 328 } 329 330 Condition *StaticIfCondition::syntaxCopy() 331 { 332 return new StaticIfCondition(loc, exp->syntaxCopy()); 333 } 334 335 int StaticIfCondition::include(Scope *sc, ScopeDsymbol *sds) 336 { 337 if (inc == 0) 338 { 339 if (exp->op == TOKerror || nest > 100) 340 { 341 error(loc, (nest > 1000) ? "unresolvable circular static if expression" 342 : "error evaluating static if expression"); 343 goto Lerror; 344 } 345 346 if (!sc) 347 { 348 error(loc, "static if conditional cannot be at global scope"); 349 inc = 2; 350 return 0; 351 } 352 353 ++nest; 354 sc = sc->push(sc->scopesym); 355 sc->sds = sds; // sds gets any addMember() 356 357 bool errors = false; 358 bool result = evalStaticCondition(sc, exp, exp, errors); 359 sc->pop(); 360 --nest; 361 362 // Prevent repeated condition evaluation. 363 // See: fail_compilation/fail7815.d 364 if (inc != 0) 365 return (inc == 1); 366 if (errors) 367 goto Lerror; 368 if (result) 369 inc = 1; 370 else 371 inc = 2; 372 } 373 return (inc == 1); 374 375 Lerror: 376 if (!global.gag) 377 inc = 2; // so we don't see the error message again 378 return 0; 379 } 380