| author | |
| committer | |
| log | e60c0468aaed9bae19ff40bcc163927e98aa2dd9 |
| tree | 8b8fcb9b7fbc5554aebb1bb223d463fd039dd91d |
| parent | 338bf55e84abcb4f5fb595266135d6fc074ecf3c |
| parent | 6fdca525dec95ea9ed96946188af41d3d0c29f47 |
| signature |
CBE: add support for tuples4 files changed, 97 insertions(+), 26 deletions(-)
src/codegen/c.zig+80-5| ... | @@ -1000,6 +1000,46 @@ pub const DeclGen = struct { | ... | @@ -1000,6 +1000,46 @@ pub const DeclGen = struct { |
| 1000 | return name; | 1000 | return name; |
| 1001 | } | 1001 | } |
| 1002 | 1002 | ||
| 1003 | fn renderTupleTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | ||
| 1004 | const tuple = t.tupleFields(); | ||
| 1005 | |||
| 1006 | var buffer = std.ArrayList(u8).init(dg.typedefs.allocator); | ||
| 1007 | defer buffer.deinit(); | ||
| 1008 | const writer = buffer.writer(); | ||
| 1009 | |||
| 1010 | try buffer.appendSlice("typedef struct {\n"); | ||
| 1011 | { | ||
| 1012 | for (tuple.types) |field_ty, i| { | ||
| 1013 | const val = tuple.values[i]; | ||
| 1014 | if (val.tag() != .unreachable_value) continue; | ||
| 1015 | |||
| 1016 | var name = std.ArrayList(u8).init(dg.gpa); | ||
| 1017 | defer name.deinit(); | ||
| 1018 | try name.writer().print("field_{d}", .{i}); | ||
| 1019 | |||
| 1020 | try buffer.append(' '); | ||
| 1021 | try dg.renderTypeAndName(writer, field_ty, .{ .bytes = name.items }, .Mut, Value.initTag(.abi_align_default)); | ||
| 1022 | try buffer.appendSlice(";\n"); | ||
| 1023 | } | ||
| 1024 | } | ||
| 1025 | try buffer.appendSlice("} "); | ||
| 1026 | |||
| 1027 | const name_start = buffer.items.len; | ||
| 1028 | try writer.print("zig_T_{};\n", .{typeToCIdentifier(t)}); | ||
| 1029 | |||
| 1030 | const rendered = buffer.toOwnedSlice(); | ||
| 1031 | errdefer dg.typedefs.allocator.free(rendered); | ||
| 1032 | const name = rendered[name_start .. rendered.len - 2]; | ||
| 1033 | |||
| 1034 | try dg.typedefs.ensureUnusedCapacity(1); | ||
| 1035 | dg.typedefs.putAssumeCapacityNoClobber( | ||
| 1036 | try t.copy(dg.typedefs_arena), | ||
| 1037 | .{ .name = name, .rendered = rendered }, | ||
| 1038 | ); | ||
| 1039 | |||
| 1040 | return name; | ||
| 1041 | } | ||
| 1042 | |||
| 1003 | fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { | 1043 | fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1004 | const union_ty = t.cast(Type.Payload.Union).?.data; | 1044 | const union_ty = t.cast(Type.Payload.Union).?.data; |
| 1005 | const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator); | 1045 | const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator); |
| ... | @@ -1276,7 +1316,9 @@ pub const DeclGen = struct { | ... | @@ -1276,7 +1316,9 @@ pub const DeclGen = struct { |
| 1276 | return w.writeAll(name); | 1316 | return w.writeAll(name); |
| 1277 | }, | 1317 | }, |
| 1278 | .Struct => { | 1318 | .Struct => { |
| 1279 | const name = dg.getTypedefName(t) orelse | 1319 | const name = dg.getTypedefName(t) orelse if (t.isTuple()) |
| 1320 | try dg.renderTupleTypedef(t) | ||
| 1321 | else | ||
| 1280 | try dg.renderStructTypedef(t); | 1322 | try dg.renderStructTypedef(t); |
| 1281 | 1323 | ||
| 1282 | return w.writeAll(name); | 1324 | return w.writeAll(name); |
| ... | @@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3116 | var field_name: []const u8 = undefined; | 3158 | var field_name: []const u8 = undefined; |
| 3117 | var field_val_ty: Type = undefined; | 3159 | var field_val_ty: Type = undefined; |
| 3118 | 3160 | ||
| 3161 | var buf = std.ArrayList(u8).init(f.object.dg.gpa); | ||
| 3162 | defer buf.deinit(); | ||
| 3119 | switch (struct_ty.tag()) { | 3163 | switch (struct_ty.tag()) { |
| 3120 | .@"struct" => { | 3164 | .@"struct" => { |
| 3121 | const fields = struct_ty.structFields(); | 3165 | const fields = struct_ty.structFields(); |
| ... | @@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc | ... | @@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3127 | field_name = fields.keys()[index]; | 3171 | field_name = fields.keys()[index]; |
| 3128 | field_val_ty = fields.values()[index].ty; | 3172 | field_val_ty = fields.values()[index].ty; |
| 3129 | }, | 3173 | }, |
| 3174 | .tuple => { | ||
| 3175 | const tuple = struct_ty.tupleFields(); | ||
| 3176 | if (tuple.values[index].tag() != .unreachable_value) return CValue.none; | ||
| 3177 | |||
| 3178 | try buf.writer().print("field_{d}", .{index}); | ||
| 3179 | field_name = buf.items; | ||
| 3180 | field_val_ty = tuple.types[index]; | ||
| 3181 | }, | ||
| 3130 | else => unreachable, | 3182 | else => unreachable, |
| 3131 | } | 3183 | } |
| 3132 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | 3184 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| ... | @@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3149,9 +3201,18 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3149 | const writer = f.object.writer(); | 3201 | const writer = f.object.writer(); |
| 3150 | const struct_byval = try f.resolveInst(extra.struct_operand); | 3202 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 3151 | const struct_ty = f.air.typeOf(extra.struct_operand); | 3203 | const struct_ty = f.air.typeOf(extra.struct_operand); |
| 3204 | var buf = std.ArrayList(u8).init(f.object.dg.gpa); | ||
| 3205 | defer buf.deinit(); | ||
| 3152 | const field_name = switch (struct_ty.tag()) { | 3206 | const field_name = switch (struct_ty.tag()) { |
| 3153 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], | 3207 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], |
| 3154 | .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index], | 3208 | .@"union", .union_tagged => struct_ty.unionFields().keys()[extra.field_index], |
| 3209 | .tuple => blk: { | ||
| 3210 | const tuple = struct_ty.tupleFields(); | ||
| 3211 | if (tuple.values[extra.field_index].tag() != .unreachable_value) return CValue.none; | ||
| 3212 | |||
| 3213 | try buf.writer().print("field_{d}", .{extra.field_index}); | ||
| 3214 | break :blk buf.items; | ||
| 3215 | }, | ||
| 3155 | else => unreachable, | 3216 | else => unreachable, |
| 3156 | }; | 3217 | }; |
| 3157 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; | 3218 | const payload = if (struct_ty.tag() == .union_tagged) "payload." else ""; |
| ... | @@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3652,11 +3713,25 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3652 | 3713 | ||
| 3653 | const writer = f.object.writer(); | 3714 | const writer = f.object.writer(); |
| 3654 | const local = try f.allocLocal(inst_ty, .Const); | 3715 | const local = try f.allocLocal(inst_ty, .Const); |
| 3655 | try writer.writeAll(" = "); | 3716 | try writer.writeAll(" = {"); |
| 3717 | switch (vector_ty.zigTypeTag()) { | ||
| 3718 | .Struct => { | ||
| 3719 | const tuple = vector_ty.tupleFields(); | ||
| 3720 | var i: usize = 0; | ||
| 3721 | for (elements) |elem, elem_index| { | ||
| 3722 | if (tuple.values[elem_index].tag() != .unreachable_value) continue; | ||
| 3723 | |||
| 3724 | const value = try f.resolveInst(elem); | ||
| 3725 | if (i != 0) try writer.writeAll(", "); | ||
| 3726 | try f.writeCValue(writer, value); | ||
| 3727 | i += 1; | ||
| 3728 | } | ||
| 3729 | }, | ||
| 3730 | else => |tag| return f.fail("TODO: C backend: implement airAggregateInit for type {s}", .{@tagName(tag)}), | ||
| 3731 | } | ||
| 3732 | try writer.writeAll("};\n"); | ||
| 3656 | 3733 | ||
| 3657 | _ = elements; | 3734 | return local; |
| 3658 | _ = local; | ||
| 3659 | return f.fail("TODO: C backend: implement airAggregateInit", .{}); | ||
| 3660 | } | 3735 | } |
| 3661 | 3736 | ||
| 3662 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { | 3737 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
test/behavior.zig+1-1| ... | @@ -146,6 +146,7 @@ test { | ... | @@ -146,6 +146,7 @@ test { |
| 146 | { | 146 | { |
| 147 | // Tests that pass for stage1, llvm backend, C backend | 147 | // Tests that pass for stage1, llvm backend, C backend |
| 148 | _ = @import("behavior/bugs/421.zig"); | 148 | _ = @import("behavior/bugs/421.zig"); |
| 149 | _ = @import("behavior/bugs/3779.zig"); | ||
| 149 | _ = @import("behavior/bugs/9584.zig"); | 150 | _ = @import("behavior/bugs/9584.zig"); |
| 150 | _ = @import("behavior/cast_int.zig"); | 151 | _ = @import("behavior/cast_int.zig"); |
| 151 | _ = @import("behavior/eval.zig"); | 152 | _ = @import("behavior/eval.zig"); |
| ... | @@ -162,7 +163,6 @@ test { | ... | @@ -162,7 +163,6 @@ test { |
| 162 | _ = @import("behavior/saturating_arithmetic.zig"); | 163 | _ = @import("behavior/saturating_arithmetic.zig"); |
| 163 | _ = @import("behavior/widening.zig"); | 164 | _ = @import("behavior/widening.zig"); |
| 164 | _ = @import("behavior/bugs/2114.zig"); | 165 | _ = @import("behavior/bugs/2114.zig"); |
| 165 | _ = @import("behavior/bugs/3779.zig"); | ||
| 166 | _ = @import("behavior/bugs/10147.zig"); | 166 | _ = @import("behavior/bugs/10147.zig"); |
| 167 | _ = @import("behavior/shuffle.zig"); | 167 | _ = @import("behavior/shuffle.zig"); |
| 168 | 168 |
test/behavior/bugs/3779.zig+14-14| ... | @@ -7,9 +7,9 @@ const ptr_tag_name: [*:0]const u8 = tag_name; | ... | @@ -7,9 +7,9 @@ const ptr_tag_name: [*:0]const u8 = tag_name; |
| 7 | 7 | ||
| 8 | test "@tagName() returns a string literal" { | 8 | test "@tagName() returns a string literal" { |
| 9 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong | 9 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong |
| 10 | try std.testing.expectEqual(*const [13:0]u8, @TypeOf(tag_name)); | 10 | try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name)); |
| 11 | try std.testing.expectEqualStrings("TestEnumValue", tag_name); | 11 | try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name)); |
| 12 | try std.testing.expectEqualStrings("TestEnumValue", ptr_tag_name[0..tag_name.len]); | 12 | try std.testing.expect(std.mem.eql(u8, "TestEnumValue", ptr_tag_name[0..tag_name.len])); |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | const TestError = error{TestErrorCode}; | 15 | const TestError = error{TestErrorCode}; |
| ... | @@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name; | ... | @@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name; |
| 18 | 18 | ||
| 19 | test "@errorName() returns a string literal" { | 19 | test "@errorName() returns a string literal" { |
| 20 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong | 20 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong |
| 21 | try std.testing.expectEqual(*const [13:0]u8, @TypeOf(error_name)); | 21 | try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name)); |
| 22 | try std.testing.expectEqualStrings("TestErrorCode", error_name); | 22 | try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name)); |
| 23 | try std.testing.expectEqualStrings("TestErrorCode", ptr_error_name[0..error_name.len]); | 23 | try std.testing.expect(std.mem.eql(u8, "TestErrorCode", ptr_error_name[0..error_name.len])); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | const TestType = struct {}; | 26 | const TestType = struct {}; |
| ... | @@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name; | ... | @@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name; |
| 29 | 29 | ||
| 30 | test "@typeName() returns a string literal" { | 30 | test "@typeName() returns a string literal" { |
| 31 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong | 31 | if (builtin.zig_backend == .stage1) return error.SkipZigTest; // stage1 gets the type wrong |
| 32 | try std.testing.expectEqual(*const [type_name.len:0]u8, @TypeOf(type_name)); | 32 | try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name)); |
| 33 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name); | 33 | try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", type_name)); |
| 34 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]); | 34 | try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len])); |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | const actual_contents = @embedFile("3779_file_to_embed.txt"); | 37 | const actual_contents = @embedFile("3779_file_to_embed.txt"); |
| ... | @@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents; | ... | @@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents; |
| 39 | const expected_contents = "hello zig\n"; | 39 | const expected_contents = "hello zig\n"; |
| 40 | 40 | ||
| 41 | test "@embedFile() returns a string literal" { | 41 | test "@embedFile() returns a string literal" { |
| 42 | try std.testing.expectEqual(*const [expected_contents.len:0]u8, @TypeOf(actual_contents)); | 42 | try std.testing.expect(*const [expected_contents.len:0]u8 == @TypeOf(actual_contents)); |
| 43 | try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); | 43 | try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); |
| 44 | try std.testing.expectEqualStrings(expected_contents, actual_contents); | 44 | try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); |
| 45 | try std.testing.expectEqualStrings(expected_contents, ptr_actual_contents[0..actual_contents.len]); | 45 | try std.testing.expect(std.mem.eql(u8, expected_contents, ptr_actual_contents[0..actual_contents.len])); |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | fn testFnForSrc() std.builtin.SourceLocation { | 48 | fn testFnForSrc() std.builtin.SourceLocation { |
| ... | @@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation { | ... | @@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation { |
| 51 | 51 | ||
| 52 | test "@src() returns a struct containing 0-terminated string slices" { | 52 | test "@src() returns a struct containing 0-terminated string slices" { |
| 53 | const src = testFnForSrc(); | 53 | const src = testFnForSrc(); |
| 54 | try std.testing.expectEqual([:0]const u8, @TypeOf(src.file)); | 54 | try std.testing.expect([:0]const u8 == @TypeOf(src.file)); |
| 55 | try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig")); | 55 | try std.testing.expect(std.mem.endsWith(u8, src.file, "3779.zig")); |
| 56 | try std.testing.expectEqual([:0]const u8, @TypeOf(src.fn_name)); | 56 | try std.testing.expect([:0]const u8 == @TypeOf(src.fn_name)); |
| 57 | try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc")); | 57 | try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc")); |
| 58 | 58 | ||
| 59 | const ptr_src_file: [*:0]const u8 = src.file; | 59 | const ptr_src_file: [*:0]const u8 = src.file; |
test/behavior/tuple.zig+2-6| ... | @@ -2,11 +2,9 @@ const builtin = @import("builtin"); | ... | @@ -2,11 +2,9 @@ const builtin = @import("builtin"); |
| 2 | const std = @import("std"); | 2 | const std = @import("std"); |
| 3 | const testing = std.testing; | 3 | const testing = std.testing; |
| 4 | const expect = testing.expect; | 4 | const expect = testing.expect; |
| 5 | const expectEqual = testing.expectEqual; | ||
| 6 | 5 | ||
| 7 | test "tuple concatenation" { | 6 | test "tuple concatenation" { |
| 8 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 10 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 8 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 11 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| ... | @@ -18,8 +16,8 @@ test "tuple concatenation" { | ... | @@ -18,8 +16,8 @@ test "tuple concatenation" { |
| 18 | var x = .{a}; | 16 | var x = .{a}; |
| 19 | var y = .{b}; | 17 | var y = .{b}; |
| 20 | var c = x ++ y; | 18 | var c = x ++ y; |
| 21 | try expectEqual(@as(i32, 1), c[0]); | 19 | try expect(@as(i32, 1) == c[0]); |
| 22 | try expectEqual(@as(i32, 2), c[1]); | 20 | try expect(@as(i32, 2) == c[1]); |
| 23 | } | 21 | } |
| 24 | }; | 22 | }; |
| 25 | try S.doTheTest(); | 23 | try S.doTheTest(); |
| ... | @@ -51,7 +49,6 @@ test "tuple multiplication" { | ... | @@ -51,7 +49,6 @@ test "tuple multiplication" { |
| 51 | 49 | ||
| 52 | test "more tuple concatenation" { | 50 | test "more tuple concatenation" { |
| 53 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 51 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 55 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 52 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 56 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 57 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | 54 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | @@ -129,7 +126,6 @@ test "tuple initializer for var" { | ... | @@ -129,7 +126,6 @@ test "tuple initializer for var" { |
| 129 | } | 126 | } |
| 130 | 127 | ||
| 131 | test "array-like initializer for tuple types" { | 128 | test "array-like initializer for tuple types" { |
| 132 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 133 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO | 129 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 134 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | 130 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 135 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | 131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |