summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorcooldome <cdome@bk.ru>2020-01-19 13:14:26 +0000
committerAndreas Rumpf <rumpf_a@web.de>2020-01-19 14:14:26 +0100
commit416b4c3612f444608218619947ecf290060ee8f6 (patch)
treec55c2650005888e57482bbe3be441968e30961aa
parentbc14453f69b9bde449cb52655eb6ffe571d6a28b (diff)
downloadNim-416b4c3612f444608218619947ecf290060ee8f6.tar.gz
more on arc codegen (#13178)
* arc codegen for union type

* add more tests

* fix offsetof

* fix tsizeof test

* fix style
-rw-r--r--compiler/ccgexprs.nim55
-rw-r--r--compiler/ccgtypes.nim14
-rw-r--r--tests/destructor/tarc3.nim21
-rw-r--r--tests/misc/tsizeof.nim17
4 files changed, 81 insertions, 26 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index e52be902b..eed29ff4b 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -2204,12 +2204,12 @@ proc genMagicExpr(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
       else:
         internalError(p.config, e.info, "unknown ast")
     let t = dotExpr[0].typ.skipTypes({tyTypeDesc})
+    let tname = getTypeDesc(p.module, t)
     let member =
       if t.kind == tyTuple:
         "Field" & rope(dotExpr[1].sym.position)
-      else:
-        rope(dotExpr[1].sym.name.s)
-    putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [getTypeDesc(p.module, t), member])
+      else: dotExpr[1].sym.loc.r
+    putIntoDest(p,d,e, "((NI)offsetof($1, $2))" % [tname, member])
   of mChr: genSomeCast(p, e, d)
   of mOrd: genOrd(p, e, d)
   of mLengthArray, mHigh, mLengthStr, mLengthSeq, mLengthOpenArray:
@@ -2782,17 +2782,50 @@ proc getNullValueAux(p: BProc; t: PType; obj, constOrNil: PNode,
   of nkRecCase:
     getNullValueAux(p, t, obj[0], constOrNil, result, count, isConst, info)
     if count > 0: result.add ", "
-    # XXX select default case branch here!
-    #for i in 1..<obj.len:
-    let selectedBranch = 1
-    result.add "{" # struct inside union
-    if lastSon(obj[selectedBranch]).kind != nkSym:
-      result.add "{"
+    var branch = Zero
+    if constOrNil != nil:
+      ## find kind value, default is zero if not specified
+      for i in 1..<constOrNil.len:
+        if constOrNil[i].kind == nkExprColonExpr:
+          if constOrNil[i][0].sym.name.id == obj[0].sym.name.id:
+            branch = getOrdValue(constOrNil[i][1])
+            break
+        elif i == obj[0].sym.position:
+          branch = getOrdValue(constOrNil[i])
+          break
+
+    var selectedBranch = -1
+    block branchSelection:
+      for i in 1 ..< obj.len:
+        for j in 0 .. obj[i].len - 2:
+          if obj[i][j].kind == nkRange:
+              let x = getOrdValue(obj[i][j][0])
+              let y = getOrdValue(obj[i][j][1])
+              if branch >= x and branch <= y:
+                selectedBranch = i
+                break branchSelection
+          elif getOrdValue(obj[i][j]) == branch:
+            selectedBranch = i
+            break branchSelection
+        if obj[i].len == 1:
+          # else branch
+          selectedBranch = i
+    assert(selectedBranch >= 1)
+    
+    result.add "{"
     var countB = 0
-    getNullValueAux(p, t, lastSon(obj[selectedBranch]), constOrNil, result, countB, isConst, info)
-    if lastSon(obj[selectedBranch]).kind != nkSym:
+    let b = lastSon(obj[selectedBranch])
+    # designated initilization is the only way to init non first element of unions
+    # branches are allowed to have no members (b.len == 0), in this case they don't need initializer
+    if  b.kind == nkRecList and b.len > 0:
+      result.add "._i" & $selectedBranch & " = {"
+      getNullValueAux(p, t,  b, constOrNil, result, countB, isConst, info)
       result.add "}"
+    elif b.kind == nkSym:
+      result.add "." & lastSon(obj[selectedBranch]).sym.loc.r & " = "
+      getNullValueAux(p, t,  b, constOrNil, result, countB, isConst, info)
     result.add "}"
+    
   of nkSym:
     if count > 0: result.add ", "
     inc count
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index 56f227e37..2bcaa5dc3 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -508,15 +508,15 @@ proc mangleRecFieldName(m: BModule; field: PSym): Rope =
 
 proc genRecordFieldsAux(m: BModule, n: PNode,
                         rectype: PType,
-                        check: var IntSet): Rope =
+                        check: var IntSet, unionPrefix = ""): Rope =
   result = nil
   case n.kind
   of nkRecList:
     for i in 0..<n.len:
-      result.add(genRecordFieldsAux(m, n[i], rectype, check))
+      result.add(genRecordFieldsAux(m, n[i], rectype, check, unionPrefix))
   of nkRecCase:
     if n[0].kind != nkSym: internalError(m.config, n.info, "genRecordFieldsAux")
-    result.add(genRecordFieldsAux(m, n[0], rectype, check))
+    result.add(genRecordFieldsAux(m, n[0], rectype, check, unionPrefix))
     # prefix mangled name with "_U" to avoid clashes with other field names,
     # since identifiers are not allowed to start with '_'
     var unionBody: Rope = nil
@@ -525,7 +525,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
       of nkOfBranch, nkElse:
         let k = lastSon(n[i])
         if k.kind != nkSym:
-          let a = genRecordFieldsAux(m, k, rectype, check)
+          let a = genRecordFieldsAux(m, k, rectype, check, unionPrefix & "_i" & $i & ".")
           if a != nil:
             if tfPacked notin rectype.flags:
               unionBody.add("struct {")
@@ -535,11 +535,11 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
               else:
                 unionBody.addf("#pragma pack(push, 1)$nstruct{", [])
             unionBody.add(a)
-            unionBody.addf("};$n", [])
+            unionBody.addf("} _i$1;$n", [rope($i)])
             if tfPacked in rectype.flags and hasAttribute notin CC[m.config.cCompiler].props:
               unionBody.addf("#pragma pack(pop)$n", [])
         else:
-          unionBody.add(genRecordFieldsAux(m, k, rectype, check))
+          unionBody.add(genRecordFieldsAux(m, k, rectype, check, unionPrefix))
       else: internalError(m.config, "genRecordFieldsAux(record case branch)")
     if unionBody != nil:
       result.addf("union{$n$1};$n", [unionBody])
@@ -548,7 +548,7 @@ proc genRecordFieldsAux(m: BModule, n: PNode,
     if field.typ.kind == tyVoid: return
     #assert(field.ast == nil)
     let sname = mangleRecFieldName(m, field)
-    fillLoc(field.loc, locField, n, sname, OnUnknown)
+    fillLoc(field.loc, locField, n, unionPrefix & sname, OnUnknown)
     if field.alignment > 0:
       result.addf "NIM_ALIGN($1) ", [rope(field.alignment)]
     # for importcpp'ed objects, we only need to set field.loc, but don't
diff --git a/tests/destructor/tarc3.nim b/tests/destructor/tarc3.nim
index 1ca4c70e9..d3b9639ad 100644
--- a/tests/destructor/tarc3.nim
+++ b/tests/destructor/tarc3.nim
@@ -4,7 +4,7 @@ discard """
 """
 
 when defined(cpp):
-  {.passC: "-std=gnu++17".}
+  {.passC: "-std=gnu++2a".}
 
 type
   TokenKind* = enum
@@ -24,6 +24,23 @@ type
     else: discard
     pos*: Natural
 
+
+  Token2* = object
+    case kind*: TokenKind
+    of tkString: strVal*: string
+    of tkNumber: numVal*: float
+    of tkInt64, tkColon..tkComma:
+      str1*: array[2, string]
+      float: float
+    else: discard
+    pos*: Natural
+
+  Token3* = object
+    case kind*: TokenKind
+    of tkNumber: numVal*: float
+    of tkInt64, tkComma..tkString: ff: seq[float]
+    else: str1*: string
+  
   BaseLexer* = object of RootObj
     input*: string
     pos*: Natural
@@ -39,6 +56,8 @@ type
   Parser[T: Lexer] = object
     l: T
     tok: Token
+    tok2: Token2
+    tok3: Token3
     allowTrailingComma: bool
     allowIdentifierObjectKey: bool
 
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
index a2a9fe59e..7b92d3639 100644
--- a/tests/misc/tsizeof.nim
+++ b/tests/misc/tsizeof.nim
@@ -74,20 +74,23 @@ proc strAlign(arg: string): string =
   for i in 0 ..< minLen - arg.len:
     result &= ' '
 
-macro c_offsetof(a: typed, b: untyped): int32 =
+macro c_offsetof(fieldAccess: typed): int32 =
   ## Bullet proof implementation that works on actual offsetof operator
   ## in the c backend. Assuming of course this implementation is
   ## correct.
-  let bliteral =
-    if b.kind == nnkStrLit:
-      b
-    else:
-      newLit(repr(b))
+  let s = if fieldAccess.kind == nnkCheckedFieldExpr: fieldAccess[0] 
+          else: fieldAccess
+  let a = s[0].getTypeInst
+  let b = s[1]
   result = quote do:
     var res: int32
-    {.emit: [res, " = offsetof(", `a`, ", ", `bliteral`, ");"] .}
+    {.emit: [res, " = offsetof(", `a`, ", ", `b`, ");"] .}
     res
 
+template c_offsetof(t: typedesc, a: untyped): int32 =
+  var x: ptr t
+  c_offsetof(x[].a)
+
 macro c_sizeof(a: typed): int32 =
   ## Bullet proof implementation that works using the sizeof operator
   ## in the c backend. Assuming of course this implementation is