From 66db9de714be7c2f4cf1f2fb0a0a99145baf6acb Mon Sep 17 00:00:00 2001 From: Timothee Cour Date: Thu, 23 Apr 2020 02:24:09 -0700 Subject: CT sizeof(+friends) for {.importc, completeStruct.} types, enable ABI static checks (#13926) * -d:checkabi obsolete (ABI check now enforced); add `addTypeHeader` helper * cleanups * import sizeof at CT for {.completeType.} * address comments; revert default enabling of -d:checkAbi for now * mimportc_size_check.nim => msizeof5.nim; merge mabi_check.nim into msizeof5.nim; refactor * all pragmas in errmsgs should be written: '.importc' (un-ambiguous and less verbose than {.importc.}) --- tests/misc/msizeof5.nim | 131 ++++++++++++++++++++++++++++++++++++++++++++++++ tests/misc/tsizeof2.nim | 2 +- tests/trunner.nim | 42 +++++++++++----- 3 files changed, 161 insertions(+), 14 deletions(-) create mode 100644 tests/misc/msizeof5.nim (limited to 'tests') diff --git a/tests/misc/msizeof5.nim b/tests/misc/msizeof5.nim new file mode 100644 index 000000000..c833d1e43 --- /dev/null +++ b/tests/misc/msizeof5.nim @@ -0,0 +1,131 @@ +## tests for -d:checkAbi used by addAbiCheck via NIM_STATIC_ASSERT + +{.emit:"""/*TYPESECTION*/ +struct Foo1{ + int a; +}; +struct Foo2{ + int a; +}; +enum Foo3{k1, k2}; +typedef enum Foo3 Foo3b; +typedef enum Foo4{k3, k4} Foo4; + +typedef int Foo5[3]; + +typedef struct Foo6{ + int a1; + bool a2; + double a3; + struct Foo6* a4; +} Foo6; +""".} + +template ensureCgen(T: typedesc) = + ## ensures cgen + var a {.volatile.}: T + +block: + type Foo1Alias{.importc: "struct Foo1", size: sizeof(cint).} = object + a: cint + ensureCgen Foo1Alias + +block: + type Foo3Alias{.importc: "enum Foo3", size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3Alias + +block: + type Foo3bAlias{.importc: "Foo3b", size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3bAlias + +block: + type Foo3b{.importc, size: sizeof(cint).} = enum + k1, k2 + ensureCgen Foo3b + static: + doAssert Foo3b.sizeof == cint.sizeof + +block: + type Foo4{.importc, size: sizeof(cint).} = enum + k3, k4 + # adding entries should not yield duplicate ABI checks, as enforced by + # `typeABICache`. + # Currently the test doesn't check for this but you can inspect the cgen'd file + ensureCgen Foo4 + ensureCgen Foo4 + ensureCgen Foo4 + +block: + type Foo5{.importc.} = array[3, cint] + ensureCgen Foo5 + +block: + type Foo5{.importc.} = array[3, cint] + ensureCgen Foo5 + +block: # CT sizeof + type Foo6GT = object # grountruth + a1: cint + a2: bool + a3: cfloat + a4: ptr Foo6GT + + type Foo6{.importc, completeStruct.} = object + a1: cint + a2: bool + a3: cfloat + a4: ptr Foo6 + + static: doAssert compiles(static(Foo6.sizeof)) + static: doAssert Foo6.sizeof == Foo6GT.sizeof + static: doAssert (Foo6, int, array[2, Foo6]).sizeof == + (Foo6GT, int, array[2, Foo6GT]).sizeof + +block: + type GoodImportcType {.importc: "signed char", nodecl.} = char + # "good" in sense the sizeof will match + ensureCgen GoodImportcType + +block: + type Foo6{.importc.} = object + a1: cint + doAssert compiles(Foo6.sizeof) + static: doAssert not compiles(static(Foo6.sizeof)) + +when defined caseBad: + # Each case below should give a static cgen assert fail message + + block: + type BadImportcType {.importc: "unsigned char", nodecl.} = uint64 + # "sizeof" check will fail + ensureCgen BadImportcType + + block: + type Foo2AliasBad{.importc: "struct Foo2", size: 1.} = object + a: cint + ensureCgen Foo2AliasBad + + block: + type Foo5{.importc.} = array[4, cint] + ensureCgen Foo5 + + block: + type Foo5{.importc.} = array[3, bool] + ensureCgen Foo5 + + block: + type Foo6{.importc, completeStruct.} = object + a1: cint + # a2: bool # missing this should trigger assert fail + a3: cfloat + a4: ptr Foo6 + ensureCgen Foo6 + + when false: + block: + # pre-existing BUG: this should give a CT error in semcheck because `size` + # disagrees with `array[3, cint]` + type Foo5{.importc, size: 1.} = array[3, cint] + ensureCgen Foo5 diff --git a/tests/misc/tsizeof2.nim b/tests/misc/tsizeof2.nim index a193cf7c3..da28de508 100644 --- a/tests/misc/tsizeof2.nim +++ b/tests/misc/tsizeof2.nim @@ -1,5 +1,5 @@ discard """ -errormsg: "cannot evaluate 'sizeof' because its type is not defined completely" +errormsg: "'sizeof' requires '.importc' types to be '.completeStruct'" line: 9 """ diff --git a/tests/trunner.nim b/tests/trunner.nim index 7e1468e84..263184571 100644 --- a/tests/trunner.nim +++ b/tests/trunner.nim @@ -19,14 +19,10 @@ proc runCmd(file, options = ""): auto = echo result[0] echo result[1] -proc testCodegenStaticAssert() = - let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim") - doAssert "sizeof(bool) == 2" in output - doAssert exitCode != 0 - -proc testCTFFI() = - let (output, exitCode) = runCmd("vm/mevalffi.nim", "--experimental:compiletimeFFI") - let expected = """ +when defined(nimHasLibFFIEnabled): + block: # mevalffi + let (output, exitCode) = runCmd("vm/mevalffi.nim", "--experimental:compiletimeFFI") + let expected = """ hello world stderr hi stderr foo @@ -37,10 +33,30 @@ foo:102:103:104 foo:0.03:asdf:103:105 ret={s1:foobar s2:foobar age:25 pi:3.14} """ - doAssert output == expected, output - doAssert exitCode == 0 + doAssert output == expected, output + doAssert exitCode == 0 -when defined(nimHasLibFFIEnabled): - testCTFFI() else: # don't run twice the same test - testCodegenStaticAssert() + template check(msg) = doAssert msg in output, output + + block: # mstatic_assert + let (output, exitCode) = runCmd("ccgbugs/mstatic_assert.nim", "-d:caseBad") + check "sizeof(bool) == 2" + doAssert exitCode != 0 + + block: # ABI checks + let file = "misc/msizeof5.nim" + block: + let (output, exitCode) = runCmd(file, "-d:checkAbi") + doAssert exitCode == 0, output + block: + let (output, exitCode) = runCmd(file, "-d:checkAbi -d:caseBad") + # on platforms that support _StaticAssert natively, errors will show full context, eg: + # error: static_assert failed due to requirement 'sizeof(unsigned char) == 8' + # "backend & Nim disagree on size for: BadImportcType{int64} [declared in mabi_check.nim(1, 6)]" + check "sizeof(unsigned char) == 8" + check "sizeof(struct Foo2) == 1" + check "sizeof(Foo5) == 16" + check "sizeof(Foo5) == 3" + check "sizeof(struct Foo6) == " + doAssert exitCode != 0 -- cgit 1.4.1-2-gfad0