| 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 | 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 | 1043 | fn renderUnionTypedef(dg: *DeclGen, t: Type) error{ OutOfMemory, AnalysisFail }![]const u8 { |
| 1004 | 1044 | const union_ty = t.cast(Type.Payload.Union).?.data; |
| 1005 | 1045 | const fqn = try union_ty.getFullyQualifiedName(dg.typedefs.allocator); |
| ... | ... | @@ -1276,7 +1316,9 @@ pub const DeclGen = struct { |
| 1276 | 1316 | return w.writeAll(name); |
| 1277 | 1317 | }, |
| 1278 | 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 | 1322 | try dg.renderStructTypedef(t); |
| 1281 | 1323 | |
| 1282 | 1324 | return w.writeAll(name); |
| ... | ... | @@ -3116,6 +3158,8 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3116 | 3158 | var field_name: []const u8 = undefined; |
| 3117 | 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 | 3163 | switch (struct_ty.tag()) { |
| 3120 | 3164 | .@"struct" => { |
| 3121 | 3165 | const fields = struct_ty.structFields(); |
| ... | ... | @@ -3127,6 +3171,14 @@ fn structFieldPtr(f: *Function, inst: Air.Inst.Index, struct_ptr_ty: Type, struc |
| 3127 | 3171 | field_name = fields.keys()[index]; |
| 3128 | 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 | 3182 | else => unreachable, |
| 3131 | 3183 | } |
| 3132 | 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 | 3201 | const writer = f.object.writer(); |
| 3150 | 3202 | const struct_byval = try f.resolveInst(extra.struct_operand); |
| 3151 | 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 | 3206 | const field_name = switch (struct_ty.tag()) { |
| 3153 | 3207 | .@"struct" => struct_ty.structFields().keys()[extra.field_index], |
| 3154 | 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 | 3216 | else => unreachable, |
| 3156 | 3217 | }; |
| 3157 | 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 | 3713 | |
| 3653 | 3714 | const writer = f.object.writer(); |
| 3654 | 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; | |
| 3658 | _ = local; | |
| 3659 | return f.fail("TODO: C backend: implement airAggregateInit", .{}); | |
| 3734 | return local; | |
| 3660 | 3735 | } |
| 3661 | 3736 | |
| 3662 | 3737 | fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { |
test/behavior.zig+1-1| ... | ... | @@ -146,6 +146,7 @@ test { |
| 146 | 146 | { |
| 147 | 147 | // Tests that pass for stage1, llvm backend, C backend |
| 148 | 148 | _ = @import("behavior/bugs/421.zig"); |
| 149 | _ = @import("behavior/bugs/3779.zig"); | |
| 149 | 150 | _ = @import("behavior/bugs/9584.zig"); |
| 150 | 151 | _ = @import("behavior/cast_int.zig"); |
| 151 | 152 | _ = @import("behavior/eval.zig"); |
| ... | ... | @@ -162,7 +163,6 @@ test { |
| 162 | 163 | _ = @import("behavior/saturating_arithmetic.zig"); |
| 163 | 164 | _ = @import("behavior/widening.zig"); |
| 164 | 165 | _ = @import("behavior/bugs/2114.zig"); |
| 165 | _ = @import("behavior/bugs/3779.zig"); | |
| 166 | 166 | _ = @import("behavior/bugs/10147.zig"); |
| 167 | 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 | 7 | |
| 8 | 8 | test "@tagName() returns a string literal" { |
| 9 | 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)); | |
| 11 | try std.testing.expectEqualStrings("TestEnumValue", tag_name); | |
| 12 | try std.testing.expectEqualStrings("TestEnumValue", ptr_tag_name[0..tag_name.len]); | |
| 10 | try std.testing.expect(*const [13:0]u8 == @TypeOf(tag_name)); | |
| 11 | try std.testing.expect(std.mem.eql(u8, "TestEnumValue", tag_name)); | |
| 12 | try std.testing.expect(std.mem.eql(u8, "TestEnumValue", ptr_tag_name[0..tag_name.len])); | |
| 13 | 13 | } |
| 14 | 14 | |
| 15 | 15 | const TestError = error{TestErrorCode}; |
| ... | ... | @@ -18,9 +18,9 @@ const ptr_error_name: [*:0]const u8 = error_name; |
| 18 | 18 | |
| 19 | 19 | test "@errorName() returns a string literal" { |
| 20 | 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)); | |
| 22 | try std.testing.expectEqualStrings("TestErrorCode", error_name); | |
| 23 | try std.testing.expectEqualStrings("TestErrorCode", ptr_error_name[0..error_name.len]); | |
| 21 | try std.testing.expect(*const [13:0]u8 == @TypeOf(error_name)); | |
| 22 | try std.testing.expect(std.mem.eql(u8, "TestErrorCode", error_name)); | |
| 23 | try std.testing.expect(std.mem.eql(u8, "TestErrorCode", ptr_error_name[0..error_name.len])); | |
| 24 | 24 | } |
| 25 | 25 | |
| 26 | 26 | const TestType = struct {}; |
| ... | ... | @@ -29,9 +29,9 @@ const ptr_type_name: [*:0]const u8 = type_name; |
| 29 | 29 | |
| 30 | 30 | test "@typeName() returns a string literal" { |
| 31 | 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)); | |
| 33 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", type_name); | |
| 34 | try std.testing.expectEqualStrings("behavior.bugs.3779.TestType", ptr_type_name[0..type_name.len]); | |
| 32 | try std.testing.expect(*const [type_name.len:0]u8 == @TypeOf(type_name)); | |
| 33 | try std.testing.expect(std.mem.eql(u8, "behavior.bugs.3779.TestType", type_name)); | |
| 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 | 37 | const actual_contents = @embedFile("3779_file_to_embed.txt"); |
| ... | ... | @@ -39,10 +39,10 @@ const ptr_actual_contents: [*:0]const u8 = actual_contents; |
| 39 | 39 | const expected_contents = "hello zig\n"; |
| 40 | 40 | |
| 41 | 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 | 43 | try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); |
| 44 | try std.testing.expectEqualStrings(expected_contents, actual_contents); | |
| 45 | try std.testing.expectEqualStrings(expected_contents, ptr_actual_contents[0..actual_contents.len]); | |
| 44 | try std.testing.expect(std.mem.eql(u8, expected_contents, actual_contents)); | |
| 45 | try std.testing.expect(std.mem.eql(u8, expected_contents, ptr_actual_contents[0..actual_contents.len])); | |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | 48 | fn testFnForSrc() std.builtin.SourceLocation { |
| ... | ... | @@ -51,9 +51,9 @@ fn testFnForSrc() std.builtin.SourceLocation { |
| 51 | 51 | |
| 52 | 52 | test "@src() returns a struct containing 0-terminated string slices" { |
| 53 | 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 | 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 | 57 | try std.testing.expect(std.mem.endsWith(u8, src.fn_name, "testFnForSrc")); |
| 58 | 58 | |
| 59 | 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 | 2 | const std = @import("std"); |
| 3 | 3 | const testing = std.testing; |
| 4 | 4 | const expect = testing.expect; |
| 5 | const expectEqual = testing.expectEqual; | |
| 6 | 5 | |
| 7 | 6 | test "tuple concatenation" { |
| 8 | 7 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 9 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 10 | 8 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 11 | 9 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 12 | 10 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| ... | ... | @@ -18,8 +16,8 @@ test "tuple concatenation" { |
| 18 | 16 | var x = .{a}; |
| 19 | 17 | var y = .{b}; |
| 20 | 18 | var c = x ++ y; |
| 21 | try expectEqual(@as(i32, 1), c[0]); | |
| 22 | try expectEqual(@as(i32, 2), c[1]); | |
| 19 | try expect(@as(i32, 1) == c[0]); | |
| 20 | try expect(@as(i32, 2) == c[1]); | |
| 23 | 21 | } |
| 24 | 22 | }; |
| 25 | 23 | try S.doTheTest(); |
| ... | ... | @@ -51,7 +49,6 @@ test "tuple multiplication" { |
| 51 | 49 | |
| 52 | 50 | test "more tuple concatenation" { |
| 53 | 51 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 54 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 55 | 52 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 56 | 53 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 57 | 54 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| ... | ... | @@ -129,7 +126,6 @@ test "tuple initializer for var" { |
| 129 | 126 | } |
| 130 | 127 | |
| 131 | 128 | test "array-like initializer for tuple types" { |
| 132 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 133 | 129 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 134 | 130 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO |
| 135 | 131 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |