From ef3fc7f583927e0e2be275334a43519ec24f1e5f Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Tue, 24 Aug 2021 22:22:34 -0700 Subject: [PATCH] zero size structs with extern (C) attribute --- spec/struct.dd | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spec/struct.dd b/spec/struct.dd index 0ad679c609..e1f7ae02fa 100644 --- a/spec/struct.dd +++ b/spec/struct.dd @@ -169,7 +169,9 @@ $(H2 $(LNAME2 struct_layout, Struct Layout)) the first field and the start of the object. ) - $(P Structs with no fields of non-zero size (aka $(I Empty Structs)) have a size of one byte.) + $(P A struct with no fields of non-zero size is an $(I Empty Struct). + An Empty Struct with a $(DDSUBLINK spec/attribute, linkage, Linkage Attribute) of `extern (C)` has a size of zero. + Otherwise, its size is one byte.) $(P Non-static $(RELATIVE_LINK2 nested, function-nested D structs), which access the context of their enclosing scope, have an extra field. @@ -179,20 +181,22 @@ $(H2 $(LNAME2 struct_layout, Struct Layout)) $(OL $(LI The default layout of the fields of a struct is an exact match with the $(I associated C compiler).) - $(LI g++ and clang++ differ in how empty structs are handled. Both return `1` from `sizeof`, + $(LI g++ and clang++ differ in how Empty Structs are handled. Both return `1` from `sizeof`, however, clang++ does not push them onto the parameter stack while g++ does. This is a binary incompatibility between g++ and clang++. dmd follows clang++ behavior for OSX and FreeBSD, and g++ behavior for Linux and other Posix platforms. ) - $(LI clang and gcc both return `0` from `sizeof` for empty structs. Using `extern "C++"` - in clang++ and g++ does not cause them to conform to the behavior of their respective C compilers.) + $(LI C compilers normally evaluate `sizeof` applied to Empty Structs as `0`, although it + is undefined behavior according to the C11 6.7.2.1-8 Standard. + C++ compilers normally evaluate the size as `1`, even if `extern "C"` is applied. + ) )) $(UNDEFINED_BEHAVIOR $(OL $(LI The padding data can be accessed, but its contents are undefined.) - $(LI Do not pass or return structs with no fields of non-zero size to `extern (C)` functions. + $(LI Do not pass or return Empty Structs to `extern (C)` functions. According to C11 6.7.2.1p8 this is undefined behavior.) )) @@ -202,8 +206,7 @@ $(H2 $(LNAME2 struct_layout, Struct Layout)) attributes to describe an exact match. Using a $(DDSUBLINK spec/version, static-assert, Static Assert) to ensure the result is as expected.) $(LI Although the contents of the padding are often zero, do not rely on that.) - $(LI Avoid using empty structs when interfacing with C and C++ code.) - $(LI Avoid using empty structs as parameters or arguments to variadic functions.) + $(LI Avoid using Empty Structs. Add a one byte dummy field to those structs.) )) $(H2 $(LNAME2 POD, Plain Old Data))