From 9c46927fad6535cf7e172f5af5e93d179cec1020 Mon Sep 17 00:00:00 2001 From: Andreas Rumpf Date: Sat, 4 Apr 2020 22:56:03 +0200 Subject: [PATCH] new feature: ability to turn specific warnings to errors --- changelog.md | 1 + compiler/commands.nim | 17 ++++++++++++----- compiler/msgs.nim | 7 ++++--- compiler/options.nim | 1 + compiler/pragmas.nim | 35 ++++++++++++++++------------------- compiler/semdata.nim | 4 ++++ compiler/wordrecg.nim | 5 +++-- doc/advopt.txt | 2 ++ 8 files changed, 43 insertions(+), 29 deletions(-) diff --git a/changelog.md b/changelog.md index 139bdc8326ed..77a757b1df4a 100644 --- a/changelog.md +++ b/changelog.md @@ -10,6 +10,7 @@ ## Compiler changes +- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`. ## Tool changes diff --git a/compiler/commands.nim b/compiler/commands.nim index babdd5871ae2..47dbcfa9064f 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -209,12 +209,18 @@ proc processSpecificNote*(arg: string, state: TSpecialWord, pass: TCmdLinePass, incl(conf.modifiedyNotes, n) case val of "on": - incl(conf.notes, n) - incl(conf.mainPackageNotes, n) + if state == wWarningAsError: + incl(conf.warningAsErrors, n) + else: + incl(conf.notes, n) + incl(conf.mainPackageNotes, n) of "off": - excl(conf.notes, n) - excl(conf.mainPackageNotes, n) - excl(conf.foreignPackageNotes, n) + if state == wWarningAsError: + excl(conf.warningAsErrors, n) + else: + excl(conf.notes, n) + excl(conf.mainPackageNotes, n) + excl(conf.foreignPackageNotes, n) proc processCompile(conf: ConfigRef; filename: string) = var found = findFile(conf, filename) @@ -528,6 +534,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo; if processOnOffSwitchOrList(conf, {optWarns}, arg, pass, info): listWarnings(conf) of "warning": processSpecificNote(arg, wWarning, pass, info, switch, conf) of "hint": processSpecificNote(arg, wHint, pass, info, switch, conf) + of "warningaserror": processSpecificNote(arg, wWarningAsError, pass, info, switch, conf) of "hints": if processOnOffSwitchOrList(conf, {optHints}, arg, pass, info): listHints(conf) of "threadanalysis": processOnOffSwitchG(conf, {optThreadAnalysis}, arg, pass, info) diff --git a/compiler/msgs.nim b/compiler/msgs.nim index 6d1ecb2b14e4..6fdd4931bb6a 100644 --- a/compiler/msgs.nim +++ b/compiler/msgs.nim @@ -354,7 +354,8 @@ proc handleError(conf: ConfigRef; msg: TMsgKind, eh: TErrorHandling, s: string) if msg >= fatalMin and msg <= fatalMax: if conf.cmd == cmdIdeTools: log(s) quit(conf, msg) - if msg >= errMin and msg <= errMax: + if msg >= errMin and msg <= errMax or + (msg in warnMin..warnMax and msg in conf.warningAsErrors): inc(conf.errorCounter) conf.exitcode = 1'i8 if conf.errorCounter >= conf.errorMax: @@ -412,7 +413,7 @@ proc rawMessage*(conf: ConfigRef; msg: TMsgKind, args: openArray[string]) = sev = Severity.Warning if not conf.hasWarn(msg): return writeContext(conf, unknownLineInfo) - title = WarningTitle + title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(conf.warnCounter) @@ -500,7 +501,7 @@ proc liMessage(conf: ConfigRef; info: TLineInfo, msg: TMsgKind, arg: string, sev = Severity.Warning ignoreMsg = not conf.hasWarn(msg) if not ignoreMsg: writeContext(conf, info) - title = WarningTitle + title = if msg in conf.warningAsErrors: ErrorTitle else: WarningTitle color = WarningColor kind = WarningsToStr[ord(msg) - ord(warnMin)] inc(conf.warnCounter) diff --git a/compiler/options.nim b/compiler/options.nim index 013c12b501a0..038e83eb0020 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -237,6 +237,7 @@ type cmdlineNotes*: TNoteKinds # notes that have been set/unset from cmdline foreignPackageNotes*: TNoteKinds notes*: TNoteKinds # notes after resolving all logic(defaults, verbosity)/cmdline/configs + warningAsErrors*: TNoteKinds mainPackageNotes*: TNoteKinds mainPackageId*: int errorCounter*: int diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index 4b0cf406ddc9..674673443489 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -330,31 +330,28 @@ proc processDynLib(c: PContext, n: PNode, sym: PSym) = sym.typ.callConv = ccCDecl proc processNote(c: PContext, n: PNode) = + template handleNote(toStrArray, msgMin, notes) = + let x = findStr(toStrArray, n[0][1].ident.s) + if x >= 0: + nk = TNoteKind(x + ord(msgMin)) + let x = c.semConstBoolExpr(c, n[1]) + n[1] = x + if x.kind == nkIntLit and x.intVal != 0: incl(notes, nk) + else: excl(notes, nk) + else: + invalidPragma(c, n) + if n.kind in nkPragmaCallKinds and n.len == 2 and n[0].kind == nkBracketExpr and n[0].len == 2 and n[0][1].kind == nkIdent and n[0][0].kind == nkIdent: var nk: TNoteKind case whichKeyword(n[0][0].ident) - of wHint: - var x = findStr(HintsToStr, n[0][1].ident.s) - if x >= 0: nk = TNoteKind(x + ord(hintMin)) - else: invalidPragma(c, n); return - of wWarning: - var x = findStr(WarningsToStr, n[0][1].ident.s) - if x >= 0: nk = TNoteKind(x + ord(warnMin)) - else: invalidPragma(c, n); return - else: - invalidPragma(c, n) - return - - let x = c.semConstBoolExpr(c, n[1]) - n[1] = x - if x.kind == nkIntLit and x.intVal != 0: incl(c.config.notes, nk) - else: excl(c.config.notes, nk) - # checkme: honor cmdlineNotes with: c.setNote(nk, x.kind == nkIntLit and x.intVal != 0) - else: - invalidPragma(c, n) + of wHint: handleNote(HintsToStr, hintMin, c.config.notes) + of wWarning: handleNote(WarningsToStr, warnMin, c.config.notes) + of wWarningAsError: handleNote(WarningsToStr, warnMin, c.config.warningAsErrors) + else: invalidPragma(c, n) + else: invalidPragma(c, n) proc pragmaToOptions(w: TSpecialWord): TOptions {.inline.} = case w diff --git a/compiler/semdata.nim b/compiler/semdata.nim index 7ec4c423f981..4d836d8f2e2c 100644 --- a/compiler/semdata.nim +++ b/compiler/semdata.nim @@ -21,6 +21,7 @@ type notes*: TNoteKinds features*: set[Feature] otherPragmas*: PNode # every pragma can be pushed + warningAsErrors*: TNoteKinds POptionEntry* = ref TOptionEntry PProcCon* = ref TProcCon @@ -213,6 +214,7 @@ proc newOptionEntry*(conf: ConfigRef): POptionEntry = result.defaultCC = ccDefault result.dynlib = nil result.notes = conf.notes + result.warningAsErrors = conf.warningAsErrors proc pushOptionEntry*(c: PContext): POptionEntry = new(result) @@ -221,12 +223,14 @@ proc pushOptionEntry*(c: PContext): POptionEntry = result.defaultCC = prev.defaultCC result.dynlib = prev.dynlib result.notes = c.config.notes + result.warningAsErrors = c.config.warningAsErrors result.features = c.features c.optionStack.add(result) proc popOptionEntry*(c: PContext) = c.config.options = c.optionStack[^1].options c.config.notes = c.optionStack[^1].notes + c.config.warningAsErrors = c.optionStack[^1].warningAsErrors c.features = c.optionStack[^1].features c.optionStack.setLen(c.optionStack.len - 1) diff --git a/compiler/wordrecg.nim b/compiler/wordrecg.nim index 55c38b76a83b..30a003dee30a 100644 --- a/compiler/wordrecg.nim +++ b/compiler/wordrecg.nim @@ -44,7 +44,7 @@ type wAlign, wNodecl, wPure, wSideEffect, wHeader, wNoSideEffect, wGcSafe, wNoreturn, wNosinks, wMerge, wLib, wDynlib, wCompilerProc, wCore, wProcVar, wBase, wUsed, - wFatal, wError, wWarning, wHint, wLine, wPush, wPop, wDefine, wUndef, + wFatal, wError, wWarning, wHint, wWarningAsError, wLine, wPush, wPop, wDefine, wUndef, wLineDir, wStackTrace, wLineTrace, wLink, wCompile, wLinksys, wDeprecated, wVarargs, wCallconv, wDebugger, wNimcall, wStdcall, wCdecl, wSafecall, wSyscall, wInline, wNoInline, @@ -131,7 +131,7 @@ const "requiresinit", "align", "nodecl", "pure", "sideeffect", "header", "nosideeffect", "gcsafe", "noreturn", "nosinks", "merge", "lib", "dynlib", "compilerproc", "core", "procvar", "base", "used", - "fatal", "error", "warning", "hint", "line", + "fatal", "error", "warning", "hint", "warningaserror", "line", "push", "pop", "define", "undef", "linedir", "stacktrace", "linetrace", "link", "compile", "linksys", "deprecated", "varargs", "callconv", "debugger", "nimcall", "stdcall", @@ -212,4 +212,5 @@ proc canonPragmaSpelling*(w: TSpecialWord): string = of wCodegenDecl: "codegenDecl" of wLiftLocals: "liftLocals" of wLocalPassc: "localPassc" + of wWarningAsError: "warningAsError" else: specialWords[w] diff --git a/doc/advopt.txt b/doc/advopt.txt index 157208a05591..bc5f9948ca95 100644 --- a/doc/advopt.txt +++ b/doc/advopt.txt @@ -38,6 +38,8 @@ Advanced options: --warning[X]:on|off turn specific warning X on|off --hints:on|off|list turn all hints on|off or list all available --hint[X]:on|off turn specific hint X on|off + --warningAsError[X]:on|off + turn specific warning X into an error on|off --styleCheck:off|hint|error produce hints or errors for Nim identifiers that do not adhere to Nim's official style guide