summary refs log tree commit diff stats
path: root/compiler/ccgexprs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/ccgexprs.nim')
-rw-r--r--compiler/ccgexprs.nim130
1 files changed, 81 insertions, 49 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index b6feb78b2..4a3be0027 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -20,7 +20,7 @@ proc int64Literal(i: BiggestInt): PRope =
 proc uint64Literal(i: uint64): PRope = toRope($i & "ULL")
 
 proc intLiteral(i: BiggestInt): PRope =
-  if (i > low(int32)) and (i <= high(int32)):
+  if i > low(int32) and i <= high(int32):
     result = toRope(i)
   elif i == low(int32):
     # Nim has the same bug for the same reasons :-)
@@ -39,7 +39,7 @@ proc int32Literal(i: int): PRope =
 proc genHexLiteral(v: PNode): PRope =
   # hex literals are unsigned in C
   # so we don't generate hex literals any longer.
-  if not (v.kind in {nkIntLit..nkUInt64Lit}):
+  if v.kind notin {nkIntLit..nkUInt64Lit}:
     internalError(v.info, "genHexLiteral")
   result = intLiteral(v.intVal)
 
@@ -224,9 +224,9 @@ proc optAsgnLoc(a: TLoc, t: PType, field: PRope): TLoc =
 proc genOptAsgnTuple(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
   let newflags =
     if src.k == locData:
-      flags + { needToCopy }
+      flags + {needToCopy}
     elif tfShallow in dest.t.flags:
-      flags - { needToCopy }
+      flags - {needToCopy}
     else:
       flags
   for i in 0 .. <dest.t.len:
@@ -240,9 +240,9 @@ proc genOptAsgnObject(p: BProc, dest, src: TLoc, flags: TAssignmentFlags,
   if t == nil: return
   let newflags =
     if src.k == locData:
-      flags + { needToCopy }
+      flags + {needToCopy}
     elif tfShallow in dest.t.flags:
-      flags - { needToCopy }
+      flags - {needToCopy}
     else:
       flags
   case t.kind
@@ -328,7 +328,9 @@ proc genAssignment(p: BProc, dest, src: TLoc, flags: TAssignmentFlags) =
       linefmt(p, cpsStmts, "$1 = $2;$n", rdLoc(dest), rdLoc(src))
   of tyObject:
     # XXX: check for subtyping?
-    if needsComplexAssignment(ty):
+    if not isObjLackingTypeField(ty):
+      genGenericAsgn(p, dest, src, flags)
+    elif needsComplexAssignment(ty):
       if ty.sons[0].isNil and asgnComplexity(ty.n) <= 4:
         discard getTypeDesc(p.module, ty)
         internalAssert ty.n != nil
@@ -655,13 +657,16 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
               ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
                     getSimpleTypeDesc(p.module, e.typ)]))
 
-proc genDeref(p: BProc, e: PNode, d: var TLoc) =
-  var a: TLoc
-  if mapType(e.sons[0].typ) in {ctArray, ctPtrToArray}:
+proc genDeref(p: BProc, e: PNode, d: var TLoc; enforceDeref=false) =
+  let mt = mapType(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?
+    #if e[0].kind != nkBracketExpr:
+    #  message(e.info, warnUser, "CAME HERE " & renderTree(e))
     expr(p, e.sons[0], d)
   else:
+    var a: TLoc
     initLocExpr(p, e.sons[0], a)
     case skipTypes(a.t, abstractInst).kind
     of tyRef:
@@ -671,7 +676,15 @@ proc genDeref(p: BProc, e: PNode, d: var TLoc) =
     of tyPtr:
       d.s = OnUnknown         # BUGFIX!
     else: internalError(e.info, "genDeref " & $a.t.kind)
-    putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
+    if enforceDeref and mt == ctPtrToArray:
+      # 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
+      # ends up using 'memcpy' for the array assignment,
+      # so the '&' and '*' cancel out:
+      putIntoDest(p, d, a.t.sons[0], rdLoc(a))
+    else:
+      putIntoDest(p, d, a.t.sons[0], ropef("(*$1)", [rdLoc(a)]))
 
 proc genAddr(p: BProc, e: PNode, d: var TLoc) =
   # careful  'addr(myptrToArray)' needs to get the ampersand:
@@ -794,15 +807,15 @@ proc genCheckedRecordField(p: BProc, e: PNode, d: var TLoc) =
   else:
     genRecordField(p, e.sons[0], d)
 
-proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
+proc genArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
-  initLocExpr(p, e.sons[0], a)
-  initLocExpr(p, e.sons[1], b)
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
   var ty = skipTypes(skipTypes(a.t, abstractVarRange), abstractPtrs)
   var first = intLiteral(firstOrd(ty))
   # emit range check:
   if optBoundsCheck in p.options and tfUncheckedArray notin ty.flags:
-    if not isConstExpr(e.sons[1]):
+    if not isConstExpr(y):
       # semantic pass has already checked for const index expressions
       if firstOrd(ty) == 0:
         if (firstOrd(b.t) < firstOrd(ty)) or (lastOrd(b.t) > lastOrd(ty)):
@@ -812,26 +825,26 @@ proc genArrayElem(p: BProc, e: PNode, d: var TLoc) =
         linefmt(p, cpsStmts, "if ($1 < $2 || $1 > $3) #raiseIndexError();$n",
                 rdCharLoc(b), first, intLiteral(lastOrd(ty)))
     else:
-      let idx = getOrdValue(e.sons[1])
+      let idx = getOrdValue(y)
       if idx < firstOrd(ty) or idx > lastOrd(ty):
-        localError(e.info, errIndexOutOfBounds)
+        localError(x.info, errIndexOutOfBounds)
   d.inheritLocation(a)
   putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
               rfmt(nil, "$1[($2)- $3]", rdLoc(a), rdCharLoc(b), first))
 
