summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2024-07-19 02:53:07 +0800
committerGitHub <noreply@github.com>2024-07-18 20:53:07 +0200
commit3a103669d18408cd75ca5c5c97c34f4222c6e217 (patch)
treee539caadbb207be8f4bc6d14c38fb63d2bd990eb
parent6aa54d533b3ee10ed5156b0f67f5418bc4b6d99d (diff)
downloadNim-3a103669d18408cd75ca5c5c97c34f4222c6e217.tar.gz
fixes #23858; 2.2.0 rc1 regression with cdecl functions (#23859)
fixes #23858

We should not assign fields to fields for returns of function calls
because calls might have side effects.
-rw-r--r--compiler/ccgcalls.nim6
-rw-r--r--compiler/ccgexprs.nim3
-rw-r--r--compiler/cgen.nim1
-rw-r--r--tests/arc/tarc_orc.nim11
4 files changed, 17 insertions, 4 deletions
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 040eebc3a..89a6862af 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -141,7 +141,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
             if d.k == locNone: d = getTemp(p, typ.returnType)
             var list = initLoc(locCall, d.lode, OnUnknown)
             list.snippet = pl
-            genAssignment(p, d, list, {}) # no need for deep copying
+            genAssignment(p, d, list, {needAssignCall}) # no need for deep copying
             if canRaise: raiseExit(p)
 
       elif isHarmlessStore(p, canRaise, d):
@@ -152,7 +152,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
         assert(d.t != nil)        # generate an assignment to d:
         var list = initLoc(locCall, d.lode, OnUnknown)
         list.snippet = pl
-        genAssignment(p, d, list, flags) # no need for deep copying
+        genAssignment(p, d, list, flags+{needAssignCall}) # no need for deep copying
         if canRaise:
           if not (useTemp and cleanupTemp(p, typ.returnType, d)):
             raiseExit(p)
@@ -160,7 +160,7 @@ proc fixupCall(p: BProc, le, ri: PNode, d: var TLoc,
         var tmp: TLoc = getTemp(p, typ.returnType, needsInit=true)
         var list = initLoc(locCall, d.lode, OnUnknown)
         list.snippet = pl
-        genAssignment(p, tmp, list, flags) # no need for deep copying
+        genAssignment(p, tmp, list, flags+{needAssignCall}) # no need for deep copying
         if canRaise:
           if not cleanupTemp(p, typ.returnType, tmp):
             raiseExit(p)
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 45a2cc2a9..af3c8bf66 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -379,7 +379,8 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
     elif not isObjLackingTypeField(ty):
       genGenericAsgn(p, dest, src, flags)
     elif containsGarbageCollectedRef(ty):
-      if ty[0].isNil and asgnComplexity(ty.n) <= 4:
+      if ty[0].isNil and asgnComplexity(ty.n) <= 4 and
+            needAssignCall notin flags: # calls might contain side effects
         discard getTypeDesc(p.module, ty)
         internalAssert p.config, ty.n != nil
         genOptAsgnObject(p, dest, src, flags, ty.n, ty)
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index c0af19080..08180a939 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -413,6 +413,7 @@ type
     needToCopy
     needToCopySinkParam
     needTempForOpenArray
+    needAssignCall
   TAssignmentFlags = set[TAssignmentFlag]
 
 proc genObjConstr(p: BProc, e: PNode, d: var TLoc)
diff --git a/tests/arc/tarc_orc.nim b/tests/arc/tarc_orc.nim
index 674ba0dbb..0e6208b4a 100644
--- a/tests/arc/tarc_orc.nim
+++ b/tests/arc/tarc_orc.nim
@@ -160,3 +160,14 @@ block:
     testCase()
 
   main()
+
+block: # bug #23858
+  type Object = object
+    a: int
+    b: ref int
+  var x = 0
+  proc fn(): auto {.cdecl.} =
+    inc x
+    return Object()
+  discard fn()
+  doAssert x == 1