diff options
-rw-r--r-- | compiler/ast.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 9 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 49 | ||||
-rw-r--r-- | compiler/types.nim | 9 | ||||
-rw-r--r-- | tests/openarray/tptrarrayderef.nim | 18 | ||||
-rw-r--r-- | tests/types/tillegaltyperecursion3.nim | 10 |
6 files changed, 49 insertions, 48 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim index aeb19ae1a..4ac1a1465 100644 --- a/compiler/ast.nim +++ b/compiler/ast.nim @@ -768,6 +768,8 @@ type lfHeader, # include header file for symbol lfImportCompilerProc, # ``importc`` of a compilerproc lfSingleUse # no location yet and will only be used once + lfEnforceDeref # a copyMem is required to dereference if this a + # ptr array due to C array limitations. See #1181, #6422, #11171 TStorageLoc* = enum OnUnknown, # location is unknown (stack, heap or static) OnStatic, # in a static section diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 88a69b6a1..1a262ddde 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -717,13 +717,11 @@ proc isCppRef(p: BProc; typ: PType): bool {.inline.} = skipTypes(typ, abstractInstOwned).kind == tyVar and tfVarIsPtr notin skipTypes(typ, abstractInstOwned).flags -proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = +proc genDeref(p: BProc, e: PNode, d: var TLoc) = let mt = mapType(p.config, e.sons[0].typ) - if mt in {ctArray, ctPtrToArray} and not enforceDeref: + if mt in {ctArray, ctPtrToArray} and lfEnforceDeref notin d.flags: # XXX the amount of hacks for C's arrays is incredible, maybe we should # simply wrap them in a struct? --> Losing auto vectorization then? - #if e[0].kind != nkBracketExpr: - # message(e.info, warnUser, "CAME HERE " & renderTree(e)) expr(p, e.sons[0], d) if e.sons[0].typ.skipTypes(abstractInstOwned).kind == tyRef: d.storage = OnHeap @@ -760,7 +758,7 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) = e.kind == nkHiddenDeref: putIntoDest(p, d, e, rdLoc(a), a.storage) return - if enforceDeref and mt == ctPtrToArray: + if mt == ctPtrToArray and lfEnforceDeref in d.flags: # we lie about the type for better C interop: 'ptr array[3,T]' is # translated to 'ptr T', but for deref'ing this produces wrong code. # See tmissingderef. So we get rid of the deref instead. The codegen @@ -2343,6 +2341,7 @@ proc genTupleConstr(p: BProc, n: PNode, d: var TLoc) = if it.kind == nkExprColonExpr: it = it.sons[1] initLoc(rec, locExpr, it, d.storage) rec.r = "$1.Field$2" % [rdLoc(d), rope(i)] + rec.flags.incl(lfEnforceDeref) expr(p, it, rec) proc isConstClosure(n: PNode): bool {.inline.} = diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim index abddb7c6c..81b87fd4a 100644 --- a/compiler/ccgstmts.nim +++ b/compiler/ccgstmts.nim @@ -123,13 +123,11 @@ proc genVarTuple(p: BProc, n: PNode) = if forHcr or isGlobalInBlock: hcrGlobals.add((loc: v.loc, tp: if traverseProc == nil: ~"NULL" else: traverseProc)) -proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) - proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = if ri.kind in nkCallKinds and (ri.sons[0].kind != nkSym or ri.sons[0].sym.magic == mNone): genAsgnCall(p, le, ri, a) - elif ri.kind in {nkDerefExpr, nkHiddenDeref}: + else: # this is a hacky way to fix #1181 (tmissingderef):: # # var arr1 = cast[ptr array[4, int8]](addr foo)[] @@ -137,8 +135,7 @@ proc loadInto(p: BProc, le, ri: PNode, a: var TLoc) {.inline.} = # However, fixing this properly really requires modelling 'array' as # a 'struct' in C to preserve dereferencing semantics completely. Not # worth the effort until version 1.0 is out. - genDeref(p, ri, a, enforceDeref=true) - else: + a.flags.incl(lfEnforceDeref) expr(p, ri, a) proc assignLabel(b: var TBlock): Rope {.inline.} = @@ -597,10 +594,12 @@ proc genWhileStmt(p: BProc, t: PNode) = dec(p.withinLoop) proc genBlock(p: BProc, n: PNode, d: var TLoc) = - # bug #4505: allocate the temp in the outer scope - # so that it can escape the generated {}: - if not isEmptyType(n.typ) and d.k == locNone: - getTemp(p, n.typ, d) + if not isEmptyType(n.typ): + # bug #4505: allocate the temp in the outer scope + # so that it can escape the generated {}: + if d.k == locNone: + getTemp(p, n.typ, d) + d.flags.incl(lfEnforceDeref) preserveBreakIdx: p.breakIdx = startBlock(p) if n.sons[0].kind != nkEmpty: @@ -1232,44 +1231,18 @@ proc asgnFieldDiscriminant(p: BProc, e: PNode) = genDiscriminantCheck(p, a, tmp, dotExpr.sons[0].typ, dotExpr.sons[1].sym) genAssignment(p, a, tmp, {}) -proc patchAsgnStmtListExpr(father, orig, n: PNode) = - case n.kind - of nkDerefExpr, nkHiddenDeref: - let asgn = copyNode(orig) - asgn.add orig[0] - asgn.add n - father.add asgn - of nkStmtList, nkStmtListExpr: - for x in n: - patchAsgnStmtListExpr(father, orig, x) - else: - father.add n - proc genAsgn(p: BProc, e: PNode, fastAsgn: bool) = if e.sons[0].kind == nkSym and sfGoto in e.sons[0].sym.flags: genLineDir(p, e) genGotoVar(p, e.sons[1]) elif not fieldDiscriminantCheckNeeded(p, e): - # this fixes bug #6422 but we really need to change the representation of - # arrays in the backend... let le = e[0] let ri = e[1] - var needsRepair = false - var it = ri - while it.kind in {nkStmtList, nkStmtListExpr}: - it = it.lastSon - needsRepair = true - if it.kind in {nkDerefExpr, nkHiddenDeref} and needsRepair: - var patchedTree = newNodeI(nkStmtList, e.info) - patchAsgnStmtListExpr(patchedTree, e, ri) - genStmts(p, patchedTree) - return var a: TLoc discard getTypeDesc(p.module, le.typ.skipTypes(skipPtrs)) - if le.kind in {nkDerefExpr, nkHiddenDeref}: - genDeref(p, le, a, enforceDeref=true) - else: - initLocExpr(p, le, a) + initLoc(a, locNone, le, OnUnknown) + a.flags.incl(lfEnforceDeref) + expr(p, le, a) if fastAsgn: incl(a.flags, lfNoDeepCopy) assert(a.t != nil) genLineDir(p, ri) diff --git a/compiler/types.nim b/compiler/types.nim index 199bd3352..a40a94421 100644 --- a/compiler/types.nim +++ b/compiler/types.nim @@ -1517,11 +1517,12 @@ proc typeMismatch*(conf: ConfigRef; info: TLineInfo, formal, actual: PType) = localError(conf, info, msg) proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = - if t == nil: return + if t == nil: + return false + if cycleDetector.containsOrIncl(t.id): + return true case t.kind: of tyTuple: - if cycleDetector.containsOrIncl(t.id): - return true var cycleDetectorCopy: IntSet for i in 0..<t.len: assign(cycleDetectorCopy, cycleDetector) @@ -1530,7 +1531,7 @@ proc isTupleRecursive(t: PType, cycleDetector: var IntSet): bool = of tyAlias, tyRef, tyPtr, tyGenericInst, tyVar, tyLent, tySink, tyArray, tyUncheckedArray, tySequence: return isTupleRecursive(t.lastSon, cycleDetector) else: - discard + return false proc isTupleRecursive*(t: PType): bool = var cycleDetector = initIntSet() diff --git a/tests/openarray/tptrarrayderef.nim b/tests/openarray/tptrarrayderef.nim index 5c63f6f98..b75bc08c4 100644 --- a/tests/openarray/tptrarrayderef.nim +++ b/tests/openarray/tptrarrayderef.nim @@ -1,5 +1,8 @@ discard """ - output: "OK" + output: '''[1, 2, 3, 4] +3 +OK +''' """ var @@ -50,4 +53,17 @@ let aa = getFilledBuffer(3) for i in 0..aa[].len-1: doAssert(aa[i] == chr(i)) +var + x = [1, 2, 3, 4] + y1 = block: ( + a: (block: + echo x + cast[ptr array[2, int]](addr(x[0]))[]), + b: 3) + y2 = block: + echo y1.a[0] + y1.a[1] + cast[ptr array[4, int]](addr(x))[] +doAssert y1 == ([1, 2], 3) +doAssert y2 == [1, 2, 3, 4] + echo "OK" diff --git a/tests/types/tillegaltyperecursion3.nim b/tests/types/tillegaltyperecursion3.nim new file mode 100644 index 000000000..8e1138329 --- /dev/null +++ b/tests/types/tillegaltyperecursion3.nim @@ -0,0 +1,10 @@ +discard """ +errormsg: "illegal recursion in type 'Weird'" +""" + +# issue #3456 + +import tables +type + Weird = ref seq[Weird] +var t = newTable[int, Weird]() |