1 /** 2 * Stores command line options and contains other miscellaneous declarations. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/globals.d, _globals.d) 8 * Documentation: https://dlang.org/phobos/dmd_globals.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/globals.d 10 */ 11 12 module dmd.globals; 13 14 import core.stdc.stdio; 15 import core.stdc.stdint; 16 import core.stdc.string; 17 18 import dmd.root.array; 19 import dmd.root.filename; 20 import dmd.common.outbuffer; 21 import dmd.errorsink; 22 import dmd.errors; 23 import dmd.file_manager; 24 import dmd.identifier; 25 import dmd.location; 26 import dmd.lexer : CompileEnv; 27 import dmd.utils; 28 29 version (IN_GCC) {} 30 else version (IN_LLVM) {} 31 else version = MARS; 32 33 /// Defines a setting for how compiler warnings and deprecations are handled 34 enum DiagnosticReporting : ubyte 35 { 36 error, /// generate an error 37 inform, /// generate a warning 38 off, /// disable diagnostic 39 } 40 41 /// In which context checks for assertions, contracts, bounds checks etc. are enabled 42 enum CHECKENABLE : ubyte 43 { 44 _default, /// initial value 45 off, /// never do checking 46 on, /// always do checking 47 safeonly, /// do checking only in @safe functions 48 } 49 50 /// What should happend when an assertion fails 51 enum CHECKACTION : ubyte 52 { 53 D, /// call D assert on failure 54 C, /// call C assert on failure 55 halt, /// cause program halt on failure 56 context, /// call D assert with the error context on failure 57 } 58 59 /** 60 Each flag represents a field that can be included in the JSON output. 61 62 NOTE: set type to uint so its size matches C++ unsigned type 63 */ 64 enum JsonFieldFlags : uint 65 { 66 none = 0, 67 compilerInfo = (1 << 0), 68 buildInfo = (1 << 1), 69 modules = (1 << 2), 70 semantics = (1 << 3), 71 } 72 73 /// Version of C++ standard to support 74 enum CppStdRevision : uint 75 { 76 cpp98 = 1997_11, 77 cpp11 = 2011_03, 78 cpp14 = 2014_02, 79 cpp17 = 2017_03, 80 cpp20 = 2020_02, 81 } 82 83 /// Trivalent boolean to represent the state of a `revert`able change 84 enum FeatureState : ubyte 85 { 86 default_ = 0, /// Not specified by the user 87 disabled = 1, /// Specified as `-revert=` 88 enabled = 2, /// Specified as `-preview=` 89 } 90 91 extern(C++) struct Output 92 { 93 bool doOutput; // Output is enabled 94 bool fullOutput; // Generate comments for hidden declarations (for -HC), 95 // and don't strip the bodies of plain (non-template) functions (for -H) 96 97 const(char)[] dir; // write to directory 'dir' 98 const(char)[] name; // write to file 'name' 99 Array!(const(char)*) files; // Other files associated with this output, 100 // e.g. macro include files for Ddoc, dependencies for makedeps 101 OutBuffer* buffer; // if this output is buffered, this is the buffer 102 int bufferLines; // number of lines written to the buffer 103 } 104 105 /// Command line state related to printing usage about other switches 106 extern(C++) struct Help 107 { 108 bool manual; // open browser on compiler manual 109 bool usage; // print usage and exit 110 // print help of switch: 111 bool mcpu; // -mcpu 112 bool transition; // -transition 113 bool check; // -check 114 bool checkAction; // -checkaction 115 bool revert; // -revert 116 bool preview; // -preview 117 bool externStd; // -extern-std 118 bool hc; // -HC 119 } 120 121 extern(C++) struct Verbose 122 { 123 bool verbose; // verbose compile 124 bool showColumns; // print character (column) numbers in diagnostics 125 bool tls; // identify thread local variables 126 bool templates; // collect and list statistics on template instantiations 127 // collect and list statistics on template instantiations origins. 128 // TODO: make this an enum when we want to list other kinds of instances 129 bool templatesListInstances; 130 bool gc; // identify gc usage 131 bool field; // identify non-mutable field variables 132 bool complex = true; // identify complex/imaginary type usage 133 bool vin; // identify 'in' parameters 134 bool showGaggedErrors; // print gagged errors anyway 135 bool printErrorContext; // print errors with the error context (the error line in the source file) 136 bool logo; // print compiler logo 137 bool color; // use ANSI colors in console output 138 bool cov; // generate code coverage data 139 MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages 140 uint errorLimit = 20; 141 uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited) 142 143 uint errorSupplementCount() 144 { 145 if (verbose) 146 return uint.max; 147 if (errorSupplementLimit == 0) 148 return uint.max; 149 return errorSupplementLimit; 150 } 151 } 152 153 /// Put command line switches in here 154 extern (C++) struct Param 155 { 156 bool obj = true; // write object file 157 bool multiobj; // break one object file into multiple ones 158 bool trace; // insert profiling hooks 159 bool tracegc; // instrument calls to 'new' 160 bool vcg_ast; // write-out codegen-ast 161 DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled 162 bool useUnitTests; // generate unittest code 163 bool useInline = false; // inline expand functions 164 bool release; // build release version 165 bool preservePaths; // true means don't strip path from source file 166 DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled 167 bool cov; // generate code coverage data 168 ubyte covPercent; // 0..100 code coverage percentage required 169 bool ctfe_cov = false; // generate coverage data for ctfe 170 bool ignoreUnsupportedPragmas; // rather than error on them 171 bool useModuleInfo = true; // generate runtime module information 172 bool useTypeInfo = true; // generate runtime type information 173 bool useExceptions = true; // support exception handling 174 bool useGC = true; // support features that require the D runtime GC 175 bool betterC; // be a "better C" compiler; no dependency on D runtime 176 bool addMain; // add a default main() function 177 bool allInst; // generate code for all template instantiations 178 bool bitfields; // support C style bit fields 179 180 CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support 181 182 Help help; 183 Verbose v; 184 185 // Options for `-preview=/-revert=` 186 FeatureState useDIP25 = FeatureState.enabled; // implement https://wiki.dlang.org/DIP25 187 FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params 188 bool ehnogc; // use @nogc exception handling 189 bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md 190 FeatureState fieldwise; // do struct equality testing field-wise rather than by memcmp() 191 bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes 192 FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters 193 // https://dconf.org/2019/talks/alexandrescu.html 194 // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a 195 // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html 196 // Implementation: https://github.com/dlang/dmd/pull/9817 197 FeatureState noSharedAccess; // read/write access to shared memory objects 198 bool previewIn; // `in` means `[ref] scope const`, accepts rvalues 199 bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract 200 bool shortenedMethods = true; // allow => in normal function declarations 201 bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 202 bool fix16997 = true; // fix integral promotions for unary + - ~ operators 203 // https://issues.dlang.org/show_bug.cgi?id=16997 204 FeatureState dtorFields; // destruct fields of partially constructed objects 205 // https://issues.dlang.org/show_bug.cgi?id=14246 206 FeatureState systemVariables; // limit access to variables marked @system from @safe code 207 208 CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks 209 CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks 210 CHECKENABLE useOut = CHECKENABLE._default; // generate postcondition checks 211 CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks 212 CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s 213 CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default 214 CHECKENABLE boundscheck = CHECKENABLE._default; // state of -boundscheck switch 215 216 CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated 217 218 const(char)[] argv0; // program name 219 Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings 220 Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules 221 Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules 222 const(char)[] objdir; // .obj/.lib file output directory 223 const(char)[] objname; // .obj file output name 224 const(char)[] libname; // .lib file output name 225 226 Output ddoc; // Generate embedded documentation comments 227 Output dihdr; // Generate `.di` 'header' files 228 Output cxxhdr; // Generate 'Cxx header' file 229 Output json; // Generate JSON file 230 JsonFieldFlags jsonFieldFlags; // JSON field flags to include 231 Output makeDeps; // Generate make file dependencies 232 Output mixinOut; // write expanded mixins for debugging 233 Output moduleDeps; // Generate `.deps` module dependencies 234 235 uint debuglevel; // debug level 236 uint versionlevel; // version level 237 238 bool run; // run resulting executable 239 Strings runargs; // arguments for executable 240 Array!(const(char)*) cppswitches; // C preprocessor switches 241 const(char)* cpp; // if not null, then this specifies the C preprocessor 242 243 // Linker stuff 244 Array!(const(char)*) objfiles; 245 Array!(const(char)*) linkswitches; 246 Array!bool linkswitchIsForCC; 247 Array!(const(char)*) libfiles; 248 Array!(const(char)*) dllfiles; 249 const(char)[] deffile; 250 const(char)[] resfile; 251 const(char)[] exefile; 252 const(char)[] mapfile; 253 } 254 255 enum mars_ext = "d"; // for D source files 256 enum doc_ext = "html"; // for Ddoc generated files 257 enum ddoc_ext = "ddoc"; // for Ddoc macro include files 258 enum dd_ext = "dd"; // for Ddoc source files 259 enum hdr_ext = "di"; // for D 'header' import files 260 enum json_ext = "json"; // for JSON files 261 enum map_ext = "map"; // for .map files 262 enum c_ext = "c"; // for C source files 263 enum i_ext = "i"; // for preprocessed C source file 264 265 /** 266 * Collection of global compiler settings and global state used by the frontend 267 */ 268 extern (C++) struct Global 269 { 270 const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value 271 272 string copyright = "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved"; 273 string written = "written by Walter Bright"; 274 275 Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path 276 Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path 277 278 private enum string _version = import("VERSION"); 279 char[26] datetime; /// string returned by ctime() 280 CompileEnv compileEnv; 281 282 Param params; /// command line parameters 283 uint errors; /// number of errors reported so far 284 uint warnings; /// number of warnings reported so far 285 uint gag; /// !=0 means gag reporting of errors & warnings 286 uint gaggedErrors; /// number of errors reported while gagged 287 uint gaggedWarnings; /// number of warnings reported while gagged 288 289 void* console; /// opaque pointer to console for controlling text attributes 290 291 Array!Identifier* versionids; /// command line versions and predefined versions 292 Array!Identifier* debugids; /// command line debug versions and predefined versions 293 294 bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch) 295 uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks 296 297 /// Cache files read from disk 298 FileManager fileManager; 299 300 enum recursionLimit = 500; /// number of recursive template expansions before abort 301 302 ErrorSink errorSink; /// where the error messages go 303 ErrorSink errorSinkNull; /// where the error messages are ignored 304 305 extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; 306 307 nothrow: 308 309 /** 310 * Start ignoring compile errors instead of reporting them. 311 * 312 * Used for speculative compilation like `__traits(compiles, XXX)`, but also internally 313 * to e.g. try out an `alias this` rewrite without comitting to it. 314 * 315 * Works like a stack, so N calls to `startGagging` should be paired with N 316 * calls to `endGagging`. 317 * 318 * Returns: the current number of gagged errors, which should later be passed to `endGagging` 319 */ 320 extern (C++) uint startGagging() @safe 321 { 322 ++gag; 323 gaggedWarnings = 0; 324 return gaggedErrors; 325 } 326 327 /** 328 * Stop gagging, restoring the old gagged state before the most recent call to `startGagging`. 329 * 330 * Params: 331 * oldGagged = the previous number of errors, as returned by `startGagging` 332 * Returns: true if errors occurred while gagged. 333 */ 334 extern (C++) bool endGagging(uint oldGagged) @safe 335 { 336 bool anyErrs = (gaggedErrors != oldGagged); 337 --gag; 338 // Restore the original state of gagged errors; set total errors 339 // to be original errors + new ungagged errors. 340 errors -= (gaggedErrors - oldGagged); 341 gaggedErrors = oldGagged; 342 return anyErrs; 343 } 344 345 /** 346 * Increment the error count to record that an error has occurred in the current context. 347 * 348 * An error message may or may not have been printed. 349 */ 350 extern (C++) void increaseErrorCount() @safe 351 { 352 if (gag) 353 ++gaggedErrors; 354 ++errors; 355 } 356 357 extern (C++) void _init() 358 { 359 errorSink = new ErrorSinkCompiler; 360 errorSinkNull = new ErrorSinkNull; 361 362 this.fileManager = new FileManager(); 363 version (MARS) 364 { 365 compileEnv.vendor = "Digital Mars D"; 366 367 // -color=auto is the default value 368 import dmd.console : detectTerminal, detectColorPreference; 369 params.v.color = detectTerminal() && detectColorPreference(); 370 } 371 else version (IN_GCC) 372 { 373 compileEnv.vendor = "GNU D"; 374 } 375 compileEnv.versionNumber = parseVersionNumber(_version); 376 377 /* Initialize date, time, and timestamp 378 */ 379 import core.stdc.time; 380 import core.stdc.stdlib : getenv; 381 382 time_t ct; 383 // https://issues.dlang.org/show_bug.cgi?id=20444 384 if (auto p = getenv("SOURCE_DATE_EPOCH")) 385 { 386 if (!ct.parseDigits(p[0 .. strlen(p)])) 387 errorSink.error(Loc.initial, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); 388 } 389 else 390 core.stdc.time.time(&ct); 391 const p = ctime(&ct); 392 assert(p); 393 datetime[] = p[0 .. 26]; 394 395 __gshared char[11 + 1] date = 0; // put in BSS segment 396 __gshared char[8 + 1] time = 0; 397 __gshared char[24 + 1] timestamp = 0; 398 399 const dsz = snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20); 400 const tsz = snprintf(&time[0], time.length, "%.8s", p + 11); 401 const tssz = snprintf(×tamp[0], timestamp.length, "%.24s", p); 402 assert(dsz > 0 && tsz > 0 && tssz > 0); 403 compileEnv.time = time[0 .. tsz]; 404 compileEnv.date = date[0 .. dsz]; 405 compileEnv.timestamp = timestamp[0 .. tssz]; 406 } 407 408 /** 409 * Deinitializes the global state of the compiler. 410 * 411 * This can be used to restore the state set by `_init` to its original 412 * state. 413 */ 414 extern (D) void deinitialize() 415 { 416 this = this.init; 417 } 418 419 /** 420 * Computes the version number __VERSION__ from the compiler version string. 421 */ 422 extern (D) private static uint parseVersionNumber(string version_) @safe 423 { 424 // 425 // parse _version 426 // 427 uint major = 0; 428 uint minor = 0; 429 bool point = false; 430 // skip initial 'v' 431 foreach (const c; version_[1..$]) 432 { 433 if ('0' <= c && c <= '9') // isdigit 434 { 435 minor = minor * 10 + c - '0'; 436 } 437 else if (c == '.') 438 { 439 if (point) 440 break; // ignore everything after second '.' 441 point = true; 442 major = minor; 443 minor = 0; 444 } 445 else 446 break; 447 } 448 return major * 1000 + minor; 449 } 450 451 /** 452 Returns: the version as the number that would be returned for __VERSION__ 453 */ 454 extern(C++) uint versionNumber() @safe 455 { 456 return compileEnv.versionNumber; 457 } 458 459 /** 460 Returns: compiler version string. 461 */ 462 extern(D) string versionString() @safe 463 { 464 return _version; 465 } 466 467 /** 468 Returns: compiler version as char string. 469 */ 470 extern(C++) const(char*) versionChars() 471 { 472 return _version.ptr; 473 } 474 } 475 476 // Because int64_t and friends may be any integral type of the 477 // correct size, we have to explicitly ask for the correct 478 // integer type to get the correct mangling with dmd 479 480 // Be careful not to care about sign when using dinteger_t 481 // use this instead of integer_t to 482 // avoid conflicts with system #include's 483 alias dinteger_t = ulong; 484 // Signed and unsigned variants 485 alias sinteger_t = long; 486 alias uinteger_t = ulong; 487 488 /// Collection of global state 489 extern (C++) __gshared Global global;