move now uses its declaration for overridden =wasMoved

This commit is contained in:
ringabout
2026-05-11 19:05:05 +08:00
parent f0c60b06e5
commit 1bb7817f65
4 changed files with 47 additions and 1 deletions

View File

@@ -2842,6 +2842,9 @@ proc genMove(p: BProc; n: PNode; d: var TLoc) =
var op = getAttachedOp(p.module.g.graph, n.typ, attachedWasMoved)
if op == nil:
resetLoc(p, a)
elif sfOverridden in op.flags:
internalError(p.config, n.info,
"overridden =wasMoved should be emitted by instantiated move")
else:
var b = initLocExpr(p, newSymNode(op))
case skipTypes(a.t, abstractVar+{tyStatic}).kind

View File

@@ -853,6 +853,12 @@ proc compactVoidArgs(n: PNode): PNode =
if n[i] != nil:
result.add n[i]
proc hasOverriddenWasMoved(c: PContext; call: PNode): bool =
if call.len != 2 or call[1].typ == nil: return false
let typ = call[1].typ.skipTypes({tyAlias, tyVar, tySink})
let op = getAttachedOp(c.graph, typ, attachedWasMoved)
result = op != nil and sfOverridden in op.flags
proc semResolvedCall(c: PContext, x: var TCandidate,
n: PNode, flags: TExprFlags;
expectedType: PType = nil): PNode =
@@ -880,6 +886,13 @@ proc semResolvedCall(c: PContext, x: var TCandidate,
else:
c.inheritBindings(x, expectedType)
finalCallee = generateInstance(c, x.calleeSym, x.bindings, n.info)
if x.calleeSym.magic == mMove and hasOverriddenWasMoved(c, x.call):
# Let system.move[T]'s instantiated body perform the overridable
# =wasMoved call. The mMove codegen path stays the compact default
# implementation for non-overridden hooks.
ensureMutable finalCallee
finalCallee.magic = mNone
setOwner(finalCallee, c.module)
else:
# For macros and templates, the resolved generic params
# are added as normal params.

View File

@@ -166,7 +166,7 @@ proc wasMoved*[T](obj: var T) {.magic: "WasMoved", noSideEffect.}
## it was "moved" and to signify its destructor should do nothing and
## ideally be optimized away.
proc move*[T](x: var T): T {.magic: "Move", noSideEffect.} =
proc move*[T](x: var T): T {.magic: "Move", noSideEffect, nodestroy.} =
result = x
{.cast(raises: []), cast(tags: []).}:
`=wasMoved`(x)

30
tests/ccgbugs2/t25800.nim Normal file
View File

@@ -0,0 +1,30 @@
discard """
cmd: "nim cpp $file"
action: "compile"
"""
# Bug Report 1: {.importcpp.} on =wasMoved generates invalid preprocessor directive #.
{.emit: """/*TYPESECTION*/
struct CppRef {
int* data;
CppRef() : data(new int(42)) {}
~CppRef() { delete data; data = nullptr; }
void reset() { delete data; data = nullptr; }
};
""".}
type CppRef* {.importcpp, bycopy, noInit.} = object
proc `=destroy`(x: var CppRef) {.importcpp: "#.~CppRef()".}
proc `=wasMoved`(x: var CppRef) {.importcpp: "#.reset()".}
proc `=copy`(dest: var CppRef; src: CppRef) {.importcpp: "dest = src".}
proc `=sink`(dest: var CppRef; src: CppRef) {.importcpp: "dest = std::move(src)".}
# This triggers =wasMoved when passing to sink parameter
proc consume(x: sink CppRef) = discard
proc test() =
var x: CppRef
consume(move(x)) # =wasMoved MUST be called here after the move
test()