summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorJasper Jenkins <jasper.vs.jenkins@gmail.com>2019-05-06 23:14:38 -0700
committerAndreas Rumpf <rumpf_a@web.de>2019-05-07 08:14:38 +0200
commita6ba3116b2376d9f3476ef0f8db5bbb32afc2a76 (patch)
tree325d1c688970c410fa6e452a84b670fa196ffd1c
parent7804b5c55888717b35432c2670f4eef23afd583a (diff)
downloadNim-a6ba3116b2376d9f3476ef0f8db5bbb32afc2a76.tar.gz
Fixes for ptr array deref codegen (#11191)
* fixes for ptr array derefence codegen
* fix comments, make diff nicer
-rw-r--r--compiler/ast.nim2
-rw-r--r--compiler/ccgexprs.nim7
-rw-r--r--compiler/ccgstmts.nim49
-rw-r--r--tests/openarray/tptrarrayderef.nim18
4 files changed, 36 insertions, 40 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..d8c9255a7 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -717,8 +717,10 @@ 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) =
-  let mt = mapType(p.config, e.sons[0].typ)
+proc genDeref(p: BProc, e: PNode, d: var TLoc) =
+  let
+    enforceDeref = lfEnforceDeref in d.flags
+    mt = mapType(p.config, e.sons[0].typ)
   if mt in {ctArray, ctPtrToArray} and not enforceDeref:
     # XXX the amount of hacks for C's arrays is incredible, maybe we should
     # simply wrap them in a struct? --> Losing auto vectorization then?
@@ -2343,6 +2345,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..2f8e1653f 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -123,13 +123,13 @@ 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 genDeref(p: BProc, e: PNode, d: var TLoc)
 
 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 +137,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 +596,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 +1233,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/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"