summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2023-06-05 14:06:14 +0800
committerGitHub <noreply@github.com>2023-06-05 08:06:14 +0200
commit1edae67efd90a880bd537f27a3cfabbed722a7af (patch)
tree826b5d7eadcee339a7f1791ce0deb3533525db8c
parent211ef26f2937ef218410231952a0680dfa1705ea (diff)
downloadNim-1edae67efd90a880bd537f27a3cfabbed722a7af.tar.gz
infer error for `=dup` if there is a custom `=copy` error hook (#22004)
-rw-r--r--compiler/injectdestructors.nim11
-rw-r--r--tests/destructor/tprevent_assign2.nim4
2 files changed, 12 insertions, 3 deletions
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index a03f85d02..c5056025b 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -186,8 +186,11 @@ template isUnpackedTuple(n: PNode): bool =
   ## hence unpacked tuples themselves don't need to be destroyed
   (n.kind == nkSym and n.sym.kind == skTemp and n.sym.typ.kind == tyTuple)
 
-proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string) =
+proc checkForErrorPragma(c: Con; t: PType; ri: PNode; opname: string; inferredFromCopy = false) =
   var m = "'" & opname & "' is not available for type <" & typeToString(t) & ">"
+  if inferredFromCopy:
+    m.add ", which is inferred from unavailable '=copy'"
+
   if (opname == "=" or opname == "=copy" or opname == "=dup") and ri != nil:
     m.add "; requires a copy because it's not the last read of '"
     m.add renderTree(ri)
@@ -430,6 +433,12 @@ proc passCopyToSink(n: PNode; c: var Con; s: var Scope): PNode =
     if op != nil and tfHasOwned notin typ.flags:
       if sfError in op.flags:
         c.checkForErrorPragma(n.typ, n, "=dup")
+      else:
+        let copyOp = getAttachedOp(c.graph, typ, attachedAsgn)
+        if copyOp != nil and sfError in copyOp.flags and
+           sfOverriden notin op.flags:
+          c.checkForErrorPragma(n.typ, n, "=dup", inferredFromCopy = true)
+
       let src = p(n, c, s, normal)
       var newCall = newTreeIT(nkCall, src.info, src.typ,
             newSymNode(op),
diff --git a/tests/destructor/tprevent_assign2.nim b/tests/destructor/tprevent_assign2.nim
index 7d788fa5c..eb5588b1a 100644
--- a/tests/destructor/tprevent_assign2.nim
+++ b/tests/destructor/tprevent_assign2.nim
@@ -1,5 +1,5 @@
 discard """
-  errormsg: "'=dup' is not available for type <Foo>; requires a copy because it's not the last read of 'otherTree'"
+  errormsg: "'=dup' is not available for type <Foo>, which is inferred from unavailable '=copy'; requires a copy because it's not the last read of 'otherTree'; another read is done here: tprevent_assign2.nim(51, 31); routine: preventThis"
   file: "tprevent_assign2.nim"
   line: 49
 """
@@ -10,7 +10,7 @@ type
 
 proc `=destroy`(f: var Foo) = f.x = 0
 proc `=copy`(a: var Foo; b: Foo) {.error.} # = a.x = b.x
-proc `=dup`(a: Foo): Foo {.error.}
+
 proc `=sink`(a: var Foo; b: Foo) = a.x = b.x
 
 proc createTree(x: int): Foo =