summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/ast.nim1
-rw-r--r--compiler/options.nim10
-rw-r--r--compiler/pragmas.nim10
-rw-r--r--compiler/semtypes.nim9
-rw-r--r--compiler/sizealignoffsetimpl.nim343
-rw-r--r--tests/misc/tsizeof.nim53
6 files changed, 197 insertions, 229 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 6e5006bb7..71d19be30 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -899,6 +899,7 @@ type
     size*: BiggestInt         # the size of the type in bytes
                               # -1 means that the size is unkwown
     align*: int16             # the type's alignment requirements
+    paddingAtEnd*: int16      #
     lockLevel*: TLockLevel    # lock level as required for deadlock checking
     loc*: TLoc
     typeInst*: PType          # for generic instantiations the tyGenericInst that led to this
diff --git a/compiler/options.nim b/compiler/options.nim
index 52ecd61bc..8b5ade727 100644
--- a/compiler/options.nim
+++ b/compiler/options.nim
@@ -719,3 +719,13 @@ proc `$`*(c: IdeCmd): string =
   of ideOutline: "outline"
   of ideKnown: "known"
   of ideMsg: "msg"
+
+proc floatInt64Align*(conf: ConfigRef): int16 =
+  ## Returns either 4 or 8 depending on reasons.
+  if conf.target.targetCPU == cpuI386:
+    #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
+    if conf.target.targetOS != osWindows:
+      # on i386 for all known POSIX systems, 64bits ints are aligned
+      # to 4bytes (except with -malign-double)
+      return 4
+  return 8
diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim
index 12b0cff87..000066b8e 100644
--- a/compiler/pragmas.nim
+++ b/compiler/pragmas.nim
@@ -816,12 +816,12 @@ proc singlePragma(c: PContext, sym: PSym, n: PNode, i: var int,
         if sym.typ == nil: invalidPragma(c, it)
         var size = expectIntLit(c, it)
         case size
-        of 1, 2, 4, 8:
+        of 1, 2, 4:
           sym.typ.size = size
-          if size == 8 and c.config.target.targetCPU == cpuI386:
-            sym.typ.align = 4
-          else:
-            sym.typ.align = int16(size)
+          sym.typ.align = int16 size
+        of 8:
+          sym.typ.size = 8
+          sym.typ.align = floatInt64Align(c.config)
         else:
           localError(c.config, it.info, "size may only be 1, 2, 4 or 8")
       of wNodecl:
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 16cc89e13..6e542237b 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -1819,13 +1819,8 @@ proc setMagicType(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
 
   # FIXME: proper support for clongdouble should be added.
   # long double size can be 8, 10, 12, 16 bytes depending on platform & compiler
-  if conf.target.targetCPU == cpuI386 and size == 8:
-    #on Linux/BSD i386, double are aligned to 4bytes (except with -malign-double)
-    if conf.target.targetOS != osWindows:
-      if kind in {tyFloat64, tyFloat, tyInt, tyUInt, tyInt64, tyUInt64}:
-        # on i386 for all known POSIX systems, 64bits ints are aligned
-        # to 4bytes (except with -malign-double)
-        m.typ.align = 4
+  if kind in {tyFloat64, tyFloat, tyInt, tyUInt, tyInt64, tyUInt64} and size == 8:
+    m.typ.align = int16(conf.floatInt64Align)
 
 proc setMagicIntegral(conf: ConfigRef; m: PSym, kind: TTypeKind, size: int) =
   setMagicType(conf, m, kind, size)
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index 6028ba5ee..66b8ba1c9 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -7,6 +7,7 @@
 #
 ## code owner: Arne Döring
 ## e-mail: arne.doering@gmx.net
+## included from types.nim
 
 proc align(address, alignment: BiggestInt): BiggestInt =
   result = (address + (alignment - 1)) and not (alignment - 1)
@@ -14,7 +15,6 @@ proc align(address, alignment: BiggestInt): BiggestInt =
 proc align(address, alignment: int): int =
   result = (address + (alignment - 1)) and not (alignment - 1)
 
-
 const
   ## a size is concidered "unknown" when it is an imported type from C
   ## or C++.
@@ -39,6 +39,13 @@ proc inc(arg: var OffsetAccum; value: int) =
   else:
     arg.offset += value
 
+proc alignmentMax(a,b: int): int =
+  if unlikely(a == szIllegalRecursion or b == szIllegalRecursion):  raiseIllegalTypeRecursion()
+  if a == szUnknownSize or b == szUnknownSize:
+    szUnknownSize
+  else:
+    max(a,b)
+
 proc align(arg: var OffsetAccum; value: int) =
   if unlikely(value == szIllegalRecursion):  raiseIllegalTypeRecursion()
   if value == szUnknownSize or arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize:
@@ -48,11 +55,22 @@ proc align(arg: var OffsetAccum; value: int) =
     arg.maxAlign = max(value, arg.maxAlign)
     arg.offset = align(arg.offset, value)
 
-proc finish(arg: var OffsetAccum) =
+proc mergeBranch(arg: var OffsetAccum; value: OffsetAccum) =
+  if value.maxAlign == szUnknownSize or arg.maxAlign == szUnknownSize or
+     value.offset   == szUnknownSize or arg.offset == szUnknownSize:
+    arg.maxAlign = szUnknownSize
+    arg.offset = szUnknownSize
+  else:
+    arg.offset = max(arg.offset, value.offset)
+    arg.maxAlign = max(arg.maxAlign, value.maxAlign)
+
+proc finish(arg: var OffsetAccum): int =
   if arg.maxAlign == szUnknownSize or arg.offset == szUnknownSize:
+    result = szUnknownSize
     arg.offset = szUnknownSize
   else:
-    arg.offset = align(arg.offset, arg.maxAlign)
+    result = align(arg.offset, arg.maxAlign) - arg.offset
+    arg.offset += result
 
 proc computeSizeAlign(conf: ConfigRef; typ: PType)
 
@@ -93,154 +111,69 @@ proc setOffsetsToUnknown(n: PNode) =
     for i in 0 ..< safeLen(n):
       setOffsetsToUnknown(n[i])
 
-proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode,
-                                      initialOffset: BiggestInt): tuple[offset, align: BiggestInt] =
+proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, accum: var OffsetAccum): void =
   ## ``offset`` is the offset within the object, after the node has been written, no padding bytes added
   ## ``align`` maximum alignment from all sub nodes
   assert n != nil
   if n.typ != nil and n.typ.size == szIllegalRecursion:
-    result.offset = szIllegalRecursion
-    result.align = szIllegalRecursion
-    return
-
-  result.align = 1
+    raiseIllegalTypeRecursion()
   case n.kind
   of nkRecCase:
     assert(n.sons[0].kind == nkSym)
-    let (kindOffset, kindAlign) = computeObjectOffsetsFoldFunction(conf, n.sons[0], initialOffset)
-
-    var maxChildAlign: BiggestInt = if initialOffset == szUnknownSize: szUnknownSize else: 0
-    for i in 1 ..< sonsLen(n):
-      let child = n.sons[i]
-      case child.kind
-      of nkOfBranch, nkElse:
-        # offset parameter cannot be known yet, it needs to know the alignment first
-        let align = computeSubObjectAlign(conf, n.sons[i].lastSon)
-        if align == szIllegalRecursion:
-          result.offset = szIllegalRecursion
-          result.align = szIllegalRecursion
-          return
-        if align == szUnknownSize or maxChildAlign == szUnknownSize:
-          maxChildAlign = szUnknownSize
+    computeObjectOffsetsFoldFunction(conf, n.sons[0], packed, accum)
+    var maxChildAlign: int = if accum.offset == szUnknownSize: szUnknownSize else: 1
+    if not packed:
+      for i in 1 ..< sonsLen(n):
+        let child = n.sons[i]
+        case child.kind
+        of nkOfBranch, nkElse:
+          # offset parameter cannot be known yet, it needs to know the alignment first
+          let align = int(computeSubObjectAlign(conf, n.sons[i].lastSon))
+          maxChildAlign = alignmentMax(maxChildAlign, align)
         else:
-          maxChildAlign = max(maxChildAlign, align)
-      else:
-        internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)")
+          internalError(conf, "computeObjectOffsetsFoldFunction(record case branch)")
     if maxChildAlign == szUnknownSize:
       setOffsetsToUnknown(n)
-      result.align  = szUnknownSize
-      result.offset = szUnknownSize
+      accum.offset  = szUnknownSize
+      accum.maxAlign = szUnknownSize
     else:
       # the union neds to be aligned first, before the offsets can be assigned
-      let kindUnionOffset = align(kindOffset, maxChildAlign)
-      var maxChildOffset: BiggestInt = 0
+      accum.align(maxChildAlign)
+      let accumRoot = accum # copy, because each branch should start af the same offset
       for i in 1 ..< sonsLen(n):
-        let (offset, align) = computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset)
-        maxChildOffset = max(maxChildOffset, offset)
-      result.align = max(kindAlign, maxChildAlign)
-      result.offset = maxChildOffset
+        var branchAccum = accumRoot
+        computeObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, packed, branchAccum)
+        accum.mergeBranch(branchAccum)
   of nkRecList:
-    result.align = 1 # maximum of all member alignments
-    var offset = initialOffset
     for i, child in n.sons:
-      let (newOffset, align) = computeObjectOffsetsFoldFunction(conf, child, offset)
-      if newOffset == szIllegalRecursion:
-        result.offset = szIllegalRecursion
-        result.align = szIllegalRecursion
-        return
-      elif newOffset == szUnknownSize or offset == szUnknownSize:
-        # if anything is unknown, the rest becomes unknown as well
-        offset = szUnknownSize
-        result.align = szUnknownSize
-      else:
-        offset = newOffset
-        result.align = max(result.align, align)
-    # final alignment
-    if offset == szUnknownSize:
-      result.offset = szUnknownSize
-    else:
-      result.offset = align(offset, result.align)
+      computeObjectOffsetsFoldFunction(conf, child, packed, accum)
   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 initialOffset == szUnknownSize or size == szUnknownSize or align == szUnknownSize:
-      n.sym.offset = szUnknownSize
-      result.offset = szUnknownSize
-    else:
-      n.sym.offset = align(initialOffset, align).int
-      result.offset = n.sym.offset + n.sym.typ.size
+      align = if packed: 1 else: n.sym.typ.align.int
+    accum.align(align)
+    n.sym.offset = accum.offset
+    accum.inc(size)
   else:
-    result.align = szUnknownSize
-    result.offset = szUnknownSize
+    accum.maxAlign = szUnknownSize
+    accum.offset = szUnknownSize
 
-proc computePackedObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, initialOffset: BiggestInt, debug: bool): BiggestInt =
-  ## ``result`` is the offset within the object, after the node has been written, no padding bytes added
+proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var OffsetAccum) =
+  ## ``accum.offset`` will the offset from the larget member of the union.
   case n.kind
   of nkRecCase:
-    assert(n.sons[0].kind == nkSym)
-    let kindOffset = computePackedObjectOffsetsFoldFunction(conf, n.sons[0], initialOffset, debug)
-    # the union neds to be aligned first, before the offsets can be assigned
-    let kindUnionOffset = kindOffset
-    var maxChildOffset: BiggestInt = kindUnionOffset
-    for i in 1 ..< sonsLen(n):
-      let offset = computePackedObjectOffsetsFoldFunction(conf, n.sons[i].lastSon, kindUnionOffset, debug)
-      if offset == szIllegalRecursion:
-        return szIllegalRecursion
-      if offset == szUnknownSize or maxChildOffset == szUnknownSize:
-        maxChildOffset = szUnknownSize
-      else:
-        maxChildOffset = max(maxChildOffset, offset)
-    result = maxChildOffset
-  of nkRecList:
-    result = initialOffset
-    for i, child in n.sons:
-      result = computePackedObjectOffsetsFoldFunction(conf, child, result, debug)
-      if result == szIllegalRecursion:
-        break
-  of nkSym:
-    var size = szUnknownSize
-    if n.sym.bitsize == 0:
-      computeSizeAlign(conf, n.sym.typ)
-      size = n.sym.typ.size.int
-
-    if initialOffset == szUnknownSize or size == szUnknownSize:
-      n.sym.offset = szUnknownSize
-      result = szUnknownSize
-    else:
-      n.sym.offset = int(initialOffset)
-      result = initialOffset + n.sym.typ.size
-  else:
-    result = szUnknownSize
-
-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
+    accum.offset = szUnknownSize
+    accum.maxAlign = 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
+    let accumRoot = accum # copy, because each branch should start af the same offset
     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)
+      var branchAccum = accumRoot
+      computeUnionObjectOffsetsFoldFunction(conf, child, branchAccum)
+      accum.mergeBranch(branchAccum)
   of nkSym:
     var size = szUnknownSize
     var align = szUnknownSize
@@ -248,17 +181,12 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, debug: boo
       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
+    accum.align(align)
+    n.sym.offset = accum.offset
+    accum.inc(size)
   else:
-    result.offset = szUnknownSize
-    result.align = szUnknownSize
+    accum.maxAlign = szUnknownSize
+    accum.offset = szUnknownSize
 
 proc computeSizeAlign(conf: ConfigRef; typ: PType) =
   ## computes and sets ``size`` and ``align`` members of ``typ``
@@ -288,8 +216,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
   # mark computation in progress
   typ.size = szIllegalRecursion
   typ.align = szIllegalRecursion
-
-  var maxAlign, sizeAccum, length: BiggestInt
+  typ.paddingAtEnd = 0
 
   var tk = typ.kind
   case tk
@@ -299,26 +226,23 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     else:
       typ.size = conf.target.ptrSize
     typ.align = int16(conf.target.ptrSize)
-
   of tyNil:
     typ.size = conf.target.ptrSize
     typ.align = int16(conf.target.ptrSize)
-
   of tyString:
     if conf.selectedGC == gcDestructors:
       typ.size = conf.target.ptrSize * 2
     else:
       typ.size = conf.target.ptrSize
     typ.align = int16(conf.target.ptrSize)
-
   of tyCString, tySequence, tyPtr, tyRef, tyVar, tyLent, tyOpenArray:
     let base = typ.lastSon
     if base == typ:
       # this is not the correct location to detect ``type A = ptr A``
       typ.size = szIllegalRecursion
       typ.align = szIllegalRecursion
+      typ.paddingAtEnd = szIllegalRecursion
       return
-
     typ.align = int16(conf.target.ptrSize)
     if typ.kind == tySequence and conf.selectedGC == gcDestructors:
       typ.size = conf.target.ptrSize * 2
@@ -340,12 +264,13 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     computeSizeAlign(conf, base)
     typ.size = 0
     typ.align = base.align
+
   of tyEnum:
     if firstOrd(conf, typ) < Zero:
       typ.size = 4              # use signed int32
       typ.align = 4
     else:
-      length = toInt64(lastOrd(conf, typ))   # BUGFIX: use lastOrd!
+      let length = toInt64(lastOrd(conf, typ))   # BUGFIX: use lastOrd!
       if length + 1 < `shl`(1, 8):
         typ.size = 1
         typ.align = 1
@@ -357,30 +282,37 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
         typ.align = 4
       else:
         typ.size = 8
-        typ.align = 8
+        typ.align = int16(conf.floatInt64Align)
   of tySet:
     if typ.sons[0].kind == tyGenericParam:
       typ.size = szUncomputedSize
-      typ.align = szUncomputedSize # in original version this was 1
+      typ.align = szUncomputedSize
     else:
