diff --git a/changelog/check-switch.dd b/changelog/check-switch.dd new file mode 100644 index 000000000000..de0ad0edd7e7 --- /dev/null +++ b/changelog/check-switch.dd @@ -0,0 +1,18 @@ +Added -check switch to turn on and off each category of runtime checks. + + Option("check=[assert|bounds|in|invariant|out|switch][=[on|off]]", + `Overrides default, -boundscheck, -release and -unittest options to enable or disable specific checks. + $(UL + $(LI $(B assert): assertion checking) + $(LI $(B bounds): array bounds) + $(LI $(B in): in contracts) + $(LI $(B invariant): class/struct invariants) + $(LI $(B out): out contracts) + $(LI $(B switch): switch default) + ) + $(UL + $(LI $(B on) or not specified: specified check is enabled.) + $(LI $(B off): specified check is disabled.) + )` + ) + diff --git a/src/dmd/cli.d b/src/dmd/cli.d index bc579817c080..07769447dd69 100644 --- a/src/dmd/cli.d +++ b/src/dmd/cli.d @@ -169,14 +169,30 @@ struct Usage Option("c", "compile only, do not link" ), + Option("check=[assert|bounds|in|invariant|out|switch][=[on|off]]", + "Enable or disable specific checks", + `Overrides default, -boundscheck, -release and -unittest options to enable or disable specific checks. + $(UL + $(LI $(B assert): assertion checking) + $(LI $(B bounds): array bounds) + $(LI $(B in): in contracts) + $(LI $(B invariant): class/struct invariants) + $(LI $(B out): out contracts) + $(LI $(B switch): switch default) + ) + $(UL + $(LI $(B on) or not specified: specified check is enabled.) + $(LI $(B off): specified check is disabled.) + )` + ), Option("checkaction=D|C|halt", "behavior on assert/boundscheck/finalswitch failure", `Sets behavior when an assert fails, and array boundscheck fails, or a final switch errors. $(UL - $(LI $(I D): Default behavior, which throws an unrecoverable $(D Error).) - $(LI $(I C): Calls the C runtime library assert failure function.) - $(LI $(I halt): Executes a halt instruction, terminating the program.) + $(LI $(B D): Default behavior, which throws an unrecoverable $(D Error).) + $(LI $(B C): Calls the C runtime library assert failure function.) + $(LI $(B halt): Executes a halt instruction, terminating the program.) )` ), Option("color", diff --git a/src/dmd/globals.d b/src/dmd/globals.d index 6e475694229e..fc71c0fb998a 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -175,6 +175,7 @@ struct Param CHECKENABLE useArrayBounds = CHECKENABLE._default; // when to generate code for array bounds checks CHECKENABLE useAssert = CHECKENABLE._default; // when to generate code for assert()'s CHECKENABLE useSwitchError = CHECKENABLE._default; // check for switches without a default + CHECKENABLE boundscheck = CHECKENABLE._default; // state of -boundscheck switch CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated diff --git a/src/dmd/globals.h b/src/dmd/globals.h index 336deae5481c..cad7cae5f36b 100644 --- a/src/dmd/globals.h +++ b/src/dmd/globals.h @@ -141,6 +141,7 @@ struct Param CHECKENABLE useArrayBounds; // when to generate code for array bounds checks CHECKENABLE useAssert; // when to generate code for assert()'s CHECKENABLE useSwitchError; // check for switches without a default + CHECKENABLE boundscheck; // state of -boundscheck switch CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 8e70f9728a11..efd2a05c51a9 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -335,6 +335,19 @@ private int tryMain(size_t argc, const(char)** argv) global.params.mscrtlib = vsopt.defaultRuntimeLibrary(global.params.is64bit); } } + + if (global.params.boundscheck != CHECKENABLE._default) + { + if (global.params.useArrayBounds == CHECKENABLE._default) + global.params.useArrayBounds = global.params.boundscheck; + } + + if (global.params.useUnitTests) + { + if (global.params.useAssert == CHECKENABLE._default) + global.params.useAssert = CHECKENABLE.on; + } + if (global.params.release) { if (global.params.useInvariants == CHECKENABLE._default) @@ -376,9 +389,6 @@ private int tryMain(size_t argc, const(char)** argv) global.params.useSwitchError = CHECKENABLE.on; } - if (global.params.useUnitTests) - global.params.useAssert = CHECKENABLE.on; - if (global.params.betterC) { global.params.checkAction = CHECKACTION.C; @@ -1499,6 +1509,42 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params.useDeprecated = Diagnostic.inform; else if (arg == "-c") // https://dlang.org/dmd.html#switch-c params.link = false; + else if (startsWith(p + 1, "check=")) // https://dlang.org/dmd.html#switch-check + { + /* Parse: + * -check=[assert|bounds|in|invariant|out|switch][=[on|off]] + */ + + // Check for legal option string; return true if so + static bool check(const(char)* p, string name, ref CHECKENABLE ce) + { + p += "-check=".length; + if (startsWith(p, name)) + { + p += name.length; + if (*p == 0 || + strcmp(p, "=on") == 0) + { + ce = CHECKENABLE.on; + return true; + } + else if (strcmp(p, "=off") == 0) + { + ce = CHECKENABLE.off; + return true; + } + } + return false; + } + + if (!(check(p, "assert", params.useAssert ) || + check(p, "bounds", params.useArrayBounds) || + check(p, "in", params.useIn ) || + check(p, "invariant", params.useInvariants ) || + check(p, "out", params.useOut ) || + check(p, "switch", params.useSwitchError))) + goto Lerror; + } else if (startsWith(p + 1, "checkaction=")) // https://dlang.org/dmd.html#switch-checkaction { /* Parse: @@ -1956,7 +2002,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params.betterC = true; else if (arg == "-noboundscheck") // https://dlang.org/dmd.html#switch-noboundscheck { - params.useArrayBounds = CHECKENABLE.off; + params.boundscheck = CHECKENABLE.off; } else if (startsWith(p + 1, "boundscheck")) // https://dlang.org/dmd.html#switch-boundscheck { @@ -1966,15 +2012,15 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param { if (strcmp(p + 13, "on") == 0) { - params.useArrayBounds = CHECKENABLE.on; + params.boundscheck = CHECKENABLE.on; } else if (strcmp(p + 13, "safeonly") == 0) { - params.useArrayBounds = CHECKENABLE.safeonly; + params.boundscheck = CHECKENABLE.safeonly; } else if (strcmp(p + 13, "off") == 0) { - params.useArrayBounds = CHECKENABLE.off; + params.boundscheck = CHECKENABLE.off; } else goto Lerror;