Commit 312536540b

Daniele Cocca <daniele.cocca@gmail.com>
2022-03-15 22:53:48
CBE: better handling of sentineled slices/arrays
Adds the sentinel element to the type name to avoid ambiguous declarations, and outputs the sentinel element (if needed) even in what would otherwise be empty arrays.
1 parent d78b8c1
Changed files (2)
src
codegen
test
behavior
src/codegen/c.zig
@@ -616,27 +616,33 @@ pub const DeclGen = struct {
             .Array => {
                 // First try specific tag representations for more efficiency.
                 switch (val.tag()) {
-                    .undef, .empty_struct_value, .empty_array => try writer.writeAll("{}"),
+                    .undef, .empty_struct_value, .empty_array => {
+                        try writer.writeByte('{');
+                        const ai = ty.arrayInfo();
+                        if (ai.sentinel) |s| {
+                            try dg.renderValue(writer, ai.elem_type, s);
+                        }
+                        try writer.writeByte('}');
+                    },
                     else => {
                         // Fall back to generic implementation.
                         var arena = std.heap.ArenaAllocator.init(dg.module.gpa);
                         defer arena.deinit();
                         const arena_allocator = arena.allocator();
 
-                        try writer.writeAll("{");
+                        try writer.writeByte('{');
+                        const ai = ty.arrayInfo();
                         var index: usize = 0;
-                        const len = ty.arrayLen();
-                        const elem_ty = ty.elemType();
-                        while (index < len) : (index += 1) {
+                        while (index < ai.len) : (index += 1) {
                             if (index != 0) try writer.writeAll(",");
                             const elem_val = try val.elemValue(arena_allocator, index);
-                            try dg.renderValue(writer, elem_ty, elem_val);
+                            try dg.renderValue(writer, ai.elem_type, elem_val);
                         }
-                        if (ty.sentinel()) |sentinel_val| {
+                        if (ai.sentinel) |s| {
                             if (index != 0) try writer.writeAll(",");
-                            try dg.renderValue(writer, elem_ty, sentinel_val);
+                            try dg.renderValue(writer, ai.elem_type, s);
                         }
-                        try writer.writeAll("}");
+                        try writer.writeByte('}');
                     },
                 }
             },
@@ -925,14 +931,21 @@ pub const DeclGen = struct {
         const ptr_alignment = Value.initTag(.abi_align_default);
         try dg.renderTypeAndName(bw, ptr_type, ptr_name, .Mut, ptr_alignment);
 
+        const ptr_sentinel = ptr_type.ptrInfo().data.sentinel;
+        const child_type = t.childType();
+
         try bw.writeAll("; size_t len; } ");
         const name_index = buffer.items.len;
-        const elem_type = t.elemType();
         if (t.isConstPtr()) {
-            try bw.print("zig_L_{s};\n", .{typeToCIdentifier(elem_type)});
+            try bw.print("zig_L_{s}", .{typeToCIdentifier(child_type)});
         } else {
-            try bw.print("zig_M_{s};\n", .{typeToCIdentifier(elem_type)});
+            try bw.print("zig_M_{s}", .{typeToCIdentifier(child_type)});
+        }
+        if (ptr_sentinel) |s| {
+            try bw.writeAll("_s_");
+            try dg.renderValue(bw, child_type, s);
         }
+        try bw.writeAll(";\n");
 
         const rendered = buffer.toOwnedSlice();
         errdefer dg.typedefs.allocator.free(rendered);
test/behavior/array.zig
@@ -238,7 +238,6 @@ const Sub = struct { b: u8 };
 const Str = struct { a: []Sub };
 test "set global var array via slice embedded in struct" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     var s = Str{ .a = s_array[0..] };
@@ -254,7 +253,6 @@ test "set global var array via slice embedded in struct" {
 
 test "read/write through global variable array of struct fields initialized via array mult" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -275,7 +273,6 @@ test "read/write through global variable array of struct fields initialized via
 
 test "implicit cast single-item pointer" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     try testImplicitCastSingleItemPtr();
@@ -295,7 +292,6 @@ fn testArrayByValAtComptime(b: [2]u8) u8 {
 
 test "comptime evaluating function that takes array by value" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const arr = [_]u8{ 1, 2 };
@@ -307,7 +303,6 @@ test "comptime evaluating function that takes array by value" {
 
 test "runtime initialize array elem and then implicit cast to slice" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     var two: i32 = 2;
@@ -317,7 +312,6 @@ test "runtime initialize array elem and then implicit cast to slice" {
 
 test "array literal as argument to function" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -345,7 +339,6 @@ test "array literal as argument to function" {
 
 test "double nested array to const slice cast in array literal" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -406,7 +399,6 @@ test "double nested array to const slice cast in array literal" {
 
 test "anonymous literal in array" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -431,7 +423,6 @@ test "anonymous literal in array" {
 
 test "access the null element of a null terminated array" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -448,7 +439,6 @@ test "access the null element of a null terminated array" {
 
 test "type deduction for array subscript expression" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 
     const S = struct {
@@ -468,7 +458,6 @@ test "sentinel element count towards the ABI size calculation" {
     if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO