Skip to content

Commit f01ffbf

Browse files
ringaboutarnetheduck
authored andcommitted
fix #19580; add warning for bare except: clause (#21099)
* fix #19580; add warning for bare except: clause * fixes some easy ones * Update doc/manual.md * fixes docs * Update changelog.md * addition * Apply suggestions from code review Co-authored-by: Jacek Sieka <arnetheduck@gmail.com> * Update doc/tut2.md Co-authored-by: Jacek Sieka <arnetheduck@gmail.com> (cherry picked from commit 91ce8c3)
1 parent 0da50ce commit f01ffbf

File tree

14 files changed

+75
-25
lines changed

14 files changed

+75
-25
lines changed

changelog.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,33 @@
2424
This warning will become an error in future versions! Use a `cast` operation
2525
like `cast[cstring](x)` instead.
2626

27+
- `logging` will default to flushing all log level messages. To get the legacy behaviour of only flushing Error and Fatal messages, use `-d:nimV1LogFlushBehavior`.
28+
29+
- Object fields now support default values, see https://nim-lang.github.io/Nim/manual.html#types-default-values-for-object-fields for details.
30+
31+
- Redefining templates with the same signature was previously
32+
allowed to support certain macro code. To do this explicitly, the
33+
`{.redefine.}` pragma has been added. Note that this is only for templates.
34+
Implicit redefinition of templates is now deprecated and will give an error in the future.
35+
36+
- Using an unnamed break in a block is deprecated. This warning will become an error in future versions! Use a named block with a named break instead.
37+
38+
- Several Standard libraries are moved to nimble packages, use `nimble` to install them:
39+
- `std/punycode` => `punycode`
40+
- `std/asyncftpclient` => `asyncftpclient`
41+
- `std/smtp` => `smtp`
42+
- `std/db_common` => `db_connector/db_common`
43+
- `std/db_sqlite` => `db_connector/db_sqlite`
44+
- `std/db_mysql` => `db_connector/db_mysql`
45+
- `std/db_postgres` => `db_connector/db_postgres`
46+
- `std/db_odbc` => `db_connector/db_odbc`
47+
48+
- Previously, calls like `foo(a, b): ...` or `foo(a, b) do: ...` where the final argument of
49+
`foo` had type `proc ()` were assumed by the compiler to mean `foo(a, b, proc () = ...)`.
50+
This behavior is now deprecated. Use `foo(a, b) do (): ...` or `foo(a, b, proc () = ...)` instead.
51+
52+
- If no exception or any exception deriving from Exception but not Defect or CatchableError given in except, a `warnBareExcept` warning will be triggered.
53+
2754
## Standard library additions and changes
2855

2956
- `macros.parseExpr` and `macros.parseStmt` now accept an optional

compiler/condsyms.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,3 +140,4 @@ proc initDefines*(symbols: StringTableRef) =
140140
defineSymbol("nimHasEffectsOf")
141141

142142
defineSymbol("nimHasEnforceNoRaises")
143+
defineSymbol("nimHasWarnBareExcept")

compiler/docgen.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,7 +1536,7 @@ proc commandJson*(cache: IdentCache, conf: ConfigRef) =
15361536
let filename = getOutFile(conf, RelativeFile conf.projectName, JsonExt)
15371537
try:
15381538
writeFile(filename, content)
1539-
except:
1539+
except IOError:
15401540
rawMessage(conf, errCannotOpenFile, filename.string)
15411541

15421542
proc commandTags*(cache: IdentCache, conf: ConfigRef) =
@@ -1559,7 +1559,7 @@ proc commandTags*(cache: IdentCache, conf: ConfigRef) =
15591559
let filename = getOutFile(conf, RelativeFile conf.projectName, TagsExt)
15601560
try:
15611561
writeFile(filename, content)
1562-
except:
1562+
except IOError:
15631563
rawMessage(conf, errCannotOpenFile, filename.string)
15641564

15651565
proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"") =
@@ -1580,5 +1580,5 @@ proc commandBuildIndex*(conf: ConfigRef, dir: string, outFile = RelativeFile"")
15801580

15811581
try:
15821582
writeFile(filename, code)
1583-
except:
1583+
except IOError:
15841584
rawMessage(conf, errCannotOpenFile, filename.string)

