xref: /netbsd-src/external/gpl3/gcc/dist/gcc/d/dmd/globals.d (revision b1e838363e3c6fc78a55519254d99869742dd33c)
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