summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorArne Döring <arne.doering@gmx.net>2019-03-04 09:19:38 +0100
committerAndreas Rumpf <rumpf_a@web.de>2019-03-04 09:19:38 +0100
commit1d9b88f25d8c278123133773f83fd9ce81685bac (patch)
tree041a7d66ab4a1eee901d0e44f58fd99bce9a79d5 /compiler
parentebe0473511f23e64a8f68cd96a7534444e21c3ca (diff)
downloadNim-1d9b88f25d8c278123133773f83fd9ce81685bac.tar.gz
sizealign of union type (#10780)
* sizealign of union type

* add error message for packed union
Diffstat (limited to 'compiler')
-rw-r--r--compiler/sizealignoffsetimpl.nim54
1 files changed, 52 insertions, 2 deletions
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index fb256b895..af2f0ad40 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -145,6 +145,9 @@ proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOf
     var maxChildOffset: BiggestInt = kindUnionOffset
     for i in 1 ..< sonsLen(n):
       let offset = computePackedObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset, debug)
+      if offset < 0:
+         result = offset
+         break
       maxChildOffset = max(maxChildOffset, offset)
     result = maxChildOffset
   of nkRecList:
@@ -168,7 +171,47 @@ proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOf
   else:
     result = szUnknownSize
 
-# TODO this one needs an alignment map of the individual types
+proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, debug: bool): tuple[offset, align: BiggestInt] =
+  ## ``result`` is the offset from the larget member of the union.
+  case n.kind
+  of nkRecCase:
+    result.offset = szUnknownSize
+    result.align = szUnknownSize
+    localError(conf, n.info, "Illegal use of ``case`` in union type.")
+    #internalError(conf, "Illegal use of ``case`` in union type.")
+  of nkRecList:
+    var maxChildOffset: BiggestInt = 0
+    for i, child in n.sons:
+      let (offset, align) = computeUnionObjectOffsetsFoldFunction(conf, child, debug)
+      if offset == szIllegalRecursion or align == szIllegalRecursion:
+        result.offset = szIllegalRecursion
+        result.align = szIllegalRecursion
+      elif offset == szUnknownSize or align == szUnknownSize:
+        result.offset = szUnknownSize
+        result.align = szUnknownSize
+      else:
+        assert offset != szUncomputedSize
+        assert align != szUncomputedSize
+        result.offset = max(result.offset, offset)
+        result.align = max(result.align, align)
+  of nkSym:
+    var size = szUnknownSize
+    var align = szUnknownSize
+    if n.sym.bitsize == 0: # 0 represents bitsize not set
+      computeSizeAlign(conf, n.sym.typ)
+      size = n.sym.typ.size.int
+      align = n.sym.typ.align.int
+
+    result.align = align
+    if size == szUnknownSize:
+      n.sym.offset = szUnknownSize
+      result.offset = szUnknownSize
+    else:
+      n.sym.offset = 0
+      result.offset = n.sym.typ.size
+  else:
+    result.offset = szUnknownSize
+    result.align = szUnknownSize
 
 proc computeSizeAlign(conf: ConfigRef; typ: PType) =
   ## computes and sets ``size`` and ``align`` members of ``typ``
@@ -343,7 +386,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
       headerSize = 0
       headerAlign = 1
     let (offset, align) =
-      if tfPacked in typ.flags:
+      if tfUnion in typ.flags:
+        if tfPacked in typ.flags:
+          let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo()
+          localError(conf, info, "type may not be packed and union at the same time.")
+          (BiggestInt(szUnknownSize), BiggestInt(szUnknownSize))
+        else:
+          computeUnionObjectOffsetsFoldFunction(conf, typ.n, false)
+      elif tfPacked in typ.flags:
         (computePackedObjectOffsetsFoldFunction(conf, typ.n, headerSize, false), BiggestInt(1))
       else:
         computeObjectOffsetsFoldFunction(conf, typ.n, headerSize)