summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorcooldome <ariabushenko@gmail.com>2020-10-01 16:39:48 +0100
committerGitHub <noreply@github.com>2020-10-01 17:39:48 +0200
commit531ed2dc365d6d33c7bccdfbe22df561cf14af86 (patch)
treed4d88cf40fb7b6f805011c4796e421bffc212fef
parent3919f0aa544d84c7a236e5095b87d7d0c8fb63b4 (diff)
downloadNim-531ed2dc365d6d33c7bccdfbe22df561cf14af86.tar.gz
fix #15405. deepcopy arc (#15410)
* fix #15405
* fix tests
* deepcopy for ARC has to be enabled via --deepcopy:on

Co-authored-by: Araq <rumpf_a@web.de>
-rw-r--r--changelog.md3
-rw-r--r--compiler/ccgexprs.nim4
-rw-r--r--compiler/ccgtypes.nim7
-rw-r--r--compiler/commands.nim3
-rw-r--r--compiler/options.nim1
-rw-r--r--doc/advopt.txt1
-rw-r--r--lib/system.nim3
-rw-r--r--tests/arc/tarcmisc.nim33
-rw-r--r--tests/arc/tdeepcopy.nim2
9 files changed, 52 insertions, 5 deletions
diff --git a/changelog.md b/changelog.md
index 5061a90b6..3bae911e9 100644
--- a/changelog.md
+++ b/changelog.md
@@ -287,6 +287,9 @@ proc mydiv(a, b): int {.raises: [].} =
   performance this keyword can enable.
 
 - `items` no longer compiles with enum with holes as its behavior was error prone, see #14004
+- `system.deepcopy` has to be enabled explicitly for `--gc:arc` and `--gc:orc` via
+  `--deepcopy:on`.
+
 
 - Added `critbits.toCritBitTree`, similar to `tables.toTable`, creates a new `CritBitTree` with given arguments.
 
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index b6808a55e..49b1f3d16 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2394,6 +2394,10 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       let n = semparallel.liftParallel(p.module.g.graph, p.module.module, e)
       expr(p, n, d)
   of mDeepCopy:
+    if p.config.selectedGC in {gcArc, gcOrc} and optEnableDeepCopy notin p.config.globalOptions:
+      localError(p.config, e.info,
+        "for --gc:arc|orc 'deepcopy' support has to be enabled with --deepcopy:on")
+
     var a, b: TLoc
     let x = if e[1].kind in {nkAddr, nkHiddenAddr}: e[1][0] else: e[1]
     initLocExpr(p, x, a)
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index c1a214532..0df7c8d2a 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -1355,6 +1355,9 @@ proc genTypeInfoV2Impl(m: BModule, t, origType: PType, name: Rope; info: TLineIn
     name, destroyImpl, getTypeDesc(m, t), typeName,
     traceImpl, disposeImpl])
 
+  if t.kind == tyObject and t.len > 0 and t[0] != nil and optEnableDeepCopy in m.config.globalOptions:
+    discard genTypeInfoV1(m, t, info)
+
 proc genTypeInfoV2(m: BModule, t: PType; info: TLineInfo): Rope =
   let origType = t
   var t = skipTypes(origType, irrelevantForBackend + tyUserTypeClasses)
@@ -1454,12 +1457,12 @@ proc genTypeInfoV1(m: BModule, t: PType; info: TLineInfo): Rope =
       genTupleInfo(m, x, x, result, info)
   of tySequence:
     genTypeInfoAux(m, t, t, result, info)
-    if m.config.selectedGC >= gcMarkAndSweep:
+    if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}:
       let markerProc = genTraverseProc(m, origType, sig)
       m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
   of tyRef:
     genTypeInfoAux(m, t, t, result, info)
-    if m.config.selectedGC >= gcMarkAndSweep:
+    if m.config.selectedGC in {gcMarkAndSweep, gcRefc, gcV2, gcGo}:
       let markerProc = genTraverseProc(m, origType, sig)
       m.s[cfsTypeInit3].addf("$1.marker = $2;$n", [tiNameForHcr(m, result), markerProc])
   of tyPtr, tyRange, tyUncheckedArray: genTypeInfoAux(m, t, t, result, info)
diff --git a/compiler/commands.nim b/compiler/commands.nim
index 17124a759..19048065f 100644
--- a/compiler/commands.nim
+++ b/compiler/commands.nim
@@ -901,7 +901,8 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
   of "sourcemap":
     conf.globalOptions.incl optSourcemap
     conf.options.incl optLineDir
-    # processOnOffSwitchG(conf, {optSourcemap, opt}, arg, pass, info)
+  of "deepcopy":
+    processOnOffSwitchG(conf, {optEnableDeepCopy}, arg, pass, info)
   of "": # comes from "-" in for example: `nim c -r -` (gets stripped from -)
     handleStdinInput(conf)
   else:
diff --git a/compiler/options.nim b/compiler/options.nim
index efb0aa2da..40d86a01d 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -96,6 +96,7 @@ type                          # please make sure we have under 32 options
     optNimV1Emulation         # emulate Nim v1.0
     optSourcemap
     optProfileVM              # enable VM profiler
+    optEnableDeepCopy         # ORC specific: enable 'deepcopy' for all types.
 
   TGlobalOptions* = set[TGlobalOption]
 
diff --git a/doc/advopt.txt b/doc/advopt.txt
index 830b8bfc6..60f5a1e10 100644
--- a/doc/advopt.txt
+++ b/doc/advopt.txt
@@ -153,3 +153,4 @@ Advanced options:
   --profileVM:on|off        enable compile time VM profiler
   --sinkInference:on|off    en-/disable sink parameter inference (default: on)
   --panics:on|off           turn panics into process terminations (default: off)
+  --deepcopy:on|off         enable 'system.deepCopy' for ``--gc:arc|orc``
diff --git a/lib/system.nim b/lib/system.nim
index 0784cacce..fe73a70f5 100644
--- a/lib/system.nim
+++ b/lib/system.nim
@@ -2895,6 +2895,9 @@ when hasAlloc and notJSnotNims:
     ##
     ## This is also used by the code generator
     ## for the implementation of ``spawn``.
+    ##
+    ## For ``--gc:arc`` or ``--gc:orc`` deepcopy support has to be enabled
+    ## via ``--deepcopy:on``.
     discard
 
   proc deepCopy*[T](y: T): T =
diff --git a/tests/arc/tarcmisc.nim b/tests/arc/tarcmisc.nim
index 542e4f316..b53d49df8 100644
--- a/tests/arc/tarcmisc.nim
+++ b/tests/arc/tarcmisc.nim
@@ -30,7 +30,7 @@ closed
 destroying variable: 20
 destroying variable: 10
 '''
-  cmd: "nim c --gc:arc $file"
+  cmd: "nim c --gc:arc --deepcopy:on $file"
 """
 
 proc takeSink(x: sink string): bool = true
@@ -347,3 +347,34 @@ var data = {
 
 # For ARC listVal is empty for some reason
 doAssert data["examples"]["values"].listVal[0].strVal == "test"
+
+
+
+
+###############################################################################
+# bug #15405
+import parsexml
+const test_xml_str = "<A><B>value</B></A>"
+var stream = newStringStream(test_xml_str)
+var xml: XmlParser
+open(xml, stream, "test")
+var xml2 = deepCopy(xml)
+
+proc text_parser(xml: var XmlParser) =
+  var test_passed = false
+  while true:
+    xml.next()
+    case xml.kind
+    of xmlElementStart:
+      if xml.elementName == "B":
+        xml.next()
+        if xml.kind == xmlCharData and xml.charData == "value":
+          test_passed = true
+
+    of xmlEof: break
+    else: discard
+  xml.close()
+  doAssert(test_passed)
+
+text_parser(xml)
+text_parser(xml2)
\ No newline at end of file
diff --git a/tests/arc/tdeepcopy.nim b/tests/arc/tdeepcopy.nim
index 0eaf7ea40..91d93aa28 100644
--- a/tests/arc/tdeepcopy.nim
+++ b/tests/arc/tdeepcopy.nim
@@ -1,5 +1,5 @@
 discard """
-  cmd: "nim c --gc:arc $file"
+  cmd: "nim c --gc:arc --deepcopy:on $file"
   output: '''13 abc
 13 abc
 13 abc