You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In some situation, in particular in a for loop, the compiler may ignore the {.noInit.} pragma.
This is problematic for non-copyable non-movable type, for example a shared atomic counter.
This can be caught at compile-time by making =sink an error:
import std/atomics
typeAtomicCounter*=object
count: Atomic[int]
proc`=`*(dst: varAtomicCounter, src: AtomicCounter) {.error: "An atomic counter cannot be copied.".}
proc`=sink`*(dst: varAtomicCounter, src: AtomicCounter) {.error: "An atomic counter cannot be moved.".}
proc`=destroy`*(sb: varAtomicCounter) {.inline.}=discardprocinitialize*(ac: varAtomicCounter) {.inline.} =
ac.count.store(0, moRelaxed)
procinc*(p: ptrAtomicCounter) =discard p.count.fetchAdd(1, moRelaxed)
var currentCounter: ptrAtomicCountertemplatescopedCounter*(body: untyped): untyped=bind currentCounter
block:
let suspended = currentCounter
var a {.noInit.}: AtomicCounter
a.initialize()
currentCounter =addr(a)
body
currentCounter = suspended
procfoo() =
scopedCounter:
echo"Counting ..."procbar() =for i in0..2:
scopedCounter:
echo"Counting ..."foo()
bar() # Does not compile, Nim tries to insert `=sink` inside a for loop
Error: '=sink' is not available for type <AtomicCounter>; routine: bar
In the C codegen we can see the eqsink
import std/atomics
typeAtomicCounter*=object
count: Atomic[int]
proc`=`*(dst: varAtomicCounter, src: AtomicCounter) {.error: "An atomic counter cannot be copied.".}
whenfalse:
proc`=sink`*(dst: varAtomicCounter, src: AtomicCounter) {.error: "An atomic counter cannot be moved.".}
else:
proc`=sink`*(dst: varAtomicCounter, src: AtomicCounter) {.inline.} =
system.`=sink`(dst.count, src.count)
proc`=destroy`*(sb: varAtomicCounter) {.inline.}=discardprocinitialize*(ac: varAtomicCounter) {.inline.} =
ac.count.store(0, moRelaxed)
procinc*(p: ptrAtomicCounter) =discard p.count.fetchAdd(1, moRelaxed)
var currentCounter: ptrAtomicCountertemplatescopedCounter*(body: untyped): untyped=bind currentCounter
block:
let suspended = currentCounter
var a {.noInit.}: AtomicCounter
a.initialize()
currentCounter =addr(a)
body
currentCounter = suspended
procfoo() =
scopedCounter:
echo"Counting ..."procbar() =for i in0..2:
scopedCounter:
echo"Counting ..."foo()
bar() # eqsink in C codegen
In some situation, in particular in a for loop, the compiler may ignore the
{.noInit.}
pragma.This is problematic for non-copyable non-movable type, for example a shared atomic counter.
This can be caught at compile-time by making
=sink
an error:In the C codegen we can see the eqsink
foo function
bar function
More importantly, this will avoid bad codegen in C++ that only happen for
bar
but not forfoo
This may be related to my C++ codegen woes in #13093 which I have no workaround for at the moment.
The text was updated successfully, but these errors were encountered: