summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorringabout <43030857+ringabout@users.noreply.github.com>2023-03-16 23:06:26 +0800
committerGitHub <noreply@github.com>2023-03-16 16:06:26 +0100
commitb5ee81fd234c690f736a8f196a234c11a32e3910 (patch)
tree4e6bc085d41a52761cbe6702206939ec89b031d3
parent6552a27ec1e973d1e9a3e002b2e48c8206bf35a5 (diff)
downloadNim-b5ee81fd234c690f736a8f196a234c11a32e3910.tar.gz
fix #18977; disallow change branch of an object variant in ORC (#21526)
* fix #18977 disallow change branch of an object variant in ORC

* check errors for goto exception

* fixes conditions

* fixes tests

* add a test case for #18977
-rw-r--r--compiler/ccgstmts.nim4
-rw-r--r--compiler/injectdestructors.nim45
-rw-r--r--tests/arc/t18977.nim26
-rw-r--r--tests/arc/tcaseobj.nim28
-rw-r--r--tests/arc/tcaseobjcopy.nim23
-rw-r--r--tests/destructor/tgotoexceptions7.nim3
6 files changed, 97 insertions, 32 deletions
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 7ade85b42..df7eada00 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -1579,6 +1579,8 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
         "#FieldDiscriminantCheck((NI)(NU)($1), (NI)(NU)($2), $3, $4);$n",
         [rdLoc(a), rdLoc(tmp), discriminatorTableName(p.module, t, field),
          lit])
+  if p.config.exc == excGoto:
+    raiseExit(p)
 
 when false:
   proc genCaseObjDiscMapping(p: BProc, e: PNode, t: PType, field: PSym; d: var TLoc) =
@@ -1603,7 +1605,7 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) =
   initLocExpr(p, e[0], a)
   getTemp(p, a.t, tmp)
   expr(p, e[1], tmp)
-  if optTinyRtti notin p.config.globalOptions and p.inUncheckedAssignSection == 0:
+  if p.inUncheckedAssignSection == 0:
     let field = dotExpr[1].sym
     genDiscriminantCheck(p, a, tmp, dotExpr[0].typ, field)
     message(p.config, e.info, warnCaseTransition)
diff --git a/compiler/injectdestructors.nim b/compiler/injectdestructors.nim
index d58f28289..5ddd49621 100644
--- a/compiler/injectdestructors.nim
+++ b/compiler/injectdestructors.nim
@@ -17,12 +17,12 @@ import
   intsets, strtabs, ast, astalgo, msgs, renderer, magicsys, types, idents,
   strutils, options, lowerings, tables, modulegraphs,
   lineinfos, parampatterns, sighashes, liftdestructors, optimizer,
-  varpartitions, aliasanalysis, dfa
+  varpartitions, aliasanalysis, dfa, wordrecg
 
 when defined(nimPreviewSlimSystem):
   import std/assertions
 
-from trees import exprStructuralEquivalent, getRoot
+from trees import exprStructuralEquivalent, getRoot, whichPragma
 
 type
   Con = object
@@ -35,6 +35,7 @@ type
     idgen: IdGenerator
     body: PNode
     otherUsage: TLineInfo
+    inUncheckedAssignSection: int
 
   Scope = object # we do scope-based memory management.
     # a scope is comparable to an nkStmtListExpr like
@@ -342,15 +343,16 @@ It is best to factor out piece of object that needs custom destructor into separ
       return
 
     # generate: if le != tmp: `=destroy`(le)
-    let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
-    let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
-    cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
-    cond.add le
-    cond.add tmp
-    let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
-    notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
-    notExpr.add cond
-    result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
+    if c.inUncheckedAssignSection != 0:
+      let branchDestructor = produceDestructorForDiscriminator(c.graph, objType, leDotExpr[1].sym, n.info, c.idgen)
+      let cond = newNodeIT(nkInfix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
+      cond.add newSymNode(getMagicEqSymForType(c.graph, le.typ, n.info))
+      cond.add le
+      cond.add tmp
+      let notExpr = newNodeIT(nkPrefix, n.info, getSysType(c.graph, unknownLineInfo, tyBool))
+      notExpr.add newSymNode(createMagic(c.graph, c.idgen, "not", mNot))
+      notExpr.add cond
+      result.add newTree(nkIfStmt, newTree(nkElifBranch, notExpr, c.genOp(branchDestructor, le)))
   result.add newTree(nkFastAsgn, le, tmp)
 
 proc genWasMoved(c: var Con, n: PNode): PNode =
@@ -877,7 +879,7 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
        nkTypeOfExpr, nkMixinStmt, nkBindStmt:
       result = n
 
-    of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange, nkPragmaBlock:
+    of nkStringToCString, nkCStringToString, nkChckRangeF, nkChckRange64, nkChckRange:
       result = shallowCopy(n)
       for i in 0 ..< n.len:
         result[i] = p(n[i], c, s, normal)
@@ -885,6 +887,25 @@ proc p(n: PNode; c: var Con; s: var Scope; mode: ProcessMode; tmpFlags = {sfSing
         if mode == normal:
           result = ensureDestruction(result, n, c, s)
 
+    of nkPragmaBlock:
+      var inUncheckedAssignSection = 0
+      let pragmaList = n[0]
+      for pi in pragmaList:
+        if whichPragma(pi) == wCast:
+          case whichPragma(pi[1])
+          of wUncheckedAssign:
+            inUncheckedAssignSection = 1
+          else:
+            discard
+      result = shallowCopy(n)
+      inc c.inUncheckedAssignSection, inUncheckedAssignSection
+      for i in 0 ..< n.len:
+        result[i] = p(n[i], c, s, normal)
+      dec c.inUncheckedAssignSection, inUncheckedAssignSection
+      if n.typ != nil and hasDestructor(c, n.typ):
+        if mode == normal:
+          result = ensureDestruction(result, n, c, s)
+
     of nkHiddenSubConv, nkHiddenStdConv, nkConv:
       # we have an "ownership invariance" for all constructors C(x).
       # See the comment for nkBracket construction. If the caller wants
diff --git a/tests/arc/t18977.nim b/tests/arc/t18977.nim
new file mode 100644
index 000000000..c775551a4
--- /dev/null
+++ b/tests/arc/t18977.nim
@@ -0,0 +1,26 @@
+discard """
+  matrix: "--mm:arc"
+"""
+
+type
+  E = enum
+    a, b, c, d
+  X = object
+    v: int
+  O = object
+    case kind: E
+    of a:
+      a: int
+    of {b, c}:
+      b: float
+    else:
+      d: X
+
+proc `=destroy`(x: var X) =
+  echo "x destroyed"
+
+var o = O(kind: d, d: X(v: 12345))
+doAssert o.d.v == 12345
+
+doAssertRaises(FieldDefect):
+  o.kind = a
diff --git a/tests/arc/tcaseobj.nim b/tests/arc/tcaseobj.nim
index 26c122384..be1d722ed 100644
--- a/tests/arc/tcaseobj.nim
+++ b/tests/arc/tcaseobj.nim
@@ -60,7 +60,7 @@ proc `=destroy`(o: var TMyObj) =
     o.p = nil
     echo "myobj destroyed"
 
-proc `=`(dst: var TMyObj, src: TMyObj) =
+proc `=copy`(dst: var TMyObj, src: TMyObj) =
   `=destroy`(dst)
   dst.p = alloc(src.len)
   dst.len = src.len
@@ -170,18 +170,24 @@ proc test_myobject =
   x.x1 = "x1"
   x.x2 = "x2"
   x.y1 = "ljhkjhkjh"
-  x.kind1 = true
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
   x.y2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
-  x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
   x.z2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
   x.kind2 = true # should be no effect
   doAssert(x.z1 == "yes")
-  x.kind2 = false
-  x.kind1 = x.kind2 # support self assignment with effect
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind1 = x.kind2 # support self assignment with effect
 
   try:
     x.kind1 = x.flag # flag is not accesible
@@ -207,8 +213,9 @@ type
       error*: string
 
 proc init(): RocksDBResult[string] =
-  result.ok = true
-  result.value = "ok"
+  {.cast(uncheckedAssign).}:
+    result.ok = true
+    result.value = "ok"
 
 echo init()
 
@@ -222,7 +229,8 @@ type MyObj = object
     of true: x1: string
 
 var a = MyObj(kind: false, x0: 1234)
-a.kind = true
+{.cast(uncheckedAssign).}:
+  a.kind = true
 doAssert(a.x1 == "")
 
 block:
diff --git a/tests/arc/tcaseobjcopy.nim b/tests/arc/tcaseobjcopy.nim
index ed07b404e..fb26a4973 100644
--- a/tests/arc/tcaseobjcopy.nim
+++ b/tests/arc/tcaseobjcopy.nim
@@ -169,18 +169,23 @@ proc test_myobject =
   x.x1 = "x1"
   x.x2 = "x2"
   x.y1 = "ljhkjhkjh"
-  x.kind1 = true
+  {.cast(uncheckedAssign).}:
+    x.kind1 = true
   x.y2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
-  x.kind2 = false
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
   x.z2 = @["1", "2"]
-  x.kind2 = true
+  {.cast(uncheckedAssign).}:
+    x.kind2 = true
   x.z1 = "yes"
   x.kind2 = true # should be no effect
   doAssert(x.z1 == "yes")
-  x.kind2 = false
-  x.kind1 = x.kind2 # support self assignment with effect
+  {.cast(uncheckedAssign).}:
+    x.kind2 = false
+    x.kind1 = x.kind2 # support self assignment with effect
 
   try:
     x.kind1 = x.flag # flag is not accesible
@@ -206,7 +211,8 @@ type
       error*: string
 
 proc init(): RocksDBResult[string] =
-  result.ok = true
+  {.cast(uncheckedAssign).}:
+    result.ok = true
   result.value = "ok"
 
 echo init()
@@ -221,7 +227,8 @@ type MyObj = object
     of true: x1: string
 
 var a = MyObj(kind: false, x0: 1234)
-a.kind = true
+{.cast(uncheckedAssign).}:
+  a.kind = true
 doAssert(a.x1 == "")
 
 block:
diff --git a/tests/destructor/tgotoexceptions7.nim b/tests/destructor/tgotoexceptions7.nim
index 6e564a044..c04bd6ba0 100644
--- a/tests/destructor/tgotoexceptions7.nim
+++ b/tests/destructor/tgotoexceptions7.nim
@@ -25,7 +25,8 @@ proc helper = doAssert(false)
 
 proc main(i: int) =
   var obj = Obj(kind: kindA, s: "abc")
-  obj.kind = kindB
+  {.cast(uncheckedAssign).}:
+    obj.kind = kindB
   obj.i = 2
   try:
     var objA = ObjA()