compiler/extccomp.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,7 @@ proc ccHasSaneOverflow*(conf: ConfigRef): bool =
517517
var exe = getConfigVar(conf, conf.cCompiler, ".exe")
518518
if exe.len == 0: exe = CC[conf.cCompiler].compilerExe
519519
# NOTE: should we need the full version, use -dumpfullversion
520-
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except: ("", 1)
520+
let (s, exitCode) = try: execCmdEx(exe & " -dumpversion") except IOError, OSError, ValueError: ("", 1)
521521
if exitCode == 0:
522522
var major: int
523523
discard parseInt(s, major)
@@ -1006,7 +1006,7 @@ proc changeDetectedViaJsonBuildInstructions*(conf: ConfigRef; jsonFile: Absolute
10061006
proc runJsonBuildInstructions*(conf: ConfigRef; jsonFile: AbsoluteFile) =
10071007
var bcache: BuildCache
10081008
try: bcache.fromJson(jsonFile.string.parseFile)
1009-
except:
1009+
except ValueError, KeyError, JsonKindError:
10101010
let e = getCurrentException()
10111011
conf.quitOrRaise "\ncaught exception:\n$#\nstacktrace:\n$#error evaluating JSON file: $#" %
10121012
[e.msg, e.getStackTrace(), jsonFile.string]

compiler/lineinfos.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ type
7878
warnCstringConv = "CStringConv",
7979
warnPtrToCstringConv = "PtrToCstringConv",
8080
warnEffect = "Effect",
81+
warnBareExcept = "BareExcept",
8182
warnUser = "User",
8283
# hints
8384
hintSuccess = "Success", hintSuccessX = "SuccessX",
@@ -169,6 +170,7 @@ const
169170
warnCstringConv: "$1",
170171
warnPtrToCstringConv: "unsafe conversion to 'cstring' from '$1'; this will become a compile time error in the future",
171172
warnEffect: "$1",
173+
warnBareExcept: "$1",
172174
warnUser: "$1",
173175
hintSuccess: "operation successful: $#",
174176
# keep in sync with `testament.isSuccess`

compiler/nim.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ define:useStdoutAsStdmsg
3131
experimental:strictEffects
3232
warningAsError:Effect:on
3333
@end
34+
35+
@if nimHasWarnBareExcept:
36+
warningAserror[BareExcept]:on
37+
@end

compiler/semstmts.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
191191
isImported = true
192192
elif not isException(typ):
193193
localError(c.config, typeNode.info, errExprCannotBeRaised)
194+
elif not isDefectOrCatchableError(typ):
195+
message(c.config, a.info, warnBareExcept, "catch a more precise Exception deriving from CatchableError or Defect.")
194196

195197
if containsOrIncl(check, typ.id):
196198
localError(c.config, typeNode.info, errExceptionAlreadyHandled)
@@ -230,7 +232,8 @@ proc semTry(c: PContext, n: PNode; flags: TExprFlags): PNode =
230232
elif a.len == 1:
231233
# count number of ``except: body`` blocks
232234
inc catchAllExcepts
233-
235+
message(c.config, a.info, warnBareExcept,
236+
"The bare except clause is deprecated; use `except CatchableError:` instead")
234237
else:
235238
# support ``except KeyError, ValueError, ... : body``
236239
if catchAllExcepts > 0:

compiler/types.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,18 @@ proc isDefectException*(t: PType): bool =
16661666
t = skipTypes(t[0], abstractPtrs)
16671667
return false
16681668

1669+
proc isDefectOrCatchableError*(t: PType): bool =
1670+
var t = t.skipTypes(abstractPtrs)
1671+
while t.kind == tyObject:
1672+
if t.sym != nil and t.sym.owner != nil and
1673+
sfSystemModule in t.sym.owner.flags and
1674+
(t.sym.name.s == "Defect" or
1675+
t.sym.name.s == "CatchableError"):
1676+
return true
1677+
if t[0] == nil: break
1678+
t = skipTypes(t[0], abstractPtrs)
1679+
return false
1680+
16691681
proc isSinkTypeForParam*(t: PType): bool =
16701682
# a parameter like 'seq[owned T]' must not be used only once, but its
16711683
# elements must, so we detect this case here:

doc/manual.rst

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4506,8 +4506,8 @@ Example:
45064506
echo "overflow!"
45074507
except ValueError, IOError:
45084508
echo "catch multiple exceptions!"
4509-
except:
4510-
echo "Unknown exception!"
4509+
except CatchableError:
4510+
echo "Catchable exception!"
45114511
finally:
45124512
close(f)
45134513
@@ -4518,9 +4518,6 @@ listed in an `except` clause, the corresponding statements are executed.
45184518
The statements following the `except` clauses are called
45194519
`exception handlers`:idx:.
45204520

4521-
The empty `except`:idx: clause is executed if there is an exception that is
4522-
not listed otherwise. It is similar to an `else` clause in `if` statements.
4523-
45244521
If there is a `finally`:idx: clause, it is always executed after the
45254522
exception handlers.
45264523

@@ -4538,19 +4535,21 @@ Try can also be used as an expression; the type of the `try` branch then
45384535
needs to fit the types of `except` branches, but the type of the `finally`
45394536
branch always has to be `void`:
45404537

4541-
.. code-block:: nim
4538+
```nim test
45424539
from std/strutils import parseInt
45434540
45444541
let x = try: parseInt("133a")
4545-
except: -1
4542+
except ValueError: -1
45464543
finally: echo "hi"
45474544
45484545
45494546
To prevent confusing code there is a parsing limitation; if the `try`
45504547
follows a `(` it has to be written as a one liner:
45514548
4552-
.. code-block:: nim
4553-
let x = (try: parseInt("133a") except: -1)
4549+
```nim test
4550+
from std/strutils import parseInt
4551+
let x = (try: parseInt("133a") except ValueError: -1)
4552+
```
45544553

45554554

45564555
Except clauses
@@ -4594,7 +4593,7 @@ error message from `e`, and for such situations, it is enough to use
45944593
.. code-block:: nim
45954594
try:
45964595
# ...
4597-
except:
4596+
except CatchableError:
45984597
echo getCurrentExceptionMsg()
45994598
46004599
Custom exceptions
@@ -4784,7 +4783,7 @@ An empty `raises` list (`raises: []`) means that no exception may be raised:
47844783
try:
47854784
unsafeCall()
47864785
result = true
4787-
except:
4786+
except CatchableError:
47884787
result = false
47894788
47904789

doc/tut2.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ The `try` statement handles exceptions:
395395
echo "could not convert string to integer"
396396
except IOError:
397397
echo "IO error!"
398-
except:
398+
except CatchableError:
399399
echo "Unknown exception!"
400400
# reraise the unknown exception:
401401
raise
@@ -426,7 +426,7 @@ module. Example:
426426
.. code-block:: nim
427427
try:
428428
doSomethingHere()
429-
except:
429+
except CatchableError:
430430
let
431431
e = getCurrentException()
432432
msg = getCurrentExceptionMsg()

lib/packages/docutils/rst.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,7 @@ proc getFootnoteType(label: PRstNode): (FootnoteType, int) =
15131513
elif label.len == 1 and label.sons[0].kind == rnLeaf:
15141514
try:
15151515
result = (fnManualNumber, parseInt(label.sons[0].text))
1516-
except:
1516+
except ValueError:
15171517
result = (fnCitation, -1)
15181518
else:
15191519
result = (fnCitation, -1)
@@ -2420,13 +2420,13 @@ proc parseEnumList(p: var RstParser): PRstNode =
24202420
let enumerator = p.tok[p.idx + 1 + wildIndex[w]].symbol
24212421
# check that it's in sequence: enumerator == next(prevEnum)
24222422
if "n" in wildcards[w]: # arabic numeral
2423-
let prevEnumI = try: parseInt(prevEnum) except: 1
2423+
let prevEnumI = try: parseInt(prevEnum) except ValueError: 1
24242424
if enumerator in autoEnums:
24252425
if prevAE != "" and enumerator != prevAE:
24262426
break
24272427
prevAE = enumerator
24282428
curEnum = prevEnumI + 1
2429-
else: curEnum = (try: parseInt(enumerator) except: 1)
2429+
else: curEnum = (try: parseInt(enumerator) except ValueError: 1)
24302430
if curEnum - prevEnumI != 1:
24312431
break
24322432
prevEnum = enumerator

lib/pure/htmlparser.nim

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,10 +391,10 @@ proc entityToRune*(entity: string): Rune =
391391
case entity[1]
392392
of '0'..'9':
393393
try: runeValue = parseInt(entity[1..^1])
394-
except: discard
394+
except ValueError: discard
395395
of 'x', 'X': # not case sensitive here
396396
try: runeValue = parseHexInt(entity[2..^1])
397-
except: discard
397+
except ValueError: discard
398398
else: discard # other entities are not defined with prefix `#`
399399
if runeValue notin 0..0x10FFFF: runeValue = 0 # only return legal values
400400
return Rune(runeValue)

lib/system/assertions.nim

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ template doAssertRaises*(exception: typedesc, code: untyped) =
9393
const begin = "expected raising '" & astToStr(exception) & "', instead"
9494
const msgEnd = " by: " & astToStr(code)
9595
template raisedForeign = raiseAssert(begin & " raised foreign exception" & msgEnd)
96+
{.warning[BareExcept]:off.}
9697
when Exception is exception:
9798
try:
9899
if true:
@@ -111,5 +112,6 @@ template doAssertRaises*(exception: typedesc, code: untyped) =
111112
mixin `$` # alternatively, we could define $cstring in this module
112113
raiseAssert(begin & " raised '" & $e.name & "'" & msgEnd)
113114
except: raisedForeign()
115+
{.warning[BareExcept]:on.}
114116
if wrong:
115117
raiseAssert(begin & " nothing was raised" & msgEnd)

tests/nimdoc/trunnableexamples.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ when true: # issue #12746
6565
runnableExamples:
6666
try:
6767
discard
68-
except:
68+
except CatchableError:
6969
# just the general except will work
7070
discard
7171

0 commit comments

Comments
 (0)