diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 5935985961..29e0f1e50e 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -448,7 +448,12 @@ pub const DeclGen = struct { try w.writeAll("ZIG_COLD "); } } - try dg.renderType(w, dg.decl.ty.fnReturnType()); + const return_ty = dg.decl.ty.fnReturnType(); + if (return_ty.hasCodeGenBits()) { + try dg.renderType(w, return_ty); + } else { + try w.writeAll("void"); + } try w.writeAll(" "); try dg.renderDeclName(dg.decl, w); try w.writeAll("("); @@ -947,6 +952,10 @@ pub fn genDecl(o: *Object) !void { } try fwd_decl_writer.writeAll(";\n"); + if (variable.init.isUndef()) { + return; + } + try o.indent_writer.insertNewline(); const w = o.writer(); try o.dg.renderType(w, o.dg.decl.ty); @@ -1886,6 +1895,9 @@ fn airBr(f: *Function, inst: Air.Inst.Index) !CValue { } fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { + if (f.liveness.isUnused(inst)) + return CValue.none; + const ty_op = f.air.instructions.items(.data)[inst].ty_op; const operand = try f.resolveInst(ty_op.operand); diff --git a/test/behavior.zig b/test/behavior.zig index 382290031f..9ef98bd772 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -21,12 +21,15 @@ test { _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/hasfield.zig"); _ = @import("behavior/if.zig"); + _ = @import("behavior/struct.zig"); + _ = @import("behavior/truncate.zig"); _ = @import("behavior/null.zig"); _ = @import("behavior/ptrcast.zig"); _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/truncate.zig"); _ = @import("behavior/underscore.zig"); _ = @import("behavior/usingnamespace.zig"); + _ = @import("behavior/while.zig"); if (builtin.object_format != .c) { // Tests that pass for stage1 and stage2 but not the C backend. @@ -60,12 +63,11 @@ test { _ = @import("behavior/saturating_arithmetic.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/slice.zig"); - _ = @import("behavior/struct.zig"); + _ = @import("behavior/struct_llvm.zig"); _ = @import("behavior/switch.zig"); _ = @import("behavior/this.zig"); _ = @import("behavior/translate_c_macros.zig"); _ = @import("behavior/union.zig"); - _ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); if (builtin.zig_is_stage2) { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 104fe64b4c..eeaa80ed69 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -32,38 +32,6 @@ fn returnEmptyStructInstance() StructWithNoFields { return empty_global_instance; } -const StructFoo = struct { - a: i32, - b: bool, - c: f32, -}; -test "structs" { - var foo: StructFoo = undefined; - @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); - foo.a += 1; - foo.b = foo.a == 1; - try testFoo(foo); - testMutation(&foo); - try expect(foo.c == 100); -} -fn testFoo(foo: StructFoo) !void { - try expect(foo.b); -} -fn testMutation(foo: *StructFoo) void { - foo.c = 100; -} - -test "struct byval assign" { - var foo1: StructFoo = undefined; - var foo2: StructFoo = undefined; - - foo1.a = 1234; - foo2.a = 0; - try expect(foo2.a == 0); - foo2 = foo1; - try expect(foo2.a == 1234); -} - const Node = struct { val: Val, next: *Node, @@ -90,65 +58,3 @@ test "call member function directly" { const result = MemberFnTestFoo.member(instance); try expect(result == 1234); } - -test "struct point to self" { - var root: Node = undefined; - root.val.x = 1; - - var node: Node = undefined; - node.next = &root; - node.val.x = 2; - - root.next = &node; - - try expect(node.next.next.next.val.x == 1); -} - -test "void struct fields" { - const foo = VoidStructFieldsFoo{ - .a = void{}, - .b = 1, - .c = void{}, - }; - try expect(foo.b == 1); - try expect(@sizeOf(VoidStructFieldsFoo) == 4); -} -const VoidStructFieldsFoo = struct { - a: void, - b: i32, - c: void, -}; - -test "member functions" { - const r = MemberFnRand{ .seed = 1234 }; - try expect(r.getSeed() == 1234); -} -const MemberFnRand = struct { - seed: u32, - pub fn getSeed(r: *const MemberFnRand) u32 { - return r.seed; - } -}; - -test "return struct byval from function" { - const bar = makeBar2(1234, 5678); - try expect(bar.y == 5678); -} -const Bar = struct { - x: i32, - y: i32, -}; -fn makeBar2(x: i32, y: i32) Bar { - return Bar{ - .x = x, - .y = y, - }; -} - -test "return empty struct from fn" { - _ = testReturnEmptyStructFromFn(); -} -const EmptyStruct2 = struct {}; -fn testReturnEmptyStructFromFn() EmptyStruct2 { - return EmptyStruct2{}; -} diff --git a/test/behavior/struct_llvm.zig b/test/behavior/struct_llvm.zig new file mode 100644 index 0000000000..e4905e510f --- /dev/null +++ b/test/behavior/struct_llvm.zig @@ -0,0 +1,134 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const native_endian = builtin.target.cpu.arch.endian(); +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectEqualSlices = std.testing.expectEqualSlices; +const maxInt = std.math.maxInt; + +const StructWithNoFields = struct { + fn add(a: i32, b: i32) i32 { + return a + b; + } +}; + +const StructFoo = struct { + a: i32, + b: bool, + c: f32, +}; +test "structs" { + var foo: StructFoo = undefined; + @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo)); + foo.a += 1; + foo.b = foo.a == 1; + try testFoo(foo); + testMutation(&foo); + try expect(foo.c == 100); +} +fn testFoo(foo: StructFoo) !void { + try expect(foo.b); +} +fn testMutation(foo: *StructFoo) void { + foo.c = 100; +} + +test "struct byval assign" { + var foo1: StructFoo = undefined; + var foo2: StructFoo = undefined; + + foo1.a = 1234; + foo2.a = 0; + try expect(foo2.a == 0); + foo2 = foo1; + try expect(foo2.a == 1234); +} + +const Node = struct { + val: Val, + next: *Node, +}; + +const Val = struct { + x: i32, +}; + +test "struct initializer" { + const val = Val{ .x = 42 }; + try expect(val.x == 42); +} + +const MemberFnTestFoo = struct { + x: i32, + fn member(foo: MemberFnTestFoo) i32 { + return foo.x; + } +}; + +test "call member function directly" { + const instance = MemberFnTestFoo{ .x = 1234 }; + const result = MemberFnTestFoo.member(instance); + try expect(result == 1234); +} + +test "struct point to self" { + var root: Node = undefined; + root.val.x = 1; + + var node: Node = undefined; + node.next = &root; + node.val.x = 2; + + root.next = &node; + + try expect(node.next.next.next.val.x == 1); +} + +test "void struct fields" { + const foo = VoidStructFieldsFoo{ + .a = void{}, + .b = 1, + .c = void{}, + }; + try expect(foo.b == 1); + try expect(@sizeOf(VoidStructFieldsFoo) == 4); +} +const VoidStructFieldsFoo = struct { + a: void, + b: i32, + c: void, +}; + +test "member functions" { + const r = MemberFnRand{ .seed = 1234 }; + try expect(r.getSeed() == 1234); +} +const MemberFnRand = struct { + seed: u32, + pub fn getSeed(r: *const MemberFnRand) u32 { + return r.seed; + } +}; + +test "return struct byval from function" { + const bar = makeBar2(1234, 5678); + try expect(bar.y == 5678); +} +const Bar = struct { + x: i32, + y: i32, +}; +fn makeBar2(x: i32, y: i32) Bar { + return Bar{ + .x = x, + .y = y, + }; +} + +test "return empty struct from fn" { + _ = testReturnEmptyStructFromFn(); +} +const EmptyStruct2 = struct {}; +fn testReturnEmptyStructFromFn() EmptyStruct2 { + return EmptyStruct2{}; +}