1 /**
2 * Stores command line options and contains other miscellaneous declarations.
3 *
4 * Copyright: Copyright (C) 1999-2022 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.stdint;
15 import dmd.root.array;
16 import dmd.root.filename;
17 import dmd.common.outbuffer;
18 import dmd.file_manager;
19 import dmd.identifier;
20
21 /// Defines a setting for how compiler warnings and deprecations are handled
22 enum DiagnosticReporting : ubyte
23 {
24 error, /// generate an error
25 inform, /// generate a warning
26 off, /// disable diagnostic
27 }
28
29 /// How code locations are formatted for diagnostic reporting
30 enum MessageStyle : ubyte
31 {
32 digitalmars, /// filename.d(line): message
33 gnu, /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
34 }
35
36 /// In which context checks for assertions, contracts, bounds checks etc. are enabled
37 enum CHECKENABLE : ubyte
38 {
39 _default, /// initial value
40 off, /// never do checking
41 on, /// always do checking
42 safeonly, /// do checking only in @safe functions
43 }
44
45 /// What should happend when an assertion fails
46 enum CHECKACTION : ubyte
47 {
48 D, /// call D assert on failure
49 C, /// call C assert on failure
50 halt, /// cause program halt on failure
51 context, /// call D assert with the error context on failure
52 }
53
54 /// Position Indepent Code setting
55 enum PIC : ubyte
56 {
57 fixed, /// located at a specific address
58 pic, /// Position Independent Code
59 pie, /// Position Independent Executable
60 }
61
62 /**
63 Each flag represents a field that can be included in the JSON output.
64
65 NOTE: set type to uint so its size matches C++ unsigned type
66 */
67 enum JsonFieldFlags : uint
68 {
69 none = 0,
70 compilerInfo = (1 << 0),
71 buildInfo = (1 << 1),
72 modules = (1 << 2),
73 semantics = (1 << 3),
74 }
75
76 /// Version of C++ standard to support
77 enum CppStdRevision : uint
78 {
79 cpp98 = 1997_11,
80 cpp11 = 2011_03,
81 cpp14 = 2014_02,
82 cpp17 = 2017_03,
83 cpp20 = 2020_02,
84 }
85
86 /// Configuration for the C++ header generator
87 enum CxxHeaderMode : uint
88 {
89 none, /// Don't generate headers
90 silent, /// Generate headers
91 verbose /// Generate headers and add comments for hidden declarations
92 }
93
94 /// Trivalent boolean to represent the state of a `revert`able change
95 enum FeatureState : byte
96 {
97 default_ = -1, /// Not specified by the user
98 disabled = 0, /// Specified as `-revert=`
99 enabled = 1 /// Specified as `-preview=`
100 }
101
102 /// Put command line switches in here
103 extern (C++) struct Param
104 {
105 bool obj = true; // write object file
106 bool link = true; // perform link
107 bool dll; // generate shared dynamic library
108 bool lib; // write library file instead of object file(s)
109 bool multiobj; // break one object file into multiple ones
110 bool oneobj; // write one object file instead of multiple ones
111 bool trace; // insert profiling hooks
112 bool tracegc; // instrument calls to 'new'
113 bool verbose; // verbose compile
114 bool vcg_ast; // write-out codegen-ast
115 bool showColumns; // print character (column) numbers in diagnostics
116 bool vtls; // identify thread local variables
117 bool vtemplates; // collect and list statistics on template instantiations
118 bool vtemplatesListInstances; // collect and list statistics on template instantiations origins. TODO: make this an enum when we want to list other kinds of instances
119 bool vgc; // identify gc usage
120 bool vfield; // identify non-mutable field variables
121 bool vcomplex = true; // identify complex/imaginary type usage
122 bool vin; // identify 'in' parameters
123 ubyte symdebug; // insert debug symbolic information
124 bool symdebugref; // insert debug information for all referenced types, too
125 bool optimize; // run optimizer
126 DiagnosticReporting useDeprecated = DiagnosticReporting.inform; // how use of deprecated features are handled
127 bool stackstomp; // add stack stomping code
128 bool useUnitTests; // generate unittest code
129 bool useInline = false; // inline expand functions
130 FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25
131 FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
132 bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
133 bool release; // build release version
134 bool preservePaths; // true means don't strip path from source file
135 DiagnosticReporting warnings = DiagnosticReporting.off; // how compiler warnings are handled
136 PIC pic = PIC.fixed; // generate fixed, pic or pie code
137 bool color; // use ANSI colors in console output
138 bool cov; // generate code coverage data
139 ubyte covPercent; // 0..100 code coverage percentage required
140 bool ctfe_cov = false; // generate coverage data for ctfe
141 bool nofloat; // code should not pull in floating point support
142 bool ignoreUnsupportedPragmas; // rather than error on them
143 bool useModuleInfo = true; // generate runtime module information
144 bool useTypeInfo = true; // generate runtime type information
145 bool useExceptions = true; // support exception handling
146 bool noSharedAccess; // read/write access to shared memory objects
147 bool previewIn; // `in` means `[ref] scope const`, accepts rvalues
148 bool shortenedMethods; // allow => in normal function declarations
149 bool betterC; // be a "better C" compiler; no dependency on D runtime
150 bool addMain; // add a default main() function
151 bool allInst; // generate code for all template instantiations
152 bool fix16997 = true; // fix integral promotions for unary + - ~ operators
153 // https://issues.dlang.org/show_bug.cgi?id=16997
154 bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
155 bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
156 /** The --transition=safe switch should only be used to show code with
157 * silent semantics changes related to @safe improvements. It should not be
158 * used to hide a feature that will have to go through deprecate-then-error
159 * before becoming default.
160 */
161 bool ehnogc; // use @nogc exception handling
162 FeatureState dtorFields; // destruct fields of partially constructed objects
163 // https://issues.dlang.org/show_bug.cgi?id=14246
164 bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
165 FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
166 // https://dconf.org/2019/talks/alexandrescu.html
167 // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
168 // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
169 // Implementation: https://github.com/dlang/dmd/pull/9817
170
171 CppStdRevision cplusplus = CppStdRevision.cpp11; // version of C++ standard to support
172
173 bool markdown = true; // enable Markdown replacements in Ddoc
174 bool vmarkdown; // list instances of Markdown replacements in Ddoc
175
176 bool showGaggedErrors; // print gagged errors anyway
177 bool printErrorContext; // print errors with the error context (the error line in the source file)
178 bool manual; // open browser on compiler manual
179 bool usage; // print usage and exit
180 bool mcpuUsage; // print help on -mcpu switch
181 bool transitionUsage; // print help on -transition switch
182 bool checkUsage; // print help on -check switch
183 bool checkActionUsage; // print help on -checkaction switch
184 bool revertUsage; // print help on -revert switch
185 bool previewUsage; // print help on -preview switch
186 bool externStdUsage; // print help on -extern-std switch
187 bool hcUsage; // print help on -HC switch
188 bool logo; // print compiler logo
189
190 CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks
191 CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks
192 CHECKENABLE useOut = CHECKENABLE._default; // generate postcondition checks
193 CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks
194 CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s
195 CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default
196 CHECKENABLE boundscheck = CHECKENABLE._default; // state of -boundscheck switch
197
198 CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated
199
200 uint errorLimit = 20;
201
202 const(char)[] argv0; // program name
203 Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
204 Array!(const(char)*)* imppath; // array of char*'s of where to look for import modules
205 Array!(const(char)*)* fileImppath; // array of char*'s of where to look for file import modules
206 const(char)[] objdir; // .obj/.lib file output directory
207 const(char)[] objname; // .obj file output name
208 const(char)[] libname; // .lib file output name
209
210 bool doDocComments; // process embedded documentation comments
211 const(char)[] docdir; // write documentation file to docdir directory
212 const(char)[] docname; // write documentation file to docname
213 Array!(const(char)*) ddocfiles; // macro include files for Ddoc
214
215 bool doHdrGeneration; // process embedded documentation comments
216 const(char)[] hdrdir; // write 'header' file to docdir directory
217 const(char)[] hdrname; // write 'header' file to docname
218 bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions
219
220 CxxHeaderMode doCxxHdrGeneration; /// Generate 'Cxx header' file
221 const(char)[] cxxhdrdir; // write 'header' file to docdir directory
222 const(char)[] cxxhdrname; // write 'header' file to docname
223
224 bool doJsonGeneration; // write JSON file
225 const(char)[] jsonfilename; // write JSON file to jsonfilename
226 JsonFieldFlags jsonFieldFlags; // JSON field flags to include
227
228 OutBuffer* mixinOut; // write expanded mixins for debugging
229 const(char)* mixinFile; // .mixin file output name
230 int mixinLines; // Number of lines in writeMixins
231
232 uint debuglevel; // debug level
233 Array!(const(char)*)* debugids; // debug identifiers
234
235 uint versionlevel; // version level
236 Array!(const(char)*)* versionids; // version identifiers
237
238 const(char)[] defaultlibname; // default library for non-debug builds
239 const(char)[] debuglibname; // default library for debug builds
240 const(char)[] mscrtlib; // MS C runtime library
241
242 const(char)[] moduleDepsFile; // filename for deps output
243 OutBuffer* moduleDeps; // contents to be written to deps file
244
245 bool emitMakeDeps; // whether to emit makedeps
246 const(char)[] makeDepsFile; // filename for makedeps output
247 Array!(const(char)*) makeDeps; // dependencies for makedeps
248
249 MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages
250
251 bool run; // run resulting executable
252 Strings runargs; // arguments for executable
253
254 // Linker stuff
255 Array!(const(char)*) objfiles;
256 Array!(const(char)*) linkswitches;
257 Array!bool linkswitchIsForCC;
258 Array!(const(char)*) libfiles;
259 Array!(const(char)*) dllfiles;
260 const(char)[] deffile;
261 const(char)[] resfile;
262 const(char)[] exefile;
263 const(char)[] mapfile;
264 }
265
266 extern (C++) struct structalign_t
267 {
268 private:
269 ushort value = 0; // unknown
270 enum STRUCTALIGN_DEFAULT = 1234; // default = match whatever the corresponding C compiler does
271 bool pack; // use #pragma pack semantics
272
273 public:
274 pure @safe @nogc nothrow:
isDefaultstructalign_t275 bool isDefault() const { return value == STRUCTALIGN_DEFAULT; }
setDefaultstructalign_t276 void setDefault() { value = STRUCTALIGN_DEFAULT; }
isUnknownstructalign_t277 bool isUnknown() const { return value == 0; } // value is not set
setUnknownstructalign_t278 void setUnknown() { value = 0; }
setstructalign_t279 void set(uint value) { this.value = cast(ushort)value; }
getstructalign_t280 uint get() const { return value; }
isPackstructalign_t281 bool isPack() const { return pack; }
setPackstructalign_t282 void setPack(bool pack) { this.pack = pack; }
283 }
284 //alias structalign_t = uint;
285
286 // magic value means "match whatever the underlying C compiler does"
287 // other values are all powers of 2
288 //enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
289
290 enum mars_ext = "d"; // for D source files
291 enum doc_ext = "html"; // for Ddoc generated files
292 enum ddoc_ext = "ddoc"; // for Ddoc macro include files
293 enum dd_ext = "dd"; // for Ddoc source files
294 enum hdr_ext = "di"; // for D 'header' import files
295 enum json_ext = "json"; // for JSON files
296 enum map_ext = "map"; // for .map files
297 enum c_ext = "c"; // for C source files
298 enum i_ext = "i"; // for preprocessed C source file
299
300 /**
301 * Collection of global compiler settings and global state used by the frontend
302 */
303 extern (C++) struct Global
304 {
305 const(char)[] inifilename; /// filename of configuration file as given by `-conf=`, or default value
306
307 string copyright = "Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved";
308 string written = "written by Walter Bright";
309
310 Array!(const(char)*)* path; /// Array of char*'s which form the import lookup path
311 Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path
312
313 private enum string _version = import("VERSION");
314 private enum uint _versionNumber = parseVersionNumber(_version);
315
316 const(char)[] vendor; /// Compiler backend name
317
318 Param params; /// command line parameters
319 uint errors; /// number of errors reported so far
320 uint warnings; /// number of warnings reported so far
321 uint gag; /// !=0 means gag reporting of errors & warnings
322 uint gaggedErrors; /// number of errors reported while gagged
323 uint gaggedWarnings; /// number of warnings reported while gagged
324
325 void* console; /// opaque pointer to console for controlling text attributes
326
327 Array!Identifier* versionids; /// command line versions and predefined versions
328 Array!Identifier* debugids; /// command line debug versions and predefined versions
329
330 bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
331 uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
332
333 /// Cache files read from disk
334 FileManager fileManager;
335
336 enum recursionLimit = 500; /// number of recursive template expansions before abort
337
338 nothrow:
339
340 /**
341 * Start ignoring compile errors instead of reporting them.
342 *
343 * Used for speculative compilation like `__traits(compiles, XXX)`, but also internally
344 * to e.g. try out an `alias this` rewrite without comitting to it.
345 *
346 * Works like a stack, so N calls to `startGagging` should be paired with N
347 * calls to `endGagging`.
348 *
349 * Returns: the current number of gagged errors, which should later be passed to `endGagging`
350 */
startGaggingGlobal351 extern (C++) uint startGagging()
352 {
353 ++gag;
354 gaggedWarnings = 0;
355 return gaggedErrors;
356 }
357
358 /**
359 * Stop gagging, restoring the old gagged state before the most recent call to `startGagging`.
360 *
361 * Params:
362 * oldGagged = the previous number of errors, as returned by `startGagging`
363 * Returns: true if errors occurred while gagged.
364 */
endGaggingGlobal365 extern (C++) bool endGagging(uint oldGagged)
366 {
367 bool anyErrs = (gaggedErrors != oldGagged);
368 --gag;
369 // Restore the original state of gagged errors; set total errors
370 // to be original errors + new ungagged errors.
371 errors -= (gaggedErrors - oldGagged);
372 gaggedErrors = oldGagged;
373 return anyErrs;
374 }
375
376 /**
377 * Increment the error count to record that an error has occurred in the current context.
378 *
379 * An error message may or may not have been printed.
380 */
increaseErrorCountGlobal381 extern (C++) void increaseErrorCount()
382 {
383 if (gag)
384 ++gaggedErrors;
385 ++errors;
386 }
387
_initGlobal388 extern (C++) void _init()
389 {
390 this.fileManager = new FileManager();
391 version (MARS)
392 {
393 vendor = "Digital Mars D";
394
395 // -color=auto is the default value
396 import dmd.console : detectTerminal;
397 params.color = detectTerminal();
398 }
399 else version (IN_GCC)
400 {
401 vendor = "GNU D";
402 }
403 }
404
405 /**
406 * Deinitializes the global state of the compiler.
407 *
408 * This can be used to restore the state set by `_init` to its original
409 * state.
410 */
deinitializeGlobal411 extern (D) void deinitialize()
412 {
413 this = this.init;
414 }
415
416 /**
417 * Computes the version number __VERSION__ from the compiler version string.
418 */
parseVersionNumberGlobal419 extern (D) private static uint parseVersionNumber(string version_)
420 {
421 //
422 // parse _version
423 //
424 uint major = 0;
425 uint minor = 0;
426 bool point = false;
427 // skip initial 'v'
428 foreach (const c; version_[1..$])
429 {
430 if ('0' <= c && c <= '9') // isdigit
431 {
432 minor = minor * 10 + c - '0';
433 }
434 else if (c == '.')
435 {
436 if (point)
437 break; // ignore everything after second '.'
438 point = true;
439 major = minor;
440 minor = 0;
441 }
442 else
443 break;
444 }
445 return major * 1000 + minor;
446 }
447
448 /**
449 Returns: the version as the number that would be returned for __VERSION__
450 */
versionNumberGlobal451 extern(C++) uint versionNumber()
452 {
453 return _versionNumber;
454 }
455
456 /**
457 Returns: compiler version string.
458 */
versionStringGlobal459 extern(D) string versionString()
460 {
461 return _version;
462 }
463
464 /**
465 Returns: compiler version as char string.
466 */
versionCharsGlobal467 extern(C++) const(char*) versionChars()
468 {
469 return _version.ptr;
470 }
471
472 /**
473 Returns: the final defaultlibname based on the command-line parameters
474 */
finalDefaultlibnameGlobal475 extern (D) const(char)[] finalDefaultlibname() const
476 {
477 return params.betterC ? null :
478 params.symdebug ? params.debuglibname : params.defaultlibname;
479 }
480 }
481
482 // Because int64_t and friends may be any integral type of the
483 // correct size, we have to explicitly ask for the correct
484 // integer type to get the correct mangling with dmd
485
486 // Be careful not to care about sign when using dinteger_t
487 // use this instead of integer_t to
488 // avoid conflicts with system #include's
489 alias dinteger_t = ulong;
490 // Signed and unsigned variants
491 alias sinteger_t = long;
492 alias uinteger_t = ulong;
493
version(DMDLIB)494 version (DMDLIB)
495 {
496 version = LocOffset;
497 }
498
499 /**
500 A source code location
501
502 Used for error messages, `__FILE__` and `__LINE__` tokens, `__traits(getLocation, XXX)`,
503 debug info etc.
504 */
505 struct Loc
506 {
507 /// zero-terminated filename string, either absolute or relative to cwd
508 const(char)* filename;
509 uint linnum; /// line number, starting from 1
510 uint charnum; /// utf8 code unit index relative to start of line, starting from 1
511 version (LocOffset)
512 uint fileOffset; /// utf8 code unit index relative to start of file, starting from 0
513
514 static immutable Loc initial; /// use for default initialization of const ref Loc's
515
516 nothrow:
thisLoc517 extern (D) this(const(char)* filename, uint linnum, uint charnum) pure
518 {
519 this.linnum = linnum;
520 this.charnum = charnum;
521 this.filename = filename;
522 }
523
524 extern (C++) const(char)* toChars(
525 bool showColumns = global.params.showColumns,
526 ubyte messageStyle = global.params.messageStyle) const pure nothrow
527 {
528 OutBuffer buf;
529 if (filename)
530 {
531 buf.writestring(filename);
532 }
533 if (linnum)
534 {
535 final switch (messageStyle)
536 {
537 case MessageStyle.digitalmars:
538 buf.writeByte('(');
539 buf.print(linnum);
540 if (showColumns && charnum)
541 {
542 buf.writeByte(',');
543 buf.print(charnum);
544 }
545 buf.writeByte(')');
546 break;
547 case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
548 buf.writeByte(':');
549 buf.print(linnum);
550 if (showColumns && charnum)
551 {
552 buf.writeByte(':');
553 buf.print(charnum);
554 }
555 break;
556 }
557 }
558 return buf.extractChars();
559 }
560
561 /**
562 * Checks for equivalence by comparing the filename contents (not the pointer) and character location.
563 *
564 * Note:
565 * - Uses case-insensitive comparison on Windows
566 * - Ignores `charnum` if `global.params.showColumns` is false.
567 */
equalsLoc568 extern (C++) bool equals(ref const(Loc) loc) const
569 {
570 return (!global.params.showColumns || charnum == loc.charnum) &&
571 linnum == loc.linnum &&
572 FileName.equals(filename, loc.filename);
573 }
574
575 /**
576 * `opEquals()` / `toHash()` for AA key usage
577 *
578 * Compare filename contents (case-sensitively on Windows too), not
579 * the pointer - a static foreach loop repeatedly mixing in a mixin
580 * may lead to multiple equivalent filenames (`foo.d-mixin-<line>`),
581 * e.g., for test/runnable/test18880.d.
582 */
opEqualsLoc583 extern (D) bool opEquals(ref const(Loc) loc) const @trusted pure nothrow @nogc
584 {
585 import core.stdc.string : strcmp;
586
587 return charnum == loc.charnum &&
588 linnum == loc.linnum &&
589 (filename == loc.filename ||
590 (filename && loc.filename && strcmp(filename, loc.filename) == 0));
591 }
592
593 /// ditto
toHashLoc594 extern (D) size_t toHash() const @trusted pure nothrow
595 {
596 import dmd.root.string : toDString;
597
598 auto hash = hashOf(linnum);
599 hash = hashOf(charnum, hash);
600 hash = hashOf(filename.toDString, hash);
601 return hash;
602 }
603
604 /******************
605 * Returns:
606 * true if Loc has been set to other than the default initialization
607 */
isValidLoc608 bool isValid() const pure
609 {
610 return filename !is null;
611 }
612 }
613
614 /// Collection of global state
615 extern (C++) __gshared Global global;
616