fixes another effect inference bug [backport:1.6] (#19100)

* fixes another effect inference bug [backport:1.6]
This commit is contained in:
Andreas Rumpf 2021-11-07 16:38:02 +01:00 • committed by GitHub
commit fce89cb60a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 85 additions and 11 deletions

View file

@ -851,6 +851,9 @@ proc trackCall(tracked: PEffects; n: PNode) =
elif isIndirectCall(tracked, a): elif isIndirectCall(tracked, a):
assumeTheWorst(tracked, n, op) assumeTheWorst(tracked, n, op)
gcsafeAndSideeffectCheck() gcsafeAndSideeffectCheck()
else:
if strictEffects in tracked.c.features and a.kind == nkSym and a.sym.kind in routineKinds:
propagateEffects(tracked, n, a.sym)
else: else:
mergeRaises(tracked, effectList[exceptionEffects], n) mergeRaises(tracked, effectList[exceptionEffects], n)
mergeTags(tracked, effectList[tagEffects], n) mergeTags(tracked, effectList[tagEffects], n)

View file

@ -733,7 +733,7 @@ when defined(windows) or defined(nimdoc):
proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn}, proc acceptAddr*(socket: AsyncFD, flags = {SocketFlag.SafeDisconn},
inheritable = defined(nimInheritHandles)): inheritable = defined(nimInheritHandles)):
owned(Future[tuple[address: string, client: AsyncFD]]) = owned(Future[tuple[address: string, client: AsyncFD]]) {.gcsafe.} =
## Accepts a new connection. Returns a future containing the client socket ## Accepts a new connection. Returns a future containing the client socket
## corresponding to that connection and the remote address of the client. ## corresponding to that connection and the remote address of the client.
## The future will complete when the connection is successfully accepted. ## The future will complete when the connection is successfully accepted.
@ -800,7 +800,7 @@ when defined(windows) or defined(nimdoc):
var ol = newCustom() var ol = newCustom()
ol.data = CompletionData(fd: socket, cb: ol.data = CompletionData(fd: socket, cb:
proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) = proc (fd: AsyncFD, bytesCount: DWORD, errcode: OSErrorCode) {.gcsafe.} =
if not retFuture.finished: if not retFuture.finished:
if errcode == OSErrorCode(-1): if errcode == OSErrorCode(-1):
completeAccept() completeAccept()

View file

@ -437,7 +437,7 @@ macro `%*`*(x: untyped): untyped =
## `%` for every element. ## `%` for every element.
result = toJsonImpl(x) result = toJsonImpl(x)
proc `==`*(a, b: JsonNode): bool = proc `==`*(a, b: JsonNode): bool {.noSideEffect.} =
## Check two nodes for equality ## Check two nodes for equality
if a.isNil: if a.isNil:
if b.isNil: return true if b.isNil: return true
@ -464,12 +464,16 @@ proc `==`*(a, b: JsonNode): bool =
if a.fields.len != b.fields.len: return false if a.fields.len != b.fields.len: return false
for key, val in a.fields: for key, val in a.fields:
if not b.fields.hasKey(key): return false if not b.fields.hasKey(key): return false
when defined(nimHasEffectsOf):
{.noSideEffect.}:
if b.fields[key] != val: return false
else:
if b.fields[key] != val: return false if b.fields[key] != val: return false
result = true result = true
proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.} proc hash*(n: OrderedTable[string, JsonNode]): Hash {.noSideEffect.}
proc hash*(n: JsonNode): Hash = proc hash*(n: JsonNode): Hash {.noSideEffect.} =
## Compute the hash for a JSON node ## Compute the hash for a JSON node
case n.kind case n.kind
of JArray: of JArray:

View file

