give hint for forward declarations with unknown raises effects (#24767)

refs #24766

Detect when we track a call to a forward declaration without explicit
`raises` effects, then when the `raises` check fails for the proc, give
a hint that this forward declaration was tracked as potentially raising
any exception.
This commit is contained in:
metagn
2025-03-11 16:24:45 +03:00
committed by GitHub
parent 850f327713
commit 82891e6850
3 changed files with 26 additions and 2 deletions

View File

@@ -110,6 +110,7 @@ type
hintSource = "Source", hintPerformance = "Performance", hintStackTrace = "StackTrace",
hintGCStats = "GCStats", hintGlobalVar = "GlobalVar", hintExpandMacro = "ExpandMacro",
hintUser = "User", hintUserRaw = "UserRaw", hintExtendedContext = "ExtendedContext",
hintUnknownRaises = "UnknownRaises",
hintMsgOrigin = "MsgOrigin", # since 1.3.5
hintDeclaredLoc = "DeclaredLoc", # since 1.5.1
@@ -236,6 +237,7 @@ const
hintUser: "$1",
hintUserRaw: "$1",
hintExtendedContext: "$1",
hintUnknownRaises: "$1 is a forward declaration without explicit .raises, assuming it can raise anything",
hintMsgOrigin: "$1",
hintDeclaredLoc: "$1"
]

View File

@@ -84,6 +84,7 @@ type
gcUnsafe, isRecursive, isTopLevel, hasSideEffect, inEnforcedGcSafe: bool
isInnerProc: bool
inEnforcedNoSideEffects: bool
unknownRaises: seq[(PSym, TLineInfo)]
currOptions: TOptions
optionsStack: seq[(TOptions, TNoteKinds)]
config: ConfigRef
@@ -639,6 +640,8 @@ proc importedFromC(n: PNode): bool =
proc propagateEffects(tracked: PEffects, n: PNode, s: PSym) =
let pragma = s.ast[pragmasPos]
let spec = effectSpec(pragma, wRaises)
if spec.isNil and sfForward in s.flags:
tracked.unknownRaises.add (s, n.info)
mergeRaises(tracked, spec, n)
let tagSpec = effectSpec(pragma, wTags)
@@ -1506,7 +1509,7 @@ proc subtypeRelation(g: ModuleGraph; spec, real: PNode): bool =
proc checkRaisesSpec(g: ModuleGraph; emitWarnings: bool; spec, real: PNode, msg: string, hints: bool;
effectPredicate: proc (g: ModuleGraph; a, b: PNode): bool {.nimcall.};
hintsArg: PNode = nil; isForbids: bool = false) =
hintsArg: PNode = nil; isForbids: bool = false; unknownRaises: seq[(PSym, TLineInfo)] = @[]) =
# check that any real exception is listed in 'spec'; mark those as used;
# report any unused exception
var used = initIntSet()
@@ -1523,6 +1526,8 @@ proc checkRaisesSpec(g: ModuleGraph; emitWarnings: bool; spec, real: PNode, msg:
pushInfoContext(g.config, spec.info)
var rr = if r.kind == nkRaiseStmt: r[0] else: r
while rr.kind in {nkStmtList, nkStmtListExpr} and rr.len > 0: rr = rr.lastSon
for (s, info) in unknownRaises.items:
message(g.config, info, hintUnknownRaises, s.name.s)
message(g.config, r.info, if emitWarnings: warnEffect else: errGenerated,
renderTree(rr) & " " & msg & typeToString(r.typ))
popInfoContext(g.config)
@@ -1680,7 +1685,7 @@ proc trackProc*(c: PContext; s: PSym, body: PNode) =
if not isNil(raisesSpec):
let useWarning = s.name.s == "=destroy"
checkRaisesSpec(g, useWarning, raisesSpec, t.exc, "can raise an unlisted exception: ",
hints=on, subtypeRelation, hintsArg=s.ast[0])
hints=on, subtypeRelation, hintsArg=s.ast[0], unknownRaises = t.unknownRaises)
# after the check, use the formal spec:
effects[exceptionEffects] = raisesSpec
else:

View File

@@ -0,0 +1,17 @@
discard """
action: reject
nimout: '''
tforwardraises.nim(15, 14) Hint: n is a forward declaration without explicit .raises, assuming it can raise anything [UnknownRaises]
tforwardraises.nim(14, 26) template/generic instantiation from here
tforwardraises.nim(15, 14) Error: n(0) can raise an unlisted exception: Exception
'''
"""
# issue #24766
proc n(_: int)
proc s(_: int) {.raises: [CatchableError].} =
if false: n(0)
proc n(_: int) = s(0)