diff options
author | Timothee Cour <timothee.cour2@gmail.com> | 2018-10-13 15:52:28 -0700 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2018-10-14 00:52:28 +0200 |
commit | 745f1642d6faf3a30543cd76196a7462d7460d6d (patch) | |
tree | c94ae73ba3e662a2c873aa8c9a85654c3aa3bbc4 /tests | |
parent | 3e2d8c1c535d75d3451ce016e7b54cb609c01e45 (diff) | |
download | Nim-745f1642d6faf3a30543cd76196a7462d7460d6d.tar.gz |
implement sizeof and alignof operator (manually squashed #5664) (#9356)
Diffstat (limited to 'tests')
-rw-r--r-- | tests/misc/tsizeof.nim | 348 | ||||
-rw-r--r-- | tests/misc/tsizeof2.nim | 11 | ||||
-rw-r--r-- | tests/types/tillegalrecursion3.nim | 12 |
3 files changed, 360 insertions, 11 deletions
diff --git a/tests/misc/tsizeof.nim b/tests/misc/tsizeof.nim index 0597535f9..ecdd44fca 100644 --- a/tests/misc/tsizeof.nim +++ b/tests/misc/tsizeof.nim @@ -1,14 +1,8 @@ discard """ - file: "tsize.nim" - output: "40 3 12 32" + output: "OK" """ -type - TMyRecord {.final.} = object - x, y: int - b: bool - r: float - s: string +type TMyEnum = enum tmOne, tmTwo, tmThree, tmFour @@ -16,13 +10,345 @@ type TMyArray2 = array[1..3, int32] TMyArray3 = array[TMyEnum, float64] -const +const mysize1 = sizeof(TMyArray1) mysize2 = sizeof(TMyArray2) mysize3 = sizeof(TMyArray3) -write(stdout, sizeof(TMyRecord)) -echo ' ', mysize1, ' ', mysize2, ' ',mysize3 +assert mysize1 == 3 +assert mysize2 == 12 +assert mysize3 == 32 + +import macros, typetraits + +macro testSizeAlignOf(args: varargs[untyped]): untyped = + result = newStmtList() + for arg in args: + result.add quote do: + let + c_size = c_sizeof(`arg`) + nim_size = sizeof(`arg`) + c_align = c_alignof(type(`arg`)) + nim_align = alignof(`arg`) + + if nim_size != c_size or nim_align != c_align: + var msg = strAlign(`arg`.type.name & ": ") + if nim_size != c_size: + msg.add " size(got, expected): " & $nim_size & " != " & $c_size + if nim_align != c_align: + msg.add " align(get, expected): " & $nim_align & " != " & $c_align + echo msg + + +macro testOffsetOf(a,b1,b2: untyped): untyped = + let typeName = newLit(a.repr) + let member = newLit(b2.repr) + result = quote do: + let + c_offset = c_offsetof(`a`,`b1`) + nim_offset = offsetof(`a`,`b2`) + if c_offset != nim_offset: + echo `typeName`, ".", `member`, " offset: ", c_offset, " != ", nim_offset + +template testOffsetOf(a,b: untyped): untyped = + testOffsetOf(a,b,b) + +proc strAlign(arg: string): string = + const minLen = 22 + result = arg + for i in 0 ..< minLen - arg.len: + result &= ' ' + +macro c_offsetof(a: typed, b: untyped): int32 = + ## Buffet 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)) + result = quote do: + var res: int32 + {.emit: [res, " = offsetof(", `a`, ", ", `bliteral`, ");"] .} + res + +macro c_sizeof(a: typed): int32 = + ## Buffet proof implementation that works using the sizeof operator + ## in the c backend. Assuming of course this implementation is + ## correct. + result = quote do: + var res: int32 + {.emit: [res, " = sizeof(", `a`, ");"] .} + res + +macro c_alignof(arg: untyped): untyped = + ## Buffet proof implementation that works on actual alignment + ## behavior measured at runtime. + let typeSym = genSym(nskType, "AlignTestType"&arg.repr) + result = quote do: + type + `typeSym` = object + causeAlign: byte + member: `arg` + c_offsetof(`typeSym`, member) + +macro testAlign(arg:untyped):untyped = + let prefix = newLit(arg.lineinfo & " alignof " & arg.repr & " ") + result = quote do: + let cAlign = c_alignof(`arg`) + let nimAlign = alignof(`arg`) + if cAlign != nimAlign: + echo `prefix`, cAlign, " != ", nimAlign + +testAlign(pointer) +testAlign(int) +testAlign(uint) +testAlign(int8) +testAlign(int16) +testAlign(int32) +testAlign(int64) +testAlign(uint8) +testAlign(uint16) +testAlign(uint32) +testAlign(uint64) +testAlign(float) +testAlign(float32) +testAlign(float64) + +type + MyEnum {.pure.} = enum + ValueA + ValueB + ValueC + + OtherEnum {.pure, size: 8.} = enum + ValueA + ValueB + + Enum1 {.pure, size: 1.} = enum + ValueA + ValueB + + Enum2 {.pure, size: 2.} = enum + ValueA + ValueB + + Enum4 {.pure, size: 4.} = enum + ValueA + ValueB + + Enum8 {.pure, size: 8.} = enum + ValueA + ValueB + +testAlign(MyEnum) +testAlign(OtherEnum) +testAlign(Enum1) +testAlign(Enum2) +testAlign(Enum4) +testAlign(Enum8) + + +template testinstance(body: untyped): untyped = + block: + {.pragma: objectconfig.} + body + + block: + {.pragma: objectconfig, packed.} + body + +testinstance: + type + + EnumObjectA {.objectconfig.} = object + a : Enum1 + b : Enum2 + c : Enum4 + d : Enum8 + + EnumObjectB {.objectconfig.} = object + a : Enum8 + b : Enum4 + c : Enum2 + d : Enum1 + + TrivialType {.objectconfig.} = object + x,y,z: int8 + + SimpleAlignment {.objectconfig.} = object + # behaves differently on 32bit Windows and 32bit Linux + a,b: int8 + c: int64 + + AlignAtEnd {.objectconfig.} = object + a: int64 + b,c: int8 + + SimpleBranch {.objectconfig.} = object + case kind: MyEnum + of MyEnum.ValueA: + a: int16 + of MyEnum.ValueB: + b: int32 + of MyEnum.ValueC: + c: int64 + + PaddingBeforeBranchA {.objectconfig.} = object + cause: int8 + case kind: MyEnum + of MyEnum.ValueA: + a: int16 + of MyEnum.ValueB: + b: int32 + of MyEnum.ValueC: + c: int64 + + PaddingBeforeBranchB {.objectconfig.} = object + cause: int8 + case kind: MyEnum + of MyEnum.ValueA: + a: int8 + of MyEnum.ValueB: + b: int16 + of MyEnum.ValueC: + c: int32 + + PaddingAfterBranch {.objectconfig.} = object + case kind: MyEnum + of MyEnum.ValueA: + a: int8 + of MyEnum.ValueB: + b: int16 + of MyEnum.ValueC: + c: int32 + cause: int64 + + RecursiveStuff {.objectconfig.} = object + case kind: MyEnum # packedOffset: 0 + of MyEnum.ValueA: # packedOffset: + a: int16 # packedOffset: 1 + of MyEnum.ValueB: # packedOffset: + b: int32 # packedOffset: 1 + of MyEnum.ValueC: # packedOffset: + case kind2: MyEnum # packedOffset: 1 + of MyEnum.ValueA: # packedOffset: + ca1: int8 + ca2: int32 + of MyEnum.ValueB: # packedOffset: + cb: int32 # packedOffset: 2 + of MyEnum.ValueC: # packedOffset: + cc: int64 # packedOffset: 2 + d1: int8 + d2: int64 + + Foobar {.objectconfig.} = object + case kind: OtherEnum + of OtherEnum.ValueA: + a: uint8 + of OtherEnum.ValueB: + b: int8 + c: int8 + + Bazing {.objectconfig.} = object of RootObj + a: int64 + # TODO test on 32 bit system + # only there the object header is smaller than the first member + + InheritanceA {.objectconfig.} = object of RootObj + a: char + + InheritanceB {.objectconfig.} = object of InheritanceA + b: char + + InheritanceC {.objectconfig.} = object of InheritanceB + c: char + + #Float128Test = object + # a: byte + # b: float128 + + #Bazang = object of RootObj + # a: float128 + + const trivialSize = sizeof(TrivialType) # needs to be able to evaluate at compile time + + testAlign(SimpleAlignment) + + proc main(): void = + var t : TrivialType + var a : SimpleAlignment + var b : AlignAtEnd + var c : SimpleBranch + var d : PaddingBeforeBranchA + var e : PaddingBeforeBranchB + var f : PaddingAfterBranch + var g : RecursiveStuff + var ro : RootObj + var + e1: Enum1 + e2: Enum2 + e4: Enum4 + e8: Enum8 + var + eoa: EnumObjectA + eob: EnumObjectB + + testSizeAlignOf(t,a,b,c,d,e,f,g,ro, e1, e2, e4, e8, eoa, eob) + + testOffsetOf(TrivialType, x) + testOffsetOf(TrivialType, y) + testOffsetOf(TrivialType, z) + + testOffsetOf(SimpleAlignment, a) + testOffsetOf(SimpleAlignment, b) + testOffsetOf(SimpleAlignment, c) + testOffsetOf(AlignAtEnd, a) + testOffsetOf(AlignAtEnd, b) + testOffsetOf(AlignAtEnd, c) + + testOffsetOf(SimpleBranch, "_Ukind", a) + testOffsetOf(SimpleBranch, "_Ukind", b) + testOffsetOf(SimpleBranch, "_Ukind", c) + + testOffsetOf(PaddingBeforeBranchA, cause) + testOffsetOf(PaddingBeforeBranchA, "_Ukind", a) + testOffsetOf(PaddingBeforeBranchB, cause) + testOffsetOf(PaddingBeforeBranchB, "_Ukind", a) + + testOffsetOf(PaddingAfterBranch, "_Ukind", a) + testOffsetOf(PaddingAfterBranch, cause) + + testOffsetOf(Foobar, c) + + testOffsetOf(Bazing, a) + + testOffsetOf(InheritanceA, a) + testOffsetOf(InheritanceB, b) + testOffsetOf(InheritanceC, c) + + testOffsetOf(EnumObjectA, a) + testOffsetOf(EnumObjectA, b) + testOffsetOf(EnumObjectA, c) + testOffsetOf(EnumObjectA, d) + testOffsetOf(EnumObjectB, a) + testOffsetOf(EnumObjectB, b) + testOffsetOf(EnumObjectB, c) + testOffsetOf(EnumObjectB, d) + + testOffsetOf(RecursiveStuff, kind) + testOffsetOf(RecursiveStuff, "_Ukind.S1.a", a) + testOffsetOf(RecursiveStuff, "_Ukind.S2.b", b) + testOffsetOf(RecursiveStuff, "_Ukind.S3.kind2", kind2) + testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S1.ca1", ca1) + testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S1.ca2", ca2) + testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S2.cb", cb) + testOffsetOf(RecursiveStuff, "_Ukind.S3._Ukind2.S3.cc", cc) + testOffsetOf(RecursiveStuff, "_Ukind.S3.d1", d1) + testOffsetOf(RecursiveStuff, "_Ukind.S3.d2", d2) + main() +echo "OK" diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim new file mode 100644 index 000000000..67379871d --- /dev/null +++ b/tests/misc/tsizeof2.nim @@ -0,0 +1,11 @@ +discard """ +errormsg: "cannot evaluate 'sizeof/alignof' because its type is not defined completely" +line: 9 +""" + +type + MyStruct {.importc: "MyStruct".} = object + +const i = sizeof(MyStruct) + +echo i diff --git a/tests/types/tillegalrecursion3.nim b/tests/types/tillegalrecursion3.nim new file mode 100644 index 000000000..fb5c1641c --- /dev/null +++ b/tests/types/tillegalrecursion3.nim @@ -0,0 +1,12 @@ +discard """ + errormsg: "illegal recursion in type 'Foo'" +""" + +type + Imported {.importc.} = object + + Foo = object + b: Imported + a: Foo + +var myFoo: Foo |