diff options
author | ringabout <43030857+ringabout@users.noreply.github.com> | 2023-03-16 23:06:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-03-16 16:06:26 +0100 |
commit | b5ee81fd234c690f736a8f196a234c11a32e3910 (patch) | |
tree | 4e6bc085d41a52761cbe6702206939ec89b031d3 | |
parent | 6552a27ec1e973d1e9a3e002b2e48c8206bf35a5 (diff) | |
download | Nim-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.nim | 4 | ||||
-rw-r--r-- | compiler/injectdestructors.nim | 45 | ||||
-rw-r--r-- | tests/arc/t18977.nim | 26 | ||||
-rw-r--r-- | tests/arc/tcaseobj.nim | 28 | ||||
-rw-r--r-- | tests/arc/tcaseobjcopy.nim | 23 | ||||
-rw-r--r-- | tests/destructor/tgotoexceptions7.nim | 3 |
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() |