Skip to content

Commit

Permalink
new feature: ability to turn specific warnings to errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Araq committed Apr 4, 2020
1 parent ed44e52 commit 9c46927
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 29 deletions.
1 change: 1 addition & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

## Compiler changes

- Specific warnings can now be turned into errors via `--warningAsError[X]:on|off`.

## Tool changes

17 changes: 12 additions & 5 deletions compiler/commands.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
7 changes: 4 additions & 3 deletions compiler/msgs.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions compiler/options.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 16 additions & 19 deletions compiler/pragmas.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions compiler/semdata.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand Down
5 changes: 3 additions & 2 deletions compiler/wordrecg.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -212,4 +212,5 @@ proc canonPragmaSpelling*(w: TSpecialWord): string =
of wCodegenDecl: "codegenDecl"
of wLiftLocals: "liftLocals"
of wLocalPassc: "localPassc"
of wWarningAsError: "warningAsError"
else: specialWords[w]
2 changes: 2 additions & 0 deletions doc/advopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

2 comments on commit 9c46927

@timotheecour
Copy link
Member

@timotheecour timotheecour commented on 9c46927 Apr 4, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good feature.

  • I just verified, it also works with this syntax: --warningAsError:UnusedImport:on (to avoid having to quote in shell)

  • @Araq ideally this should work too but currently doesn't:
    --warningAsError:on
    --warningAsError:off
    --warningAsError
    (with obvious semantics)

@Araq
Copy link
Member Author

@Araq Araq commented on 9c46927 Apr 5, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

```--warningAsError`` is not future proof, whenever we introduce a new warning, it breaks somebody's build.

Please sign in to comment.