| author | |
| committer | |
| log | 7afa220f92dc0689116fc74935f6ddb73037f3c2 |
| tree | ff0818274a1d4f2af7ce6f4cf6fd51d321addcfc |
| parent | c715d512cbf513bc5a62a4b6022b037ee43900ba |
| parent | 684d9532c5ed0f8e213e6163d77d248ceb7393dd |
| signature |
C backend: while, struct tests, better undefined global handling4 files changed, 153 insertions(+), 97 deletions(-)
src/codegen/c.zig+15-1| ... | @@ -448,7 +448,14 @@ pub const DeclGen = struct { | ... | @@ -448,7 +448,14 @@ pub const DeclGen = struct { |
| 448 | try w.writeAll("ZIG_COLD "); | 448 | try w.writeAll("ZIG_COLD "); |
| 449 | } | 449 | } |
| 450 | } | 450 | } |
| 451 | try dg.renderType(w, dg.decl.ty.fnReturnType()); | 451 | const return_ty = dg.decl.ty.fnReturnType(); |
| 452 | if (return_ty.hasCodeGenBits()) { | ||
| 453 | try dg.renderType(w, return_ty); | ||
| 454 | } else if (return_ty.zigTypeTag() == .NoReturn) { | ||
| 455 | try w.writeAll("zig_noreturn void"); | ||
| 456 | } else { | ||
| 457 | try w.writeAll("void"); | ||
| 458 | } | ||
| 452 | try w.writeAll(" "); | 459 | try w.writeAll(" "); |
| 453 | try dg.renderDeclName(dg.decl, w); | 460 | try dg.renderDeclName(dg.decl, w); |
| 454 | try w.writeAll("("); | 461 | try w.writeAll("("); |
| ... | @@ -947,6 +954,10 @@ pub fn genDecl(o: *Object) !void { | ... | @@ -947,6 +954,10 @@ pub fn genDecl(o: *Object) !void { |
| 947 | } | 954 | } |
| 948 | try fwd_decl_writer.writeAll(";\n"); | 955 | try fwd_decl_writer.writeAll(";\n"); |
| 949 | 956 | ||
| 957 | if (variable.init.isUndef()) { | ||
| 958 | return; | ||
| 959 | } | ||
| 960 | |||
| 950 | try o.indent_writer.insertNewline(); | 961 | try o.indent_writer.insertNewline(); |
| 951 | const w = o.writer(); | 962 | const w = o.writer(); |
| 952 | try o.dg.renderType(w, o.dg.decl.ty); | 963 | try o.dg.renderType(w, o.dg.decl.ty); |
| ... | @@ -1886,6 +1897,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -1886,6 +1897,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1886 | } | 1897 | } |
| 1887 | 1898 | ||
| 1888 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | 1899 | fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 1900 | if (f.liveness.isUnused(inst)) | ||
| 1901 | return CValue.none; | ||
| 1902 | |||
| 1889 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 1903 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 1890 | const operand = try f.resolveInst(ty_op.operand); | 1904 | const operand = try f.resolveInst(ty_op.operand); |
| 1891 | 1905 |
test/behavior.zig+4-2| ... | @@ -21,12 +21,15 @@ test { | ... | @@ -21,12 +21,15 @@ test { |
| 21 | _ = @import("behavior/hasdecl.zig"); | 21 | _ = @import("behavior/hasdecl.zig"); |
| 22 | _ = @import("behavior/hasfield.zig"); | 22 | _ = @import("behavior/hasfield.zig"); |
| 23 | _ = @import("behavior/if.zig"); | 23 | _ = @import("behavior/if.zig"); |
| 24 | _ = @import("behavior/struct.zig"); | ||
| 25 | _ = @import("behavior/truncate.zig"); | ||
| 24 | _ = @import("behavior/null.zig"); | 26 | _ = @import("behavior/null.zig"); |
| 25 | _ = @import("behavior/ptrcast.zig"); | 27 | _ = @import("behavior/ptrcast.zig"); |
| 26 | _ = @import("behavior/pub_enum.zig"); | 28 | _ = @import("behavior/pub_enum.zig"); |
| 27 | _ = @import("behavior/truncate.zig"); | 29 | _ = @import("behavior/truncate.zig"); |
| 28 | _ = @import("behavior/underscore.zig"); | 30 | _ = @import("behavior/underscore.zig"); |
| 29 | _ = @import("behavior/usingnamespace.zig"); | 31 | _ = @import("behavior/usingnamespace.zig"); |
| 32 | _ = @import("behavior/while.zig"); | ||
| 30 | 33 | ||
| 31 | if (builtin.object_format != .c) { | 34 | if (builtin.object_format != .c) { |
| 32 | // Tests that pass for stage1 and stage2 but not the C backend. | 35 | // Tests that pass for stage1 and stage2 but not the C backend. |
| ... | @@ -60,12 +63,11 @@ test { | ... | @@ -60,12 +63,11 @@ test { |
| 60 | _ = @import("behavior/saturating_arithmetic.zig"); | 63 | _ = @import("behavior/saturating_arithmetic.zig"); |
| 61 | _ = @import("behavior/sizeof_and_typeof.zig"); | 64 | _ = @import("behavior/sizeof_and_typeof.zig"); |
| 62 | _ = @import("behavior/slice.zig"); | 65 | _ = @import("behavior/slice.zig"); |
| 63 | _ = @import("behavior/struct.zig"); | 66 | _ = @import("behavior/struct_llvm.zig"); |
| 64 | _ = @import("behavior/switch.zig"); | 67 | _ = @import("behavior/switch.zig"); |
| 65 | _ = @import("behavior/this.zig"); | 68 | _ = @import("behavior/this.zig"); |
| 66 | _ = @import("behavior/translate_c_macros.zig"); | 69 | _ = @import("behavior/translate_c_macros.zig"); |
| 67 | _ = @import("behavior/union.zig"); | 70 | _ = @import("behavior/union.zig"); |
| 68 | _ = @import("behavior/while.zig"); | ||
| 69 | _ = @import("behavior/widening.zig"); | 71 | _ = @import("behavior/widening.zig"); |
| 70 | 72 | ||
| 71 | if (builtin.zig_is_stage2) { | 73 | if (builtin.zig_is_stage2) { |
test/behavior/struct.zig-94| ... | @@ -32,38 +32,6 @@ fn returnEmptyStructInstance() StructWithNoFields { | ... | @@ -32,38 +32,6 @@ fn returnEmptyStructInstance() StructWithNoFields { |
| 32 | return empty_global_instance; | 32 | return empty_global_instance; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | const StructFoo = struct { | ||
| 36 | a: i32, | ||
| 37 | b: bool, | ||
| 38 | c: f32, | ||
| 39 | }; | ||
| 40 | test "structs" { | ||
| 41 | var foo: StructFoo = undefined; | ||
| 42 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 43 | foo.a += 1; | ||
| 44 | foo.b = foo.a == 1; | ||
| 45 | try testFoo(foo); | ||
| 46 | testMutation(&foo); | ||
| 47 | try expect(foo.c == 100); | ||
| 48 | } | ||
| 49 | fn testFoo(foo: StructFoo) !void { | ||
| 50 | try expect(foo.b); | ||
| 51 | } | ||
| 52 | fn testMutation(foo: *StructFoo) void { | ||
| 53 | foo.c = 100; | ||
| 54 | } | ||
| 55 | |||
| 56 | test "struct byval assign" { | ||
| 57 | var foo1: StructFoo = undefined; | ||
| 58 | var foo2: StructFoo = undefined; | ||
| 59 | |||
| 60 | foo1.a = 1234; | ||
| 61 | foo2.a = 0; | ||
| 62 | try expect(foo2.a == 0); | ||
| 63 | foo2 = foo1; | ||
| 64 | try expect(foo2.a == 1234); | ||
| 65 | } | ||
| 66 | |||
| 67 | const Node = struct { | 35 | const Node = struct { |
| 68 | val: Val, | 36 | val: Val, |
| 69 | next: *Node, | 37 | next: *Node, |
| ... | @@ -90,65 +58,3 @@ test "call member function directly" { | ... | @@ -90,65 +58,3 @@ test "call member function directly" { |
| 90 | const result = MemberFnTestFoo.member(instance); | 58 | const result = MemberFnTestFoo.member(instance); |
| 91 | try expect(result == 1234); | 59 | try expect(result == 1234); |
| 92 | } | 60 | } |
| 93 | |||
| 94 | test "struct point to self" { | ||
| 95 | var root: Node = undefined; | ||
| 96 | root.val.x = 1; | ||
| 97 | |||
| 98 | var node: Node = undefined; | ||
| 99 | node.next = &root; | ||
| 100 | node.val.x = 2; | ||
| 101 | |||
| 102 | root.next = &node; | ||
| 103 | |||
| 104 | try expect(node.next.next.next.val.x == 1); | ||
| 105 | } | ||
| 106 | |||
| 107 | test "void struct fields" { | ||
| 108 | const foo = VoidStructFieldsFoo{ | ||
| 109 | .a = void{}, | ||
| 110 | .b = 1, | ||
| 111 | .c = void{}, | ||
| 112 | }; | ||
| 113 | try expect(foo.b == 1); | ||
| 114 | try expect(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 115 | } | ||
| 116 | const VoidStructFieldsFoo = struct { | ||
| 117 | a: void, | ||
| 118 | b: i32, | ||
| 119 | c: void, | ||
| 120 | }; | ||
| 121 | |||
| 122 | test "member functions" { | ||
| 123 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 124 | try expect(r.getSeed() == 1234); | ||
| 125 | } | ||
| 126 | const MemberFnRand = struct { | ||
| 127 | seed: u32, | ||
| 128 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 129 | return r.seed; | ||
| 130 | } | ||
| 131 | }; | ||
| 132 | |||
| 133 | test "return struct byval from function" { | ||
| 134 | const bar = makeBar2(1234, 5678); | ||
| 135 | try expect(bar.y == 5678); | ||
| 136 | } | ||
| 137 | const Bar = struct { | ||
| 138 | x: i32, | ||
| 139 | y: i32, | ||
| 140 | }; | ||
| 141 | fn makeBar2(x: i32, y: i32) Bar { | ||
| 142 | return Bar{ | ||
| 143 | .x = x, | ||
| 144 | .y = y, | ||
| 145 | }; | ||
| 146 | } | ||
| 147 | |||
| 148 | test "return empty struct from fn" { | ||
| 149 | _ = testReturnEmptyStructFromFn(); | ||
| 150 | } | ||
| 151 | const EmptyStruct2 = struct {}; | ||
| 152 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 153 | return EmptyStruct2{}; | ||
| 154 | } |
test/behavior/struct_llvm.zig created+134| ... | @@ -0,0 +1,134 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const native_endian = builtin.target.cpu.arch.endian(); | ||
| 4 | const expect = std.testing.expect; | ||
| 5 | const expectEqual = std.testing.expectEqual; | ||
| 6 | const expectEqualSlices = std.testing.expectEqualSlices; | ||
| 7 | const maxInt = std.math.maxInt; | ||
| 8 | |||
| 9 | const StructWithNoFields = struct { | ||
| 10 | fn add(a: i32, b: i32) i32 { | ||
| 11 | return a + b; | ||
| 12 | } | ||
| 13 | }; | ||
| 14 | |||
| 15 | const StructFoo = struct { | ||
| 16 | a: i32, | ||
| 17 | b: bool, | ||
| 18 | c: f32, | ||
| 19 | }; | ||
| 20 | test "structs" { | ||
| 21 | var foo: StructFoo = undefined; | ||
| 22 | @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); | ||
| 23 | foo.a += 1; | ||
| 24 | foo.b = foo.a == 1; | ||
| 25 | try testFoo(foo); | ||
| 26 | testMutation(&foo); | ||
| 27 | try expect(foo.c == 100); | ||
| 28 | } | ||
| 29 | fn testFoo(foo: StructFoo) !void { | ||
| 30 | try expect(foo.b); | ||
| 31 | } | ||
| 32 | fn testMutation(foo: *StructFoo) void { | ||
| 33 | foo.c = 100; | ||
| 34 | } | ||
| 35 | |||
| 36 | test "struct byval assign" { | ||
| 37 | var foo1: StructFoo = undefined; | ||
| 38 | var foo2: StructFoo = undefined; | ||
| 39 | |||
| 40 | foo1.a = 1234; | ||
| 41 | foo2.a = 0; | ||
| 42 | try expect(foo2.a == 0); | ||
| 43 | foo2 = foo1; | ||
| 44 | try expect(foo2.a == 1234); | ||
| 45 | } | ||
| 46 | |||
| 47 | const Node = struct { | ||
| 48 | val: Val, | ||
| 49 | next: *Node, | ||
| 50 | }; | ||
| 51 | |||
| 52 | const Val = struct { | ||
| 53 | x: i32, | ||
| 54 | }; | ||
| 55 | |||
| 56 | test "struct initializer" { | ||
| 57 | const val = Val{ .x = 42 }; | ||
| 58 | try expect(val.x == 42); | ||
| 59 | } | ||
| 60 | |||
| 61 | const MemberFnTestFoo = struct { | ||
| 62 | x: i32, | ||
| 63 | fn member(foo: MemberFnTestFoo) i32 { | ||
| 64 | return foo.x; | ||
| 65 | } | ||
| 66 | }; | ||
| 67 | |||
| 68 | test "call member function directly" { | ||
| 69 | const instance = MemberFnTestFoo{ .x = 1234 }; | ||
| 70 | const result = MemberFnTestFoo.member(instance); | ||
| 71 | try expect(result == 1234); | ||
| 72 | } | ||
| 73 | |||
| 74 | test "struct point to self" { | ||
| 75 | var root: Node = undefined; | ||
| 76 | root.val.x = 1; | ||
| 77 | |||
| 78 | var node: Node = undefined; | ||
| 79 | node.next = &root; | ||
| 80 | node.val.x = 2; | ||
| 81 | |||
| 82 | root.next = &node; | ||
| 83 | |||
| 84 | try expect(node.next.next.next.val.x == 1); | ||
| 85 | } | ||
| 86 | |||
| 87 | test "void struct fields" { | ||
| 88 | const foo = VoidStructFieldsFoo{ | ||
| 89 | .a = void{}, | ||
| 90 | .b = 1, | ||
| 91 | .c = void{}, | ||
| 92 | }; | ||
| 93 | try expect(foo.b == 1); | ||
| 94 | try expect(@sizeOf(VoidStructFieldsFoo) == 4); | ||
| 95 | } | ||
| 96 | const VoidStructFieldsFoo = struct { | ||
| 97 | a: void, | ||
| 98 | b: i32, | ||
| 99 | c: void, | ||
| 100 | }; | ||
| 101 | |||
| 102 | test "member functions" { | ||
| 103 | const r = MemberFnRand{ .seed = 1234 }; | ||
| 104 | try expect(r.getSeed() == 1234); | ||
| 105 | } | ||
| 106 | const MemberFnRand = struct { | ||
| 107 | seed: u32, | ||
| 108 | pub fn getSeed(r: *const MemberFnRand) u32 { | ||
| 109 | return r.seed; | ||
| 110 | } | ||
| 111 | }; | ||
| 112 | |||
| 113 | test "return struct byval from function" { | ||
| 114 | const bar = makeBar2(1234, 5678); | ||
| 115 | try expect(bar.y == 5678); | ||
| 116 | } | ||
| 117 | const Bar = struct { | ||
| 118 | x: i32, | ||
| 119 | y: i32, | ||
| 120 | }; | ||
| 121 | fn makeBar2(x: i32, y: i32) Bar { | ||
| 122 | return Bar{ | ||
| 123 | .x = x, | ||
| 124 | .y = y, | ||
| 125 | }; | ||
| 126 | } | ||
| 127 | |||
| 128 | test "return empty struct from fn" { | ||
| 129 | _ = testReturnEmptyStructFromFn(); | ||
| 130 | } | ||
| 131 | const EmptyStruct2 = struct {}; | ||
| 132 | fn testReturnEmptyStructFromFn() EmptyStruct2 { | ||
| 133 | return EmptyStruct2{}; | ||
| 134 | } | ||