@ -354,7 +354,7 @@ var onUnhandledException*: (proc (errorMsg: string) {.
## The default is to write a stacktrace to `stderr` and then call `quit(1)`. ## The default is to write a stacktrace to `stderr` and then call `quit(1)`.
## Unstable API. ## Unstable API.
proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} = proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy, gcsafe.} =
when hasSomeStackTrace: when hasSomeStackTrace:
var buf = newStringOfCap(2000) var buf = newStringOfCap(2000)
if e.trace.len == 0: if e.trace.len == 0:
@ -362,6 +362,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
else: else:
var trace = $e.trace var trace = $e.trace
add(buf, trace) add(buf, trace)
{.gcsafe.}:
`=destroy`(trace) `=destroy`(trace)
add(buf, "Error: unhandled exception: ") add(buf, "Error: unhandled exception: ")
add(buf, e.msg) add(buf, e.msg)
@ -373,6 +374,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
onUnhandledException(buf) onUnhandledException(buf)
else: else:
showErrorMessage2(buf) showErrorMessage2(buf)
{.gcsafe.}:
`=destroy`(buf) `=destroy`(buf)
else: else:
# ugly, but avoids heap allocations :-) # ugly, but avoids heap allocations :-)
@ -387,6 +389,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
if e.trace.len != 0: if e.trace.len != 0:
var trace = $e.trace var trace = $e.trace
add(buf, trace) add(buf, trace)
{.gcsafe.}:
`=destroy`(trace) `=destroy`(trace)
add(buf, "Error: unhandled exception: ") add(buf, "Error: unhandled exception: ")
add(buf, e.msg) add(buf, e.msg)
@ -398,7 +401,7 @@ proc reportUnhandledErrorAux(e: ref Exception) {.nodestroy.} =
else: else:
showErrorMessage(buf.addr, L) showErrorMessage(buf.addr, L)
proc reportUnhandledError(e: ref Exception) {.nodestroy.} = proc reportUnhandledError(e: ref Exception) {.nodestroy, gcsafe.} =
if unhandledExceptionHook != nil: if unhandledExceptionHook != nil:
unhandledExceptionHook(e) unhandledExceptionHook(e)
when hostOS != "any": when hostOS != "any":

View file

@ -73,7 +73,7 @@ proc prepareSeqAdd(len: int; p: pointer; addlen, elemSize, elemAlign: int): poin
q.cap = newCap q.cap = newCap
result = q result = q
proc shrink*[T](x: var seq[T]; newLen: Natural) = proc shrink*[T](x: var seq[T]; newLen: Natural) {.tags: [].} =
when nimvm: when nimvm:
setLen(x, newLen) setLen(x, newLen)
else: else:

View file

@ -0,0 +1,63 @@
discard """
cmd: "nim check --hints:off $file"
nimout: '''tnestedprocs.nim(27, 8) Error: 'inner' can have side effects
> tnestedprocs.nim(29, 13) Hint: 'inner' calls `.sideEffect` 'outer2'
>> tnestedprocs.nim(26, 6) Hint: 'outer2' called by 'inner'
tnestedprocs.nim(45, 8) Error: 'inner' can have side effects
> tnestedprocs.nim(47, 13) Hint: 'inner' calls `.sideEffect` 'outer6'
>> tnestedprocs.nim(44, 6) Hint: 'outer6' called by 'inner'
tnestedprocs.nim(58, 41) Error: type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'
Pragma mismatch: got '{..}', but expected '{.noSideEffect.}'.
'''
errormsg: "type mismatch: got <proc ()> but expected 'proc (){.closure, noSideEffect.}'"
"""
{.experimental: "strictEffects".}
proc outer {.noSideEffect.} =
proc inner(p: int) =
if p == 0:
outer()
inner(4)
outer()
proc outer2 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
outer2()
inner(4)
outer2()
proc outer3(p: int) {.noSideEffect.} =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
p.outer3()
inner(4)
outer3(5)
proc outer6 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
outer6()
inner(4)
echo "bad"
outer6()
proc outer4 =
proc inner(p: int) {.noSideEffect.} =
if p == 0:
let x: proc () {.noSideEffect.} = outer4
x()
inner(4)
outer4()

View file

@ -1,5 +1,6 @@
discard """ discard """
output: '''34''' output: '''34'''
joinable: false
""" """
{.compile("cfunction.c", "-DNUMBER_HERE=34").} {.compile("cfunction.c", "-DNUMBER_HERE=34").}