| author | |
| committer | |
| log | 5b689d389fa50070c08520cdb6296dda3ad78a62 |
| tree | 284c79f96a6ed88db8c68825bed2a4152412a0c4 |
| parent | 34835bbbcfe81cc87e823d14dc9b25e698ad5edc |
| signature |
Superceeds PR #12735 (now supporting all packed structs in GNU C)
Fixes issue #12733
This stops translating C packed struct as a Zig packed struct.
Instead use a regular `extern struct` with `align(1)`.
This is because (as @Vexu explained) Zig packed structs are really just integers (not structs).
Alignment issue is more complicated. I think @ifreund was the
first to notice it in his comment on PR #12735
Justification of my interpretion of the C(lang) behavior
comes from a careful reading of the GCC docs for type & variable attributes:
(clang emulates gnu's packed attribute here)
The final line of the documentation for __attribute__ ((aligned)) [on types] says:
> When used on a struct, or struct member, *the aligned attribute can only increase the alignment*; in order to decrease it, the packed attribute must be specified as well.
This implies that GCC uses the `packed` attribute for alignment purposes
in addition to eliminating padding.
The documentation for __attribute__((packed)) [on types], states:
> This attribute, attached to a struct, union, or C++ class type definition, specifies that each of its members (other than zero-width bit-fields) is placed to minimize the memory required. **This is equivalent to specifying the packed attribute on each of the members**.
The key is resolving this indirection, and looking at the documentation
for __attribute__((packed)) [on fields (wierdly under "variables" section)]:
> The packed attribute specifies that a **structure member should have the smallest possible alignment** — one bit for a bit-field and one byte otherwise, unless a larger value is specified with the aligned attribute. The attribute does not apply to non-member objects.
Furthermore, alignment is the only effect of the packed attribute mentioned in the GCC docs (for "common" architecture).
Based on this, it seems safe to completely substitute C 'packed' with Zig 'align(1)'.
Target-specific or undocumented behavior potentially changes this.
Unfortunately, the current implementation of `translate-c` translates as
`packed struct` without alignment info.
Because Zig packed structs are really integers (as mentioned above),
they are the wrong interpretation and we should be using 'extern struct'.
Running `translate-c` on the following code:
```c
struct foo {
char a;
int b;
} __attribute__((packed));
struct bar {
char a;
int b;
short c;
__attribute__((aligned(8))) long d;
} __attribute__((packed));
```
Previously used a 'packed struct' (which was not FFI-safe on stage1).
After applying this change, the translated structures have align(1)
explicitly applied to all of their fields AS EXPECTED (unless explicitly overriden).
This makes Zig behavior for `tranlsate-c` consistent with clang/GCC.
Here is the newly produced (correct) output for the above example:
```zig
pub const struct_foo = extern struct {
a: u8 align(1),
b: c_int align(1),
};
pub const struct_bar = extern struct {
a: u8 align(1),
b: c_int align(1),
c: c_short align(1),
d: c_long align(8),
};
```
Also note for reference: Since the last stable release (0.9.1),
there was a change in the language spec
related to the alignment of packed structures.
The docs for Zig 0.9.1 read:
> Packed structs have 1-byte alignment.
So the old behavior of translate-c (not specifying any alignment) was possibly correct back then.
However the current docs read:
> Packed structs have the same alignment as their backing integer
Suggsestive both to the change to an integer-backed representation
which is incompatible with C's notation.6 files changed, 106 insertions(+), 50 deletions(-)
src/clang.zig+6| ... | @@ -470,6 +470,9 @@ pub const FieldDecl = opaque { | ... | @@ -470,6 +470,9 @@ pub const FieldDecl = opaque { |
| 470 | pub const getAlignedAttribute = ZigClangFieldDecl_getAlignedAttribute; | 470 | pub const getAlignedAttribute = ZigClangFieldDecl_getAlignedAttribute; |
| 471 | extern fn ZigClangFieldDecl_getAlignedAttribute(*const FieldDecl, *const ASTContext) c_uint; | 471 | extern fn ZigClangFieldDecl_getAlignedAttribute(*const FieldDecl, *const ASTContext) c_uint; |
| 472 | 472 | ||
| 473 | pub const getPackedAttribute = ZigClangFieldDecl_getPackedAttribute; | ||
| 474 | extern fn ZigClangFieldDecl_getPackedAttribute(*const FieldDecl) bool; | ||
| 475 | |||
| 473 | pub const isAnonymousStructOrUnion = ZigClangFieldDecl_isAnonymousStructOrUnion; | 476 | pub const isAnonymousStructOrUnion = ZigClangFieldDecl_isAnonymousStructOrUnion; |
| 474 | extern fn ZigClangFieldDecl_isAnonymousStructOrUnion(*const FieldDecl) bool; | 477 | extern fn ZigClangFieldDecl_isAnonymousStructOrUnion(*const FieldDecl) bool; |
| 475 | 478 | ||
| ... | @@ -1015,6 +1018,9 @@ pub const VarDecl = opaque { | ... | @@ -1015,6 +1018,9 @@ pub const VarDecl = opaque { |
| 1015 | pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute; | 1018 | pub const getAlignedAttribute = ZigClangVarDecl_getAlignedAttribute; |
| 1016 | extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint; | 1019 | extern fn ZigClangVarDecl_getAlignedAttribute(*const VarDecl, *const ASTContext) c_uint; |
| 1017 | 1020 | ||
| 1021 | pub const getPackedAttribute = ZigClangVarDecl_getPackedAttribute; | ||
| 1022 | extern fn ZigClangVarDecl_getPackedAttribute(*const VarDecl) bool; | ||
| 1023 | |||
| 1018 | pub const getCleanupAttribute = ZigClangVarDecl_getCleanupAttribute; | 1024 | pub const getCleanupAttribute = ZigClangVarDecl_getCleanupAttribute; |
| 1019 | extern fn ZigClangVarDecl_getCleanupAttribute(*const VarDecl) ?*const FunctionDecl; | 1025 | extern fn ZigClangVarDecl_getCleanupAttribute(*const VarDecl) ?*const FunctionDecl; |
| 1020 | 1026 |
src/translate_c.zig+61-16| ... | @@ -878,7 +878,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co | ... | @@ -878,7 +878,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co |
| 878 | .is_export = is_export, | 878 | .is_export = is_export, |
| 879 | .is_threadlocal = is_threadlocal, | 879 | .is_threadlocal = is_threadlocal, |
| 880 | .linksection_string = linksection_string, | 880 | .linksection_string = linksection_string, |
| 881 | .alignment = zigAlignment(var_decl.getAlignedAttribute(c.clang_context)), | 881 | .alignment = ClangAlignment.forVar(c, var_decl).zigAlignment(), |
| 882 | .name = var_name, | 882 | .name = var_name, |
| 883 | .type = type_node, | 883 | .type = type_node, |
| 884 | .init = init_node, | 884 | .init = init_node, |
| ... | @@ -1096,7 +1096,6 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD | ... | @@ -1096,7 +1096,6 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1096 | break :blk Tag.opaque_literal.init(); | 1096 | break :blk Tag.opaque_literal.init(); |
| 1097 | }; | 1097 | }; |
| 1098 | 1098 | ||
| 1099 | const is_packed = record_decl.getPackedAttribute(); | ||
| 1100 | var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa); | 1099 | var fields = std.ArrayList(ast.Payload.Record.Field).init(c.gpa); |
| 1101 | defer fields.deinit(); | 1100 | defer fields.deinit(); |
| 1102 | 1101 | ||
| ... | @@ -1153,7 +1152,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD | ... | @@ -1153,7 +1152,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1153 | const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0) | 1152 | const alignment = if (has_flexible_array and field_decl.getFieldIndex() == 0) |
| 1154 | @intCast(c_uint, record_alignment) | 1153 | @intCast(c_uint, record_alignment) |
| 1155 | else | 1154 | else |
| 1156 | zigAlignment(field_decl.getAlignedAttribute(c.clang_context)); | 1155 | ClangAlignment.forField(c, field_decl, record_def).zigAlignment(); |
| 1157 | 1156 | ||
| 1158 | if (is_anon) { | 1157 | if (is_anon) { |
| 1159 | try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name); | 1158 | try c.decl_table.putNoClobber(c.gpa, @ptrToInt(field_decl.getCanonicalDecl()), field_name); |
| ... | @@ -1166,15 +1165,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD | ... | @@ -1166,15 +1165,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1166 | }); | 1165 | }); |
| 1167 | } | 1166 | } |
| 1168 | 1167 | ||
| 1169 | if (!c.zig_is_stage1 and is_packed) { | ||
| 1170 | return failDecl(c, record_loc, name, "cannot translate packed record union", .{}); | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | const record_payload = try c.arena.create(ast.Payload.Record); | 1168 | const record_payload = try c.arena.create(ast.Payload.Record); |
| 1174 | record_payload.* = .{ | 1169 | record_payload.* = .{ |
| 1175 | .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, | 1170 | .base = .{ .tag = ([2]Tag{ .@"struct", .@"union" })[@boolToInt(is_union)] }, |
| 1176 | .data = .{ | 1171 | .data = .{ |
| 1177 | .layout = if (is_packed) .@"packed" else .@"extern", | 1172 | .layout = .@"extern", |
| 1178 | .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items), | 1173 | .fields = try c.arena.dupe(ast.Payload.Record.Field, fields.items), |
| 1179 | .functions = try c.arena.dupe(Node, functions.items), | 1174 | .functions = try c.arena.dupe(Node, functions.items), |
| 1180 | .variables = &.{}, | 1175 | .variables = &.{}, |
| ... | @@ -1851,12 +1846,62 @@ fn transCStyleCastExprClass( | ... | @@ -1851,12 +1846,62 @@ fn transCStyleCastExprClass( |
| 1851 | return maybeSuppressResult(c, scope, result_used, cast_node); | 1846 | return maybeSuppressResult(c, scope, result_used, cast_node); |
| 1852 | } | 1847 | } |
| 1853 | 1848 | ||
| 1854 | /// Clang reports the alignment in bits, we use bytes | 1849 | /// The alignment of a variable or field |
| 1855 | /// Clang uses 0 for "no alignment specified", we use null | 1850 | const ClangAlignment = struct { |
| 1856 | fn zigAlignment(bit_alignment: c_uint) ?c_uint { | 1851 | /// Clang reports the alignment in bits, we use bytes |
| 1857 | if (bit_alignment == 0) return null; | 1852 | /// Clang uses 0 for "no alignment specified", we use null |
| 1858 | return bit_alignment / 8; | 1853 | bit_alignment: c_uint, |
| 1859 | } | 1854 | /// If the field or variable is marked as 'packed' |
| 1855 | /// | ||
| 1856 | /// According to the GCC variable attribute docs, this impacts alignment | ||
| 1857 | /// https://gcc.gnu.org/onlinedocs/gcc/Common-Variable-Attributes.html | ||
| 1858 | /// | ||
| 1859 | /// > The packed attribute specifies that a structure member | ||
| 1860 | /// > should have the smallest possible alignment | ||
| 1861 | /// | ||
| 1862 | /// Note also that specifying the 'packed' attribute on a structure | ||
| 1863 | /// implicitly packs all its fields (making their alignment 1). | ||
| 1864 | /// | ||
| 1865 | /// This will be null if the AST node doesn't support packing (functions) | ||
| 1866 | is_packed: ?bool, | ||
| 1867 | |||
| 1868 | /// Get the alignment for a field, optionally taking into account the parent record | ||
| 1869 | pub fn forField(c: *const Context, field: *const clang.FieldDecl, parent: ?*const clang.RecordDecl) ClangAlignment { | ||
| 1870 | const parent_packed = if (parent) |record| record.getPackedAttribute() else false; | ||
| 1871 | // NOTE: According to GCC docs, parent attribute packed implies child attribute packed | ||
| 1872 | return ClangAlignment{ | ||
| 1873 | .bit_alignment = field.getAlignedAttribute(c.clang_context), | ||
| 1874 | .is_packed = field.getPackedAttribute() or parent_packed, | ||
| 1875 | }; | ||
| 1876 | } | ||
| 1877 | |||
| 1878 | pub fn forVar(c: *const Context, var_decl: *const clang.VarDecl) ClangAlignment { | ||
| 1879 | return ClangAlignment{ | ||
| 1880 | .bit_alignment = var_decl.getAlignedAttribute(c.clang_context), | ||
| 1881 | .is_packed = var_decl.getPackedAttribute(), | ||
| 1882 | }; | ||
| 1883 | } | ||
| 1884 | |||
| 1885 | pub fn forFunc(c: *const Context, fun: *const clang.FunctionDecl) ClangAlignment { | ||
| 1886 | return ClangAlignment{ | ||
| 1887 | .bit_alignment = fun.getAlignedAttribute(c.clang_context), | ||
| 1888 | .is_packed = null, // not supported by GCC/clang (or meaningful), | ||
| 1889 | }; | ||
| 1890 | } | ||
| 1891 | |||
| 1892 | /// Translate the clang alignment info into a zig alignment | ||
| 1893 | /// | ||
| 1894 | /// Returns null if there is no special alignment info | ||
| 1895 | pub fn zigAlignment(self: ClangAlignment) ?c_uint { | ||
| 1896 | if (self.bit_alignment != 0) { | ||
| 1897 | return self.bit_alignment / 8; | ||
| 1898 | } else if (self.is_packed orelse false) { | ||
| 1899 | return 1; | ||
| 1900 | } else { | ||
| 1901 | return null; | ||
| 1902 | } | ||
| 1903 | } | ||
| 1904 | }; | ||
| 1860 | 1905 | ||
| 1861 | fn transDeclStmtOne( | 1906 | fn transDeclStmtOne( |
| 1862 | c: *Context, | 1907 | c: *Context, |
| ... | @@ -1910,7 +1955,7 @@ fn transDeclStmtOne( | ... | @@ -1910,7 +1955,7 @@ fn transDeclStmtOne( |
| 1910 | .is_export = false, | 1955 | .is_export = false, |
| 1911 | .is_threadlocal = var_decl.getTLSKind() != .None, | 1956 | .is_threadlocal = var_decl.getTLSKind() != .None, |
| 1912 | .linksection_string = null, | 1957 | .linksection_string = null, |
| 1913 | .alignment = zigAlignment(var_decl.getAlignedAttribute(c.clang_context)), | 1958 | .alignment = ClangAlignment.forVar(c, var_decl).zigAlignment(), |
| 1914 | .name = var_name, | 1959 | .name = var_name, |
| 1915 | .type = type_node, | 1960 | .type = type_node, |
| 1916 | .init = init_node, | 1961 | .init = init_node, |
| ... | @@ -5054,7 +5099,7 @@ fn finishTransFnProto( | ... | @@ -5054,7 +5099,7 @@ fn finishTransFnProto( |
| 5054 | break :blk null; | 5099 | break :blk null; |
| 5055 | }; | 5100 | }; |
| 5056 | 5101 | ||
| 5057 | const alignment = if (fn_decl) |decl| zigAlignment(decl.getAlignedAttribute(c.clang_context)) else null; | 5102 | const alignment = if (fn_decl) |decl| ClangAlignment.forFunc(c, decl).zigAlignment() else null; |
| 5058 | 5103 | ||
| 5059 | const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .C) null else cc; | 5104 | const explicit_callconv = if ((is_inline or is_export or is_extern) and cc == .C) null else cc; |
| 5060 | 5105 |
src/zig_clang.cpp+11-4| ... | @@ -1941,10 +1941,7 @@ const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *se | ... | @@ -1941,10 +1941,7 @@ const char* ZigClangVarDecl_getSectionAttribute(const struct ZigClangVarDecl *se |
| 1941 | 1941 | ||
| 1942 | bool ZigClangRecordDecl_getPackedAttribute(const ZigClangRecordDecl *zig_record_decl) { | 1942 | bool ZigClangRecordDecl_getPackedAttribute(const ZigClangRecordDecl *zig_record_decl) { |
| 1943 | const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); | 1943 | const clang::RecordDecl *record_decl = reinterpret_cast<const clang::RecordDecl *>(zig_record_decl); |
| 1944 | if (record_decl->getAttr<clang::PackedAttr>()) { | 1944 | return record_decl->hasAttr<clang::PackedAttr>(); |
| 1945 | return true; | ||
| 1946 | } | ||
| 1947 | return false; | ||
| 1948 | } | 1945 | } |
| 1949 | 1946 | ||
| 1950 | unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx) { | 1947 | unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx) { |
| ... | @@ -1985,6 +1982,16 @@ unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionD | ... | @@ -1985,6 +1982,16 @@ unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionD |
| 1985 | return 0; | 1982 | return 0; |
| 1986 | } | 1983 | } |
| 1987 | 1984 | ||
| 1985 | bool ZigClangVarDecl_getPackedAttribute(const struct ZigClangVarDecl *self) { | ||
| 1986 | auto casted_self = reinterpret_cast<const clang::VarDecl *>(self); | ||
| 1987 | return casted_self->hasAttr<clang::PackedAttr>(); | ||
| 1988 | } | ||
| 1989 | |||
| 1990 | bool ZigClangFieldDecl_getPackedAttribute(const struct ZigClangFieldDecl *self) { | ||
| 1991 | auto casted_self = reinterpret_cast<const clang::FieldDecl *>(self); | ||
| 1992 | return casted_self->hasAttr<clang::PackedAttr>(); | ||
| 1993 | } | ||
| 1994 | |||
| 1988 | ZigClangQualType ZigClangParmVarDecl_getOriginalType(const struct ZigClangParmVarDecl *self) { | 1995 | ZigClangQualType ZigClangParmVarDecl_getOriginalType(const struct ZigClangParmVarDecl *self) { |
| 1989 | return bitcast(reinterpret_cast<const clang::ParmVarDecl *>(self)->getOriginalType()); | 1996 | return bitcast(reinterpret_cast<const clang::ParmVarDecl *>(self)->getOriginalType()); |
| 1990 | } | 1997 | } |
src/zig_clang.h+2| ... | @@ -1101,6 +1101,8 @@ ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttrib | ... | @@ -1101,6 +1101,8 @@ ZIG_EXTERN_C const struct ZigClangFunctionDecl *ZigClangVarDecl_getCleanupAttrib |
| 1101 | ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx); | 1101 | ZIG_EXTERN_C unsigned ZigClangVarDecl_getAlignedAttribute(const struct ZigClangVarDecl *self, const ZigClangASTContext* ctx); |
| 1102 | ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx); | 1102 | ZIG_EXTERN_C unsigned ZigClangFunctionDecl_getAlignedAttribute(const struct ZigClangFunctionDecl *self, const ZigClangASTContext* ctx); |
| 1103 | ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx); | 1103 | ZIG_EXTERN_C unsigned ZigClangFieldDecl_getAlignedAttribute(const struct ZigClangFieldDecl *self, const ZigClangASTContext* ctx); |
| 1104 | ZIG_EXTERN_C bool ZigClangVarDecl_getPackedAttribute(const struct ZigClangVarDecl *self); | ||
| 1105 | ZIG_EXTERN_C bool ZigClangFieldDecl_getPackedAttribute(const struct ZigClangFieldDecl *self); | ||
| 1104 | 1106 | ||
| 1105 | ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const struct ZigClangFileScopeAsmDecl *self); | 1107 | ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangFileScopeAsmDecl_getAsmString(const struct ZigClangFileScopeAsmDecl *self); |
| 1106 | 1108 |
test/run_translated_c.zig+12-14| ... | @@ -250,20 +250,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { | ... | @@ -250,20 +250,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 250 | \\} | 250 | \\} |
| 251 | , ""); | 251 | , ""); |
| 252 | 252 | ||
| 253 | if (@import("builtin").zig_backend == .stage1) { | 253 | cases.add("struct initializer - packed", |
| 254 | cases.add("struct initializer - packed", | 254 | \\#define _NO_CRT_STDIO_INLINE 1 |
| 255 | \\#define _NO_CRT_STDIO_INLINE 1 | 255 | \\#include <stdint.h> |
| 256 | \\#include <stdint.h> | 256 | \\#include <stdlib.h> |
| 257 | \\#include <stdlib.h> | 257 | \\struct s {uint8_t x,y; |
| 258 | \\struct s {uint8_t x,y; | 258 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; |
| 259 | \\ uint32_t z;} __attribute__((packed)) s0 = {1, 2}; | 259 | \\int main() { |
| 260 | \\int main() { | 260 | \\ /* sizeof nor offsetof currently supported */ |
| 261 | \\ /* sizeof nor offsetof currently supported */ | 261 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); |
| 262 | \\ if (((intptr_t)&s0.z - (intptr_t)&s0.x) != 2) abort(); | 262 | \\ return 0; |
| 263 | \\ return 0; | 263 | \\} |
| 264 | \\} | 264 | , ""); |
| 265 | , ""); | ||
| 266 | } | ||
| 267 | 265 | ||
| 268 | cases.add("cast signed array index to unsigned", | 266 | cases.add("cast signed array index to unsigned", |
| 269 | \\#include <stdlib.h> | 267 | \\#include <stdlib.h> |
test/translate_c.zig+14-16| ... | @@ -728,22 +728,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -728,22 +728,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 728 | \\} | 728 | \\} |
| 729 | }); | 729 | }); |
| 730 | 730 | ||
| 731 | if (builtin.zig_backend == .stage1) { | 731 | cases.add("struct initializer - packed", |
| 732 | cases.add("struct initializer - packed", | 732 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; |
| 733 | \\struct {int x,y,z;} __attribute__((packed)) s0 = {1, 2}; | 733 | , &[_][]const u8{ |
| 734 | , &[_][]const u8{ | 734 | \\const struct_unnamed_1 = extern struct { |
| 735 | \\const struct_unnamed_1 = packed struct { | 735 | \\ x: c_int align(1), |
| 736 | \\ x: c_int, | 736 | \\ y: c_int align(1), |
| 737 | \\ y: c_int, | 737 | \\ z: c_int align(1), |
| 738 | \\ z: c_int, | 738 | \\}; |
| 739 | \\}; | 739 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ |
| 740 | \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{ | 740 | \\ .x = @as(c_int, 1), |
| 741 | \\ .x = @as(c_int, 1), | 741 | \\ .y = @as(c_int, 2), |
| 742 | \\ .y = @as(c_int, 2), | 742 | \\ .z = 0, |
| 743 | \\ .z = 0, | 743 | \\}; |
| 744 | \\}; | 744 | }); |
| 745 | }); | ||
| 746 | } | ||
| 747 | 745 | ||
| 748 | // Test case temporarily disabled: | 746 | // Test case temporarily disabled: |
| 749 | // https://github.com/ziglang/zig/issues/12055 | 747 | // https://github.com/ziglang/zig/issues/12055 |