diff options
author | Andreas Rumpf <rumpf_a@web.de> | 2019-08-28 19:36:29 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-08-28 19:36:29 +0200 |
commit | 21fc8b4d4d82637fab831cffed0e5b995ec7f16c (patch) | |
tree | 6b0e4c27180e89df77e4979daa463585ec81c0a6 | |
parent | 42d2e68bca2d7fce65591ed7c4697ed1ecf86026 (diff) | |
download | Nim-21fc8b4d4d82637fab831cffed0e5b995ec7f16c.tar.gz |
refactor sizealignoffset (#12077)
* small refactoring * refactor computeObjectOffsetFoldFunction with AccumObject * refactor packed object offstes fold function * refactor compute union object offsets fold function * merge normal/packed object offset fold function * compiletime offsetof in c++ inheritance objects * enable c++ inheritance offsetof tests * correct alignment for big sets/enums on weird 32bit platforms * uncomputedSize -> unknownSize * workaround for travis * fixes win32 alignment problems
-rw-r--r-- | compiler/ast.nim | 1 | ||||
-rw-r--r-- | compiler/options.nim | 10 | ||||
-rw-r--r-- | compiler/pragmas.nim | 10 | ||||
-rw-r--r-- | compiler/semtypes.nim | 9 | ||||
-rw-r--r-- | compiler/sizealignoffsetimpl.nim | 343 | ||||
-rw-r--r-- | tests/misc/tsizeof.nim | 53 |
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: |