allow packed union (#14868)

Co-authored-by: Arne Döring <arne.doering@gmx.net>
This commit is contained in:
Clyybber 2020-07-01 11:41:03 +02:00 • committed by GitHub
commit 1440e70c62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 9 deletions

View file

@ -164,7 +164,7 @@ proc computeObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode, packed: bool, a
accum.maxAlign = szUnknownSize accum.maxAlign = szUnknownSize
accum.offset = szUnknownSize accum.offset = szUnknownSize
proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var OffsetAccum) = proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; packed: bool; accum: var OffsetAccum) =
## ``accum.offset`` will the offset from the larget member of the union. ## ``accum.offset`` will the offset from the larget member of the union.
case n.kind case n.kind
of nkRecCase: of nkRecCase:
@ -175,7 +175,7 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var
let accumRoot = accum # copy, because each branch should start af the same offset let accumRoot = accum # copy, because each branch should start af the same offset
for i, child in n.sons: for i, child in n.sons:
var branchAccum = accumRoot var branchAccum = accumRoot
computeUnionObjectOffsetsFoldFunction(conf, child, branchAccum) computeUnionObjectOffsetsFoldFunction(conf, child, packed, branchAccum)
accum.mergeBranch(branchAccum) accum.mergeBranch(branchAccum)
of nkSym: of nkSym:
var size = szUnknownSize var size = szUnknownSize
@ -183,7 +183,7 @@ proc computeUnionObjectOffsetsFoldFunction(conf: ConfigRef; n: PNode; accum: var
if n.sym.bitsize == 0: # 0 represents bitsize not set if n.sym.bitsize == 0: # 0 represents bitsize not set
computeSizeAlign(conf, n.sym.typ) computeSizeAlign(conf, n.sym.typ)
size = n.sym.typ.size.int size = n.sym.typ.size.int
align = n.sym.typ.align.int align = if packed: 1 else: n.sym.typ.align.int
accum.align(align) accum.align(align)
if n.sym.alignment > 0: if n.sym.alignment > 0:
accum.align(n.sym.alignment) accum.align(n.sym.alignment)
@ -365,16 +365,14 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
else: else:
OffsetAccum(maxAlign: 1) OffsetAccum(maxAlign: 1)
if tfUnion in typ.flags: if tfUnion in typ.flags:
if tfPacked in typ.flags: if accum.offset != 0:
let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo
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 let info = if typ.sym != nil: typ.sym.info else: unknownLineInfo
localError(conf, info, "union type may not have an object header") localError(conf, info, "union type may not have an object header")
accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize) accum = OffsetAccum(offset: szUnknownSize, maxAlign: szUnknownSize)
elif tfPacked in typ.flags:
computeUnionObjectOffsetsFoldFunction(conf, typ.n, true, accum)
else: else:
computeUnionObjectOffsetsFoldFunction(conf, typ.n, accum) computeUnionObjectOffsetsFoldFunction(conf, typ.n, false, accum)
elif tfPacked in typ.flags: elif tfPacked in typ.flags:
accum.maxAlign = 1 accum.maxAlign = 1
computeObjectOffsetsFoldFunction(conf, typ.n, true, accum) computeObjectOffsetsFoldFunction(conf, typ.n, true, accum)

View file

@ -694,3 +694,13 @@ type
doAssert sizeof(O0) == 1 doAssert sizeof(O0) == 1
doAssert sizeof(T0) == 1 doAssert sizeof(T0) == 1
type
# this thing may not have padding bytes at the end
PackedUnion* {.union, packed.} = object
a*: array[11, byte]
b*: int64
doAssert sizeof(PackedUnion) == 11
doAssert alignof(PackedUnion) == 1