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