-proc genCStringElem(p: BProc, e: PNode, d: var TLoc) =
+proc genCStringElem(p: BProc, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
-  initLocExpr(p, e.sons[0], a)
-  initLocExpr(p, e.sons[1], b)
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
   var ty = skipTypes(a.t, abstractVarRange)
   if d.k == locNone: d.s = a.s
   putIntoDest(p, d, elemType(skipTypes(ty, abstractVar)),
               rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
 
-proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
+proc genOpenArrayElem(p: BProc, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
-  initLocExpr(p, e.sons[0], a)
-  initLocExpr(p, e.sons[1], b) # emit range check:
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b) # emit range check:
   if optBoundsCheck in p.options:
     linefmt(p, cpsStmts, "if ((NU)($1) >= (NU)($2Len0)) #raiseIndexError();$n",
             rdLoc(b), rdLoc(a)) # BUGFIX: ``>=`` and not ``>``!
@@ -839,10 +852,10 @@ proc genOpenArrayElem(p: BProc, e: PNode, d: var TLoc) =
   putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
               rfmt(nil, "$1[$2]", rdLoc(a), rdCharLoc(b)))
 
-proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
+proc genSeqElem(p: BProc, x, y: PNode, d: var TLoc) =
   var a, b: TLoc
-  initLocExpr(p, e.sons[0], a)
-  initLocExpr(p, e.sons[1], b)
+  initLocExpr(p, x, a)
+  initLocExpr(p, y, b)
   var ty = skipTypes(a.t, abstractVarRange)
   if ty.kind in {tyRef, tyPtr}:
     ty = skipTypes(ty.lastSon, abstractVarRange) # emit range check:
@@ -862,6 +875,17 @@ proc genSeqElem(p: BProc, e: PNode, d: var TLoc) =
   putIntoDest(p, d, elemType(skipTypes(a.t, abstractVar)),
               rfmt(nil, "$1->data[$2]", rdLoc(a), rdCharLoc(b)))
 
+proc genBracketExpr(p: BProc; n: PNode; d: var TLoc) =
+  var ty = skipTypes(n.sons[0].typ, abstractVarRange)
+  if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
+  case ty.kind
+  of tyArray, tyArrayConstr: genArrayElem(p, n.sons[0], n.sons[1], d)
+  of tyOpenArray, tyVarargs: genOpenArrayElem(p, n.sons[0], n.sons[1], d)
+  of tySequence, tyString: genSeqElem(p, n.sons[0], n.sons[1], d)
+  of tyCString: genCStringElem(p, n.sons[0], n.sons[1], d)
+  of tyTuple: genTupleElem(p, n, d)
+  else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+
 proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
   # how to generate code?
   #  'expr1 and expr2' becomes:
@@ -903,14 +927,15 @@ proc genAndOr(p: BProc, e: PNode, d: var TLoc, m: TMagic) =
 proc genEcho(p: BProc, n: PNode) =
   # this unusal way of implementing it ensures that e.g. ``echo("hallo", 45)``
   # is threadsafe.
+  internalAssert n.kind == nkBracket
   discard lists.includeStr(p.module.headerFiles, "<stdio.h>")
   var args: PRope = nil
   var a: TLoc
-  for i in countup(1, n.len-1):
+  for i in countup(0, n.len-1):
     initLocExpr(p, n.sons[i], a)
     appf(args, ", ($1)->data", [rdLoc(a)])
   linefmt(p, cpsStmts, "printf($1$2);$n",
-          makeCString(repeatStr(n.len-1, "%s") & tnl), args)
+          makeCString(repeatStr(n.len, "%s") & tnl), args)
 
 proc gcUsage(n: PNode) =
   if gSelectedGC == gcNone: message(n.info, warnGcMem, n.renderTree)
@@ -1111,7 +1136,7 @@ proc genObjConstr(p: BProc, e: PNode, d: var TLoc) =
       ty = getUniqueType(ty.sons[0])
     if field == nil or field.loc.r == nil: internalError(e.info, "genObjConstr")
     if it.len == 3 and optFieldCheck in p.options:
-      genFieldCheck(p, it.sons[2], r, field)
+      genFieldCheck(p, it.sons[2], tmp2.r, field)
     app(tmp2.r, ".")
     app(tmp2.r, field.loc.r)
     tmp2.k = locTemp
@@ -1680,7 +1705,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       discard cgsym(p.module, opr.loc.r.ropeToStr)
     genCall(p, e, d)
   of mReset: genReset(p, e)
-  of mEcho: genEcho(p, e)
+  of mEcho: genEcho(p, e[1].skipConv)
   of mArrToSeq: genArrToSeq(p, e, d)
   of mNLen..mNError:
     localError(e.info, errCannotGenerateCodeForX, e.sons[0].sym.name.s)
@@ -1702,7 +1727,7 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
 
 proc genConstExpr(p: BProc, n: PNode): PRope
 proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool =
-  if (nfAllConst in n.flags) and (d.k == locNone) and (sonsLen(n) > 0):
+  if nfAllConst in n.flags and d.k == locNone and n.len > 0 and n.isDeepConstExpr:
     var t = getUniqueType(n.typ)
     discard getTypeDesc(p.module, t) # so that any fields are initialized
     var id = nodeTableTestOrSet(p.module.dataCache, n, gBackendId)
@@ -1856,18 +1881,34 @@ proc downConv(p: BProc, n: PNode, d: var TLoc) =
     expr(p, n.sons[0], d)     # downcast does C++ for us
   else:
     var dest = skipTypes(n.typ, abstractPtrs)
-    var src = skipTypes(n.sons[0].typ, abstractPtrs)
+
+    var arg = n.sons[0]
+    while arg.kind == nkObjDownConv: arg = arg.sons[0]
+
+    var src = skipTypes(arg.typ, abstractPtrs)
     var a: TLoc
-    initLocExpr(p, n.sons[0], a)
+    initLocExpr(p, arg, a)
     var r = rdLoc(a)
-    if skipTypes(n.sons[0].typ, abstractInst).kind in {tyRef, tyPtr, tyVar} and
-        n.sons[0].kind notin {nkHiddenAddr, nkAddr, nkObjDownConv}:
+    let isRef = skipTypes(arg.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}
+    if isRef:
       app(r, "->Sup")
-      for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
-      r = con("&", r)
     else:
-      for i in countup(1, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
-    putIntoDest(p, d, n.typ, r)
+      app(r, ".Sup")
+    for i in countup(2, abs(inheritanceDiff(dest, src))): app(r, ".Sup")
+    if isRef:
+      # it can happen that we end up generating '&&x->Sup' here, so we pack
+      # the '&x->Sup' into a temporary and then those address is taken
+      # (see bug #837). However sometimes using a temporary is not correct: 
+      # init(TFigure(my)) # where it is passed to a 'var TFigure'. We test
+      # this by ensuring the destination is also a pointer:
+      if d.k == locNone and skipTypes(n.typ, abstractInst).kind in {tyRef, tyPtr, tyVar}:
+        getTemp(p, n.typ, d)
+        linefmt(p, cpsStmts, "$1 = &$2;$n", rdLoc(d), r)
+      else:
+        r = con("&", r)
+        putIntoDest(p, d, n.typ, r)
+    else:
+      putIntoDest(p, d, n.typ, r)
 
 proc exprComplexConst(p: BProc, n: PNode, d: var TLoc) =
   var t = getUniqueType(n.typ)
@@ -1985,16 +2026,7 @@ proc expr(p: BProc, n: PNode, d: var TLoc) =
   of nkCast: genCast(p, n, d)
   of nkHiddenStdConv, nkHiddenSubConv, nkConv: genConv(p, n, d)
   of nkHiddenAddr, nkAddr: genAddr(p, n, d)
-  of nkBracketExpr:
-    var ty = skipTypes(n.sons[0].typ, abstractVarRange)
-    if ty.kind in {tyRef, tyPtr}: ty = skipTypes(ty.lastSon, abstractVarRange)
-    case ty.kind
-    of tyArray, tyArrayConstr: genArrayElem(p, n, d)
-    of tyOpenArray, tyVarargs: genOpenArrayElem(p, n, d)
-    of tySequence, tyString: genSeqElem(p, n, d)
-    of tyCString: genCStringElem(p, n, d)
-    of tyTuple: genTupleElem(p, n, d)
-    else: internalError(n.info, "expr(nkBracketExpr, " & $ty.kind & ')')
+  of nkBracketExpr: genBracketExpr(p, n, d)
   of nkDerefExpr, nkHiddenDeref: genDeref(p, n, d)
   of nkDotExpr: genRecordField(p, n, d)
   of nkCheckedFieldExpr: genCheckedRecordField(p, n, d)