authorgravatar for evan@lagerdata.comEvan Haas <evan@lagerdata.com> 2021-03-18 05:41:04-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-03-18 14:41:04+02:00
logb54514d9dd15225ef2578b33c4c384db4680b90b
treee2e3c9482567d2e187c18ebf3ae6f99a4c65b60e
parent75a7abb0c47d9f5e99b1f69250776528fa60f569
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

translate-c: Use [N:0] arrays when initializer is a string literal (#8264)

* translate-c: Use [N:0] arrays when initializer is a string literal Translate incomplete arrays as [N:0] when initialized by a string literal. This preserves a bit more of the type information from the original C program. Fixes #8215

3 files changed, 210 insertions(+), 85 deletions(-)

src/translate_c.zig+78-50
...@@ -636,7 +636,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co...@@ -636,7 +636,7 @@ fn visitVarDecl(c: *Context, var_decl: *const clang.VarDecl, mangled_name: ?[]co
636 if (has_init) trans_init: {636 if (has_init) trans_init: {
637 if (decl_init) |expr| {637 if (decl_init) |expr| {
638 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)638 const node_or_error = if (expr.getStmtClass() == .StringLiteralClass)
639 transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), zigArraySize(c, type_node) catch 0)639 transStringLiteralInitializer(c, scope, @ptrCast(*const clang.StringLiteral, expr), type_node)
640 else640 else
641 transExprCoercing(c, scope, expr, .used);641 transExprCoercing(c, scope, expr, .used);
642 init_node = node_or_error catch |err| switch (err) {642 init_node = node_or_error catch |err| switch (err) {
...@@ -1412,7 +1412,7 @@ fn transDeclStmtOne(...@@ -1412,7 +1412,7 @@ fn transDeclStmtOne(
14121412
1413 var init_node = if (decl_init) |expr|1413 var init_node = if (decl_init) |expr|
1414 if (expr.getStmtClass() == .StringLiteralClass)1414 if (expr.getStmtClass() == .StringLiteralClass)
1415 try transStringLiteralAsArray(c, scope, @ptrCast(*const clang.StringLiteral, expr), try zigArraySize(c, type_node))1415 try transStringLiteralInitializer(c, scope, @ptrCast(*const clang.StringLiteral, expr), type_node)
1416 else1416 else
1417 try transExprCoercing(c, scope, expr, .used)1417 try transExprCoercing(c, scope, expr, .used)
1418 else1418 else
...@@ -1758,6 +1758,20 @@ fn transReturnStmt(...@@ -1758,6 +1758,20 @@ fn transReturnStmt(
1758 return Tag.@"return".create(c.arena, rhs);1758 return Tag.@"return".create(c.arena, rhs);
1759}1759}
17601760
1761fn transNarrowStringLiteral(
1762 c: *Context,
1763 scope: *Scope,
1764 stmt: *const clang.StringLiteral,
1765 result_used: ResultUsed,
1766) TransError!Node {
1767 var len: usize = undefined;
1768 const bytes_ptr = stmt.getString_bytes_begin_size(&len);
1769
1770 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
1771 const node = try Tag.string_literal.create(c.arena, str);
1772 return maybeSuppressResult(c, scope, result_used, node);
1773}
1774
1761fn transStringLiteral(1775fn transStringLiteral(
1762 c: *Context,1776 c: *Context,
1763 scope: *Scope,1777 scope: *Scope,
...@@ -1766,19 +1780,14 @@ fn transStringLiteral(...@@ -1766,19 +1780,14 @@ fn transStringLiteral(
1766) TransError!Node {1780) TransError!Node {
1767 const kind = stmt.getKind();1781 const kind = stmt.getKind();
1768 switch (kind) {1782 switch (kind) {
1769 .Ascii, .UTF8 => {1783 .Ascii, .UTF8 => return transNarrowStringLiteral(c, scope, stmt, result_used),
1770 var len: usize = undefined;
1771 const bytes_ptr = stmt.getString_bytes_begin_size(&len);
1772
1773 const str = try std.fmt.allocPrint(c.arena, "\"{}\"", .{std.zig.fmtEscapes(bytes_ptr[0..len])});
1774 const node = try Tag.string_literal.create(c.arena, str);
1775 return maybeSuppressResult(c, scope, result_used, node);
1776 },
1777 .UTF16, .UTF32, .Wide => {1784 .UTF16, .UTF32, .Wide => {
1778 const str_type = @tagName(stmt.getKind());1785 const str_type = @tagName(stmt.getKind());
1779 const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });1786 const name = try std.fmt.allocPrint(c.arena, "zig.{s}_string_{d}", .{ str_type, c.getMangle() });
1780 const lit_array = try transStringLiteralAsArray(c, scope, stmt, stmt.getLength() + 1);
17811787
1788 const expr_base = @ptrCast(*const clang.Expr, stmt);
1789 const array_type = try transQualTypeInitialized(c, scope, expr_base.getType(), expr_base, expr_base.getBeginLoc());
1790 const lit_array = try transStringLiteralInitializer(c, scope, stmt, array_type);
1782 const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array });1791 const decl = try Tag.var_simple.create(c.arena, .{ .name = name, .init = lit_array });
1783 try scope.appendNode(decl);1792 try scope.appendNode(decl);
1784 const node = try Tag.identifier.create(c.arena, name);1793 const node = try Tag.identifier.create(c.arena, name);
...@@ -1787,52 +1796,67 @@ fn transStringLiteral(...@@ -1787,52 +1796,67 @@ fn transStringLiteral(
1787 }1796 }
1788}1797}
17891798
1790/// Parse the size of an array back out from an ast Node.1799fn getArrayPayload(array_type: Node) ast.Payload.Array.ArrayTypeInfo {
1791fn zigArraySize(c: *Context, node: Node) TransError!usize {1800 return (array_type.castTag(.array_type) orelse array_type.castTag(.null_sentinel_array_type).?).data;
1792 if (node.castTag(.array_type)) |array| {
1793 return array.data.len;
1794 }
1795 return error.UnsupportedTranslation;
1796}1801}
17971802
1798/// Translate a string literal to an array of integers. Used when an1803/// Translate a string literal that is initializing an array. In general narrow string
1799/// array is initialized from a string literal. `array_size` is the1804/// literals become `"<string>".*` or `"<string>"[0..<size>].*` if they need truncation.
1800/// size of the array being initialized. If the string literal is larger1805/// Wide string literals become an array of integers. zero-fillers pad out the array to
1801/// than the array, truncate the string. If the array is larger than the1806/// the appropriate length, if necessary.
1802/// string literal, pad the array with 0's1807fn transStringLiteralInitializer(
1803fn transStringLiteralAsArray(
1804 c: *Context,1808 c: *Context,
1805 scope: *Scope,1809 scope: *Scope,
1806 stmt: *const clang.StringLiteral,1810 stmt: *const clang.StringLiteral,
1807 array_size: usize,1811 array_type: Node,
1808) TransError!Node {1812) TransError!Node {
1809 if (array_size == 0) return error.UnsupportedType;1813 assert(array_type.tag() == .array_type or array_type.tag() == .null_sentinel_array_type);
1814
1815 const is_narrow = stmt.getKind() == .Ascii or stmt.getKind() == .UTF8;
18101816
1811 const str_length = stmt.getLength();1817 const str_length = stmt.getLength();
1818 const payload = getArrayPayload(array_type);
1819 const array_size = payload.len;
1820 const elem_type = payload.elem_type;
1821
1822 if (array_size == 0) return Tag.empty_array.create(c.arena, elem_type);
1823
1824 const num_inits = math.min(str_length, array_size);
1825 const init_node = if (num_inits > 0) blk: {
1826 if (is_narrow) {
1827 // "string literal".* or string literal"[0..num_inits].*
1828 var str = try transNarrowStringLiteral(c, scope, stmt, .used);
1829 if (str_length != array_size) str = try Tag.string_slice.create(c.arena, .{ .string = str, .end = num_inits });
1830 break :blk try Tag.deref.create(c.arena, str);
1831 } else {
1832 const init_list = try c.arena.alloc(Node, num_inits);
1833 var i: c_uint = 0;
1834 while (i < num_inits) : (i += 1) {
1835 init_list[i] = try transCreateCharLitNode(c, false, stmt.getCodeUnit(i));
1836 }
1837 const init_args = .{ .len = num_inits, .elem_type = elem_type };
1838 const init_array_type = try if (array_type.tag() == .array_type) Tag.array_type.create(c.arena, init_args) else Tag.null_sentinel_array_type.create(c.arena, init_args);
1839 break :blk try Tag.array_init.create(c.arena, .{
1840 .cond = init_array_type,
1841 .cases = init_list,
1842 });
1843 }
1844 } else null;
18121845
1813 const expr_base = @ptrCast(*const clang.Expr, stmt);1846 if (num_inits == array_size) return init_node.?; // init_node is only null if num_inits == 0; but if num_inits == array_size == 0 we've already returned
1814 const ty = expr_base.getType().getTypePtr();1847 assert(array_size > str_length); // If array_size <= str_length, `num_inits == array_size` and we've already returned.
1815 const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty);
18161848
1817 const elem_type = try transQualType(c, scope, const_arr_ty.getElementType(), expr_base.getBeginLoc());1849 const filler_node = try Tag.array_filler.create(c.arena, .{
1818 const arr_type = try Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_type });1850 .type = elem_type,
1819 const init_list = try c.arena.alloc(Node, array_size);1851 .filler = Tag.zero_literal.init(),
1852 .count = array_size - str_length,
1853 });
18201854
1821 var i: c_uint = 0;1855 if (init_node) |some| {
1822 const kind = stmt.getKind();1856 return Tag.array_cat.create(c.arena, .{ .lhs = some, .rhs = filler_node });
1823 const narrow = kind == .Ascii or kind == .UTF8;1857 } else {
1824 while (i < str_length and i < array_size) : (i += 1) {1858 return filler_node;
1825 const code_unit = stmt.getCodeUnit(i);
1826 init_list[i] = try transCreateCharLitNode(c, narrow, code_unit);
1827 }
1828 while (i < array_size) : (i += 1) {
1829 init_list[i] = try transCreateNodeNumber(c, 0, .int);
1830 }1859 }
1831
1832 return Tag.array_init.create(c.arena, .{
1833 .cond = arr_type,
1834 .cases = init_list,
1835 });
1836}1860}
18371861
1838/// determine whether `stmt` is a "pointer subtraction expression" - a subtraction where1862/// determine whether `stmt` is a "pointer subtraction expression" - a subtraction where
...@@ -3342,9 +3366,8 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {...@@ -3342,9 +3366,8 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: Node) !void {
3342 try c.global_scope.nodes.append(decl_node);3366 try c.global_scope.nodes.append(decl_node);
3343}3367}
33443368
3345/// Translate a qual type for a variable with an initializer. The initializer3369/// Translate a qualtype for a variable with an initializer. This only matters
3346/// only matters for incomplete arrays, since the size of the array is determined3370/// for incomplete arrays, since the initializer determines the size of the array.
3347/// by the size of the initializer
3348fn transQualTypeInitialized(3371fn transQualTypeInitialized(
3349 c: *Context,3372 c: *Context,
3350 scope: *Scope,3373 scope: *Scope,
...@@ -3360,9 +3383,14 @@ fn transQualTypeInitialized(...@@ -3360,9 +3383,14 @@ fn transQualTypeInitialized(
3360 switch (decl_init.getStmtClass()) {3383 switch (decl_init.getStmtClass()) {
3361 .StringLiteralClass => {3384 .StringLiteralClass => {
3362 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);3385 const string_lit = @ptrCast(*const clang.StringLiteral, decl_init);
3363 const string_lit_size = string_lit.getLength() + 1; // +1 for null terminator3386 const string_lit_size = string_lit.getLength();
3364 const array_size = @intCast(usize, string_lit_size);3387 const array_size = @intCast(usize, string_lit_size);
3365 return Tag.array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });3388
3389 // incomplete array initialized with empty string, will be translated as [1]T{0}
3390 // see https://github.com/ziglang/zig/issues/8256
3391 if (array_size == 0) return Tag.array_type.create(c.arena, .{ .len = 1, .elem_type = elem_ty });
3392
3393 return Tag.null_sentinel_array_type.create(c.arena, .{ .len = array_size, .elem_type = elem_ty });
3366 },3394 },
3367 .InitListExprClass => {3395 .InitListExprClass => {
3368 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);3396 const init_expr = @ptrCast(*const clang.InitListExpr, decl_init);
src/translate_c/ast.zig+83-3
...@@ -40,6 +40,8 @@ pub const Node = extern union {...@@ -40,6 +40,8 @@ pub const Node = extern union {
40 string_literal,40 string_literal,
41 char_literal,41 char_literal,
42 enum_literal,42 enum_literal,
43 /// "string"[0..end]
44 string_slice,
43 identifier,45 identifier,
44 @"if",46 @"if",
45 /// if (!operand) break;47 /// if (!operand) break;
...@@ -176,6 +178,7 @@ pub const Node = extern union {...@@ -176,6 +178,7 @@ pub const Node = extern union {
176 c_pointer,178 c_pointer,
177 single_pointer,179 single_pointer,
178 array_type,180 array_type,
181 null_sentinel_array_type,
179182
180 /// @import("std").meta.sizeof(operand)183 /// @import("std").meta.sizeof(operand)
181 std_meta_sizeof,184 std_meta_sizeof,
...@@ -334,7 +337,7 @@ pub const Node = extern union {...@@ -334,7 +337,7 @@ pub const Node = extern union {
334 .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral,337 .std_meta_promoteIntLiteral => Payload.PromoteIntLiteral,
335 .block => Payload.Block,338 .block => Payload.Block,
336 .c_pointer, .single_pointer => Payload.Pointer,339 .c_pointer, .single_pointer => Payload.Pointer,
337 .array_type => Payload.Array,340 .array_type, .null_sentinel_array_type => Payload.Array,
338 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,341 .arg_redecl, .alias, .fail_decl => Payload.ArgRedecl,
339 .log2_int_type => Payload.Log2IntType,342 .log2_int_type => Payload.Log2IntType,
340 .var_simple, .pub_var_simple => Payload.SimpleVarDecl,343 .var_simple, .pub_var_simple => Payload.SimpleVarDecl,
...@@ -342,6 +345,7 @@ pub const Node = extern union {...@@ -342,6 +345,7 @@ pub const Node = extern union {
342 .array_filler => Payload.ArrayFiller,345 .array_filler => Payload.ArrayFiller,
343 .pub_inline_fn => Payload.PubInlineFn,346 .pub_inline_fn => Payload.PubInlineFn,
344 .field_access => Payload.FieldAccess,347 .field_access => Payload.FieldAccess,
348 .string_slice => Payload.StringSlice,
345 };349 };
346 }350 }
347351
...@@ -584,10 +588,12 @@ pub const Payload = struct {...@@ -584,10 +588,12 @@ pub const Payload = struct {
584588
585 pub const Array = struct {589 pub const Array = struct {
586 base: Payload,590 base: Payload,
587 data: struct {591 data: ArrayTypeInfo,
592
593 pub const ArrayTypeInfo = struct {
588 elem_type: Node,594 elem_type: Node,
589 len: usize,595 len: usize,
590 },596 };
591 };597 };
592598
593 pub const Pointer = struct {599 pub const Pointer = struct {
...@@ -664,6 +670,14 @@ pub const Payload = struct {...@@ -664,6 +670,14 @@ pub const Payload = struct {
664 radix: Node,670 radix: Node,
665 },671 },
666 };672 };
673
674 pub const StringSlice = struct {
675 base: Payload,
676 data: struct {
677 string: Node,
678 end: usize,
679 },
680 };
667};681};
668682
669/// Converts the nodes into a Zig ast.683/// Converts the nodes into a Zig ast.
...@@ -1015,6 +1029,36 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1015,6 +1029,36 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1015 .data = undefined,1029 .data = undefined,
1016 });1030 });
1017 },1031 },
1032 .string_slice => {
1033 const payload = node.castTag(.string_slice).?.data;
1034
1035 const string = try renderNode(c, payload.string);
1036 const l_bracket = try c.addToken(.l_bracket, "[");
1037 const start = try c.addNode(.{
1038 .tag = .integer_literal,
1039 .main_token = try c.addToken(.integer_literal, "0"),
1040 .data = undefined,
1041 });
1042 _ = try c.addToken(.ellipsis2, "..");
1043 const end = try c.addNode(.{
1044 .tag = .integer_literal,
1045 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.end}),
1046 .data = undefined,
1047 });
1048 _ = try c.addToken(.r_bracket, "]");
1049
1050 return c.addNode(.{
1051 .tag = .slice,
1052 .main_token = l_bracket,
1053 .data = .{
1054 .lhs = string,
1055 .rhs = try c.addExtra(std.zig.ast.Node.Slice{
1056 .start = start,
1057 .end = end,
1058 }),
1059 },
1060 });
1061 },
1018 .fail_decl => {1062 .fail_decl => {
1019 const payload = node.castTag(.fail_decl).?.data;1063 const payload = node.castTag(.fail_decl).?.data;
1020 // pub const name = @compileError(msg);1064 // pub const name = @compileError(msg);
...@@ -1581,6 +1625,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {...@@ -1581,6 +1625,10 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
1581 const payload = node.castTag(.array_type).?.data;1625 const payload = node.castTag(.array_type).?.data;
1582 return renderArrayType(c, payload.len, payload.elem_type);1626 return renderArrayType(c, payload.len, payload.elem_type);
1583 },1627 },
1628 .null_sentinel_array_type => {
1629 const payload = node.castTag(.null_sentinel_array_type).?.data;
1630 return renderNullSentinelArrayType(c, payload.len, payload.elem_type);
1631 },
1584 .array_filler => {1632 .array_filler => {
1585 const payload = node.castTag(.array_filler).?.data;1633 const payload = node.castTag(.array_filler).?.data;
15861634
...@@ -1946,6 +1994,36 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {...@@ -1946,6 +1994,36 @@ fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
1946 });1994 });
1947}1995}
19481996
1997fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
1998 const l_bracket = try c.addToken(.l_bracket, "[");
1999 const len_expr = try c.addNode(.{
2000 .tag = .integer_literal,
2001 .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),
2002 .data = undefined,
2003 });
2004 _ = try c.addToken(.colon, ":");
2005
2006 const sentinel_expr = try c.addNode(.{
2007 .tag = .integer_literal,
2008 .main_token = try c.addToken(.integer_literal, "0"),
2009 .data = undefined,
2010 });
2011
2012 _ = try c.addToken(.r_bracket, "]");
2013 const elem_type_expr = try renderNode(c, elem_type);
2014 return c.addNode(.{
2015 .tag = .array_type_sentinel,
2016 .main_token = l_bracket,
2017 .data = .{
2018 .lhs = len_expr,
2019 .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel {
2020 .sentinel = sentinel_expr,
2021 .elem_type = elem_type_expr,
2022 }),
2023 },
2024 });
2025}
2026
1949fn addSemicolonIfNeeded(c: *Context, node: Node) !void {2027fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
1950 switch (node.tag()) {2028 switch (node.tag()) {
1951 .warning => unreachable,2029 .warning => unreachable,
...@@ -2014,6 +2092,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2014,6 +2092,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2014 .integer_literal,2092 .integer_literal,
2015 .float_literal,2093 .float_literal,
2016 .string_literal,2094 .string_literal,
2095 .string_slice,
2017 .char_literal,2096 .char_literal,
2018 .enum_literal,2097 .enum_literal,
2019 .identifier,2098 .identifier,
...@@ -2035,6 +2114,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {...@@ -2035,6 +2114,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
2035 .func,2114 .func,
2036 .call,2115 .call,
2037 .array_type,2116 .array_type,
2117 .null_sentinel_array_type,
2038 .bool_to_int,2118 .bool_to_int,
2039 .div_exact,2119 .div_exact,
2040 .byte_offset_of,2120 .byte_offset_of,
test/translate_c.zig+49-32
...@@ -745,14 +745,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -745,14 +745,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
745 \\ static const char v2[] = "2.2.2";745 \\ static const char v2[] = "2.2.2";
746 \\}746 \\}
747 , &[_][]const u8{747 , &[_][]const u8{
748 \\const v2: [6]u8 = [6]u8{748 \\const v2: [5:0]u8 = "2.2.2".*;
749 \\ '2',
750 \\ '.',
751 \\ '2',
752 \\ '.',
753 \\ '2',
754 \\ 0,
755 \\};
756 \\pub export fn foo() void {}749 \\pub export fn foo() void {}
757 });750 });
758751
...@@ -1600,30 +1593,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1600,30 +1593,9 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1600 \\static char arr1[] = "hello";1593 \\static char arr1[] = "hello";
1601 \\char arr2[] = "hello";1594 \\char arr2[] = "hello";
1602 , &[_][]const u8{1595 , &[_][]const u8{
1603 \\pub export var arr0: [6]u8 = [6]u8{1596 \\pub export var arr0: [5:0]u8 = "hello".*;
1604 \\ 'h',1597 \\pub var arr1: [5:0]u8 = "hello".*;
1605 \\ 'e',1598 \\pub export var arr2: [5:0]u8 = "hello".*;
1606 \\ 'l',
1607 \\ 'l',
1608 \\ 'o',
1609 \\ 0,
1610 \\};
1611 \\pub var arr1: [6]u8 = [6]u8{
1612 \\ 'h',
1613 \\ 'e',
1614 \\ 'l',
1615 \\ 'l',
1616 \\ 'o',
1617 \\ 0,
1618 \\};
1619 \\pub export var arr2: [6]u8 = [6]u8{
1620 \\ 'h',
1621 \\ 'e',
1622 \\ 'l',
1623 \\ 'l',
1624 \\ 'o',
1625 \\ 0,
1626 \\};
1627 });1599 });
16281600
1629 cases.add("array initializer expr",1601 cases.add("array initializer expr",
...@@ -3425,4 +3397,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -3425,4 +3397,49 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
3425 , &[_][]const u8{3397 , &[_][]const u8{
3426 \\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.c.builtins");3398 \\pub const FOO = @compileError("TODO implement function '__builtin_alloca_with_align' in std.c.builtins");
3427 });3399 });
3400
3401 cases.add("null sentinel arrays when initialized from string literal. Issue #8256",
3402 \\#include <stdint.h>
3403 \\char zero[0] = "abc";
3404 \\uint32_t zero_w[0] = U"💯💯💯";
3405 \\char empty_incomplete[] = "";
3406 \\uint32_t empty_incomplete_w[] = U"";
3407 \\char empty_constant[100] = "";
3408 \\uint32_t empty_constant_w[100] = U"";
3409 \\char incomplete[] = "abc";
3410 \\uint32_t incomplete_w[] = U"💯💯💯";
3411 \\char truncated[1] = "abc";
3412 \\uint32_t truncated_w[1] = U"💯💯💯";
3413 \\char extend[5] = "a";
3414 \\uint32_t extend_w[5] = U"💯";
3415 \\char no_null[3] = "abc";
3416 \\uint32_t no_null_w[3] = U"💯💯💯";
3417 , &[_][]const u8{
3418 \\pub export var zero: [0]u8 = [0]u8{};
3419 \\pub export var zero_w: [0]u32 = [0]u32{};
3420 \\pub export var empty_incomplete: [1]u8 = [1]u8{0} ** 1;
3421 \\pub export var empty_incomplete_w: [1]u32 = [1]u32{0} ** 1;
3422 \\pub export var empty_constant: [100]u8 = [1]u8{0} ** 100;
3423 \\pub export var empty_constant_w: [100]u32 = [1]u32{0} ** 100;
3424 \\pub export var incomplete: [3:0]u8 = "abc".*;
3425 \\pub export var incomplete_w: [3:0]u32 = [3:0]u32{
3426 \\ '\u{1f4af}',
3427 \\ '\u{1f4af}',
3428 \\ '\u{1f4af}',
3429 \\};
3430 \\pub export var truncated: [1]u8 = "abc"[0..1].*;
3431 \\pub export var truncated_w: [1]u32 = [1]u32{
3432 \\ '\u{1f4af}',
3433 \\};
3434 \\pub export var extend: [5]u8 = "a"[0..1].* ++ [1]u8{0} ** 4;
3435 \\pub export var extend_w: [5]u32 = [1]u32{
3436 \\ '\u{1f4af}',
3437 \\} ++ [1]u32{0} ** 4;
3438 \\pub export var no_null: [3]u8 = "abc".*;
3439 \\pub export var no_null_w: [3]u32 = [3]u32{
3440 \\ '\u{1f4af}',
3441 \\ '\u{1f4af}',
3442 \\ '\u{1f4af}',
3443 \\};
3444 });
3428}3445}