-      length = toInt64(lengthOrd(conf, typ.sons[0]))
+      let length = toInt64(lengthOrd(conf, typ.sons[0]))
       if length <= 8:
         typ.size = 1
+        typ.align = 1
       elif length <= 16:
         typ.size = 2
+        typ.align = 2
       elif length <= 32:
         typ.size = 4
+        typ.align = 4
       elif length <= 64:
         typ.size = 8
+        typ.align = int16(conf.floatInt64Align)
       elif align(length, 8) mod 8 == 0:
         typ.size = align(length, 8) div 8
+        typ.align = int16(conf.floatInt64Align)
       else:
         typ.size = align(length, 8) div 8 + 1
-    typ.align = int16(typ.size)
+        typ.align = int16(conf.floatInt64Align)
   of tyRange:
     computeSizeAlign(conf, typ.sons[0])
     typ.size = typ.sons[0].size
     typ.align = typ.sons[0].align
+    typ.paddingAtEnd = typ.sons[0].paddingAtEnd
+
   of tyTuple:
     try:
       var accum = OffsetAccum(maxAlign: 1)
@@ -392,112 +324,121 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
           let sym = typ.n[i].sym
           sym.offset = accum.offset
         accum.inc(int(child.size))
-      accum.finish
+      typ.paddingAtEnd = int16(accum.finish())
       typ.size = accum.offset
       typ.align = int16(accum.maxAlign)
     except IllegalTypeRecursionError:
+      typ.paddingAtEnd = szIllegalRecursion
       typ.size = szIllegalRecursion
       typ.align = szIllegalRecursion
+
   of tyObject:
-    var headerSize: BiggestInt
-    var headerAlign: int16
-    if typ.sons[0] != nil:
-      # compute header size
-      if conf.cmd == cmdCompileToCpp:
-        # if the target is C++ the members of this type are written
-        # into the padding byets at the end of the parent type. At the
-        # moment it is not supported to calculate that.
-        headerSize = szUnknownSize
-        headerAlign = szUncomputedSize
-      else:
-        var st = typ.sons[0]
-        while st.kind in skipPtrs:
-          st = st.sons[^1]
-        computeSizeAlign(conf, st)
-        if st.size == szIllegalRecursion:
-          typ.size = st.size
-          typ.align = st.align
-          return
-        headerSize = st.size
-        headerAlign = st.align
-    elif isObjectWithTypeFieldPredicate(typ):
-      # this branch is taken for RootObj
-      headerSize = conf.target.intSize
-      headerAlign = conf.target.intSize.int16
-    else:
-      headerSize = 0
-      headerAlign = 1
-    let (offset, align) =
+    try:
+      var accum =
+        if typ.sons[0] != nil:
+          # compute header size
+          var st = typ.sons[0]
+          while st.kind in skipPtrs:
+            st = st.sons[^1]
+          computeSizeAlign(conf, st)
+          if conf.cmd == cmdCompileToCpp:
+            OffsetAccum(
+              offset: int(st.size) - int(st.paddingAtEnd),
+              maxAlign: st.align
+            )
+          else:
+            OffsetAccum(
+              offset: int(st.size),
+              maxAlign: st.align
+            )
+        elif isObjectWithTypeFieldPredicate(typ):
+          # this branch is taken for RootObj
+          OffsetAccum(
+            offset: conf.target.intSize,
+            maxAlign: conf.target.intSize
+          )
+        else:
+          OffsetAccum(maxAlign: 1)
       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))
+          localError(conf, info, "union type may not be packed.")
+          accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize)
+        elif accum.offset != 0:
+          let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo()
+          localError(conf, info, "union type may not have an object header")
+          accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize)
         else:
-          computeUnionObjectOffsetsFoldFunction(conf, typ.n, false)
+          computeUnionObjectOffsetsFoldFunction(conf, typ.n, accum)
       elif tfPacked in typ.flags:
-        (computePackedObjectOffsetsFoldFunction(conf, typ.n, headerSize, false), BiggestInt(1))
+        accum.maxAlign = 1
+        computeObjectOffsetsFoldFunction(conf, typ.n, true, accum)
       else:
-        computeObjectOffsetsFoldFunction(conf, typ.n, headerSize)
-    if offset == szIllegalRecursion:
+        computeObjectOffsetsFoldFunction(conf, typ.n, false, accum)
+      let paddingAtEnd = int16(accum.finish())
+      if typ.sym != nil and
+         typ.sym.flags * {sfCompilerProc, sfImportc} == {sfImportc}:
+        typ.size = szUnknownSize
+        typ.align = szUnknownSize
+        typ.paddingAtEnd = szUnknownSize
+      else:
+        typ.size = accum.offset
+        typ.align = int16(accum.maxAlign)
+        typ.paddingAtEnd = paddingAtEnd
+    except IllegalTypeRecursionError:
       typ.size = szIllegalRecursion
       typ.align = szIllegalRecursion
-      return
-    if offset == szUnknownSize or (
-        typ.sym != nil and
-        typ.sym.flags * {sfCompilerProc, sfImportc} == {sfImportc}):
-      typ.size = szUnknownSize
-      typ.align = szUnknownSize
-      return
-    # header size is already in size from computeObjectOffsetsFoldFunction
-    # maxAlign is probably not changed at all from headerAlign
-    if tfPacked in typ.flags:
-      typ.size = offset
-      typ.align = 1
-    else:
-      typ.align = int16(max(align, headerAlign))
-      typ.size = align(offset, typ.align)
+      typ.paddingAtEnd = szIllegalRecursion
   of tyInferred:
     if typ.len > 1:
       computeSizeAlign(conf, typ.lastSon)
       typ.size = typ.lastSon.size
       typ.align = typ.lastSon.align
+      typ.paddingAtEnd = typ.lastSon.paddingAtEnd
 
   of tyGenericInst, tyDistinct, tyGenericBody, tyAlias, tySink, tyOwned:
     computeSizeAlign(conf, typ.lastSon)
     typ.size = typ.lastSon.size
     typ.align = typ.lastSon.align
+    typ.paddingAtEnd = typ.lastSon.paddingAtEnd
 
   of tyTypeClasses:
     if typ.isResolvedUserTypeClass:
       computeSizeAlign(conf, typ.lastSon)
       typ.size = typ.lastSon.size
       typ.align = typ.lastSon.align
+      typ.paddingAtEnd = typ.lastSon.paddingAtEnd
     else:
-      typ.size = szUncomputedSize
-      typ.align = szUncomputedSize
+      typ.size = szUnknownSize
+      typ.align = szUnknownSize
+      typ.paddingAtEnd = szUnknownSize
 
   of tyTypeDesc:
     computeSizeAlign(conf, typ.base)
     typ.size = typ.base.size
     typ.align = typ.base.align
+    typ.paddingAtEnd = typ.base.paddingAtEnd
 
   of tyForward:
     # is this really illegal recursion, or maybe just unknown?
     typ.size = szIllegalRecursion
     typ.align = szIllegalRecursion
+    typ.paddingAtEnd = szIllegalRecursion
 
   of tyStatic:
     if typ.n != nil:
       computeSizeAlign(conf, typ.lastSon)
       typ.size = typ.lastSon.size
       typ.align = typ.lastSon.align
+      typ.paddingAtEnd = typ.lastSon.paddingAtEnd
     else:
-      typ.size = szUncomputedSize
-      typ.align = szUncomputedSize
+      typ.size = szUnknownSize
+      typ.align = szUnknownSize
+      typ.paddingAtEnd = szUnknownSize
   else:
-    typ.size = szUncomputedSize
-    typ.align = szUncomputedSize
+    typ.size = szUnknownSize
+    typ.align = szUnknownSize
+    typ.paddingAtEnd = szUnknownSize
 
 template foldSizeOf*(conf: ConfigRef; n: PNode; fallback: PNode): PNode =
   let config = conf
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim
index 9cbe9aeb0..a4633021b 100644
--- a/tests/misc/tsizeof.nim
+++ b/tests/misc/tsizeof.nim
@@ -1,4 +1,5 @@
 discard """
+  targets: "c cpp"
   output: '''
 body executed
 body executed
@@ -7,6 +8,14 @@ macros api OK
 '''
 """
 
+# This is for travis. The keyword ``alignof`` only exists in ``c++11``
+# and newer. On travis gcc does not default to c++11 yet.
+when defined(cpp) and not defined(windows):
+  {.passC: "-std=c++11".}
+
+# Object offsets are different for inheritance objects when compiling
+# to c++.
+
 type
   TMyEnum = enum
     tmOne, tmTwo, tmThree, tmFour
@@ -143,6 +152,14 @@ type
     ValueA
     ValueB
 
+  # Must have more than 32 elements so that set[MyEnum33] will become compile to an int64.
+  MyEnum33 {.pure.} = enum
+    Value1, Value2, Value3, Value4, Value5, Value6,
+    Value7, Value8, Value9, Value10, Value11, Value12,
+    Value13, Value14, Value15, Value16, Value17, Value18,
+    Value19, Value20, Value21, Value22, Value23, Value24,
+    Value25, Value26, Value27, Value28, Value29, Value30,
+    Value31, Value32, Value33
 
 proc transformObjectconfigPacked(arg: NimNode): NimNode =
   let debug = arg.kind == nnkPragmaExpr
@@ -296,6 +313,10 @@ testinstance:
         b: int8
       c: int8
 
+    PaddingOfSetEnum33 = object
+      cause: int8
+      theSet: set[MyEnum33]
+
     Bazing {.objectconfig.} = object of RootObj
       a: int64
       # TODO test on 32 bit system
@@ -328,6 +349,7 @@ testinstance:
     var g : RecursiveStuff
     var ro : RootObj
     var go : GenericObject[int64]
+    var po : PaddingOfSetEnum33
 
     var
       e1: Enum1
@@ -346,16 +368,16 @@ testinstance:
     else:
       doAssert sizeof(SimpleAlignment) > 10
 
-    testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go, e1, e2, e4, e8, eoa, eob)
+    testSizeAlignOf(t,a,b,c,d,e,f,g,ro,go,po, e1, e2, e4, e8, eoa, eob)
 
-    when not defined(cpp):
-      type
-        WithBitsize {.objectconfig.} = object
-          bitfieldA {.bitsize: 16.}: uint32
-          bitfieldB {.bitsize: 16.}: uint32
 
-      var wbs: WithBitsize
-      testSize(wbs)
+    type
+      WithBitsize {.objectconfig.} = object
+        bitfieldA {.bitsize: 16.}: uint32
+        bitfieldB {.bitsize: 16.}: uint32
+
+    var wbs: WithBitsize
+    testSize(wbs)
 
     testOffsetOf(TrivialType, x)
     testOffsetOf(TrivialType, y)
@@ -383,11 +405,13 @@ testinstance:
 
     testOffsetOf(Foobar, c)
 
-    when not defined(cpp):
-      testOffsetOf(Bazing, a)
-      testOffsetOf(InheritanceA, a)
-      testOffsetOf(InheritanceB, b)
-      testOffsetOf(InheritanceC, c)
+    testOffsetOf(PaddingOfSetEnum33, cause)
+    testOffsetOf(PaddingOfSetEnum33, theSet)
+
+    testOffsetOf(Bazing, a)
+    testOffsetOf(InheritanceA, a)
+    testOffsetOf(InheritanceB, b)
+    testOffsetOf(InheritanceC, c)
 
     testOffsetOf(EnumObjectA, a)
     testOffsetOf(EnumObjectA, b)
@@ -620,9 +644,6 @@ doAssert offsetof(MyPackedCaseObject, val4) == 9
 doAssert offsetof(MyPackedCaseObject, val5) == 13
 
 reject:
-  const off4 = offsetof(MyPackedCaseObject, val1)
-
-reject:
   const off5 = offsetof(MyPackedCaseObject, val2)
 
 reject: