I'm (still) trying to put the "missing bits" of atomic methods together into a cross-platform/cross-backend module. I've now got to the point that the VCC C version compiles and run (I only test with one thread, so idk if it really gives the expected atomic behaviour yet). When I try to build and run the VCC C++ version, I have an issue with C++ references. It seems "(t: var T)" is translated to a pointer in C, and a reference in C++. And this doesn't seem to play well with volatiles.
How to I make this work in C++?
type
VolatilePtr*[T] = distinct ptr T
proc toVolatilePtr*[T](t: var T): VolatilePtr[T] =
cast[VolatilePtr[T]](addr t)
var my_vbyte {.volatile.}: byte = 0'u8
var my_vbyte_ptr: VolatilePtr[byte] = toVolatilePtr[byte](my_vbyte)
echo(cast[pointer](my_vbyte_ptr) == nil)
When trying to use this, I get this kind of error:
error C2664: 'NU8 *toVolatilePtr_WWtk4tL3VWMmQk62xcO0Ew(NU8 &)': cannot convert argument 1 from 'volatile NU8' to 'NU8 &'
EDIT: I don't really care if "var" is implemented as pointer or reference; what I need is simply for toVolatilePtr(X) to work as expected. I tried different variations of toVolatilePtr(), but so far this was the only one that compiled and worked in C.
@Araq Here is a minimal example. This is compiled with "vcc". It compiles to C, but not to C++.
type
VolatilePtr*[T] = distinct ptr T
proc toVolatilePtr*[T](t: var T): VolatilePtr[T] =
cast[VolatilePtr[T]](addr t)
# Pretend we're actually checking it's volatile, which is apparently not possible to do.
var my_vbyte {.volatile.}: byte = 42'u8
var my_vbyte_ptr = toVolatilePtr[byte](my_vbyte)
type
AtomType* = SomeNumber|pointer|ptr|char|bool
when defined(cpp):
proc interlockedOr8(p: pointer; value: int8): int8
{.importcpp: "_InterlockedOr8(static_cast<char volatile *>(#), #)", header: "<intrin.h>".}
else:
proc interlockedOr8(p: pointer; value: int8): int8
{.importc: "_InterlockedOr8", header: "<intrin.h>".}
proc atomicLoadFull*[T: AtomType](p: VolatilePtr[T]): T {.inline.} =
let pp = cast[pointer](p)
when sizeof(T) == 1:
cast[T](interlockedOr8(pp, 0'i8))
else: # TODO, sizeof(T) == (2|4|8)
static: assert(false, "invalid parameter size: " & $sizeof(T))
assert(atomicLoadFull(my_vbyte_ptr) == 42'u8)
src\nimcache\abc_volatile2.cpp(306): error C2664: 'NU8 *toVolatilePtr_EP8VL8ilqAQ1Zz9bJAA4rwQ(NU8 &)':
cannot convert argument 1 from 'volatile NU8' to 'NU8 &'
src\nimcache\abc_volatile2.cpp(306): note: Conversion loses qualifiers
EDIT: My "rational" for this design is:
I've had the issue that the error doesn't always come, if I don't delete the nimcache, but I think it's caused by VS Code compiling automatically as well, using a different configuration.