-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CT sizeof(+friends) for {.importc, completeStruct.} types, enable ABI static checks #13926
Conversation
I love the additional static checks but I wonder why you picked this solution over simply expanding what we already have with |
4c5ef53
to
a377816
Compare
as explained in detail in timotheecour#97, in all of stdlib, there are only 2 types marked as incompleteStruct: yet, as you can see with timotheecour#97, almost all types I tried are in fact incomplete:
Dirent struct dirent => 272 vs 1048
Tflock struct flock => 32 vs 24
Glob glob_t => 24 vs 88
Group struct group => 24 vs 32
Ipc_perm struct ipc_perm => 20 vs 24
Stat struct stat => 104 vs 144
Statvfs struct statvfs => 88 vs 64 |
…izeof5.nim; refactor
…d less verbose than {.importc.})
…o subsequent PRs)
Well... ok I guess but then why do we need |
what you're suggesting cannot work. This would generate distinct types, causing all sorts of problems.
in C++ this would simply not work at all, even without overloads or templates, you can't implicitly convert; # in t10533.nim
when true:
const header = "t10533_case5.h"
{.compile: "t10533_case5.cpp".}
type Foo = object # BUG
# type Foo {.importc, header: header.} = object # this would work
x: cint
y: cint
proc fun1(a: ptr Foo) {.importc, header: header.}
var a = Foo(x: 12, y: 13)
fun1(a.addr)
# in t10533_case5.cpp
#include "t10533_case5.h"
extern "C"{ void fun1(Foo* a){} }
# in t10533_case5.h
extern "C"{
typedef struct Foo{
int x;
int y;
} Foo;
void fun1(Foo* a);
} would error:
and then there are other issues for C as well, eg ndi maps, debugging etc where the same |
Even if it would work. It is dangerous to do so. If you cut the ties to the original C declaration, it isn't possible to add static checks anymore to ensure that both C and Nim share the same stuct definition/layout. I have to side with @timotheecour here. Imported types are by default incomplete. That is the assumption in sizeof/alignof computation as well. A lot of code has been written this way. I wrote my wrappers this way. If you change this, it is a breaking chage. The @timotheecour you should also enable an specifing the size for a struct reuses the size pragma that is used for enums as well. Please add some checks that you don't break anything for enums. Please also add a test that if you only specify the size of a struct, that the aligment field isn't also set, (unlike enums, where the alignment is inherited from integer aligment). Also it would be beneficial if you add a simple check that ensures that alignment values are a power of 2 and the size is a multiple of the alignment. These are just sanity checks to catch compilation errors before the C compilation stage. |
a14ecbb
to
691e2b1
Compare
Yeah, uhm, that's what I tried to say too, I agree with you. I'm confused. Will think about it. |
Merging, but this needs a changelog entry and needs to be documented well. |
on my TODO list static_assert can also check for alignof (etc) indeed; should be done in future PR's |
marking as WIP only because I need to handle failures resulting from ABI checks (which are legit), but ready for review apart from that
$
, {.sizeof.}, const CVAR {.importc.}: int RFCs#205 with a minor modification: using{.completeStruct.}
instead of 0-argument{.sizeof.}
as it's more self documenting and{.sizeof.}
was a bit of a misnomer given that offsetof and alignof are involved too.{.importc, completeStruct.}
type, we can now compute sizeof, alignof, offsetof at CT. sizeof is checked at cgen CT (ABI static check){.importc.}
type, CT sizeof(etc) still gives CT errorcgen ABI checks give user friendly errors to make debugging easy, 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)]"
(see tests where declaration comes from; it shows both C name (unsigned char), nim type name (BadImportcType) and resolved type name (int64), and declaration location{.emit.}
now goes in sectionNIM_merge_EMITS
right aboveNIM_merge_TYPE_INFO
(unless user overrides with{.emit:"""/*TYPESECTION*/....}
as usual), instead of on top ofNIM_merge_PROC_HEADERS
which is right afterNIM_merge_TYPE_INFO
; this makes sense because ABI static checks (which is whatNIM_merge_TYPE_INFO
contains) should appear after type declarations in emit sections.-d:checkAbi
is now enabled by default thanks to the portable macro NIM_STATIC_ASSERT introduced in fix some codegen bugs: NIM_BOOL, NIM_STATIC_ASSERT, --passc:-std=... (etc) #13798see tests for more examples, but the following would trigger cgen static asserts (with human friendly errors):
semi related
(intentionally left as is instead of
DATA
etc which is less searchable when figuring out where it comes from in compiler code)benefits of static checks
this PR actually finds a number of pre-existing errors where compiler is wrong about size of certain types, which can lead to bugs