From 58c2bec589d6d90db31744430407bc88695b5161 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 24 Nov 2020 10:14:16 +0100 Subject: [PATCH] stage1: Fix ICE when generating struct fields with padding Make gen_const_ptr_struct_recursive aware of the possible presence of some trailing padding by always bitcasting the pointer to its expected type. Not an elegant solution but makes LLVM happy and is consistent with how the other callsites are handling this case. Fixes #5398 --- src/stage1/codegen.cpp | 9 ++++++++- test/stage1/behavior.zig | 1 + test/stage1/behavior/bugs/5398.zig | 31 ++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 test/stage1/behavior/bugs/5398.zig diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index d0bb9b441159b9b30b5d8bff481c0d62b95c4c1c..6a02f2912ba1db8df463bc9fee359b729ad6db76 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -7038,7 +7038,14 @@ static LLVMValueRef gen_const_ptr_struct_recursive(CodeGen *g, ZigValue *struct_ LLVMConstNull(get_llvm_type(g, u32)), LLVMConstInt(get_llvm_type(g, u32), field_index, false), }; - return LLVMConstInBoundsGEP(base_ptr, indices, 2); + + // The structure pointed by base_ptr may include trailing padding for + // alignment purposes and have the following LLVM type: <{ %T, [N x i8] }>. + // Add an extra bitcast as we're only interested in the %T part. + assert(handle_is_ptr(g, struct_const_val->type)); + LLVMValueRef casted_base_ptr = LLVMConstBitCast(base_ptr, + LLVMPointerType(get_llvm_type(g, struct_const_val->type), 0)); + return LLVMConstInBoundsGEP(casted_base_ptr, indices, 2); } static LLVMValueRef gen_const_ptr_err_union_code_recursive(CodeGen *g, ZigValue *err_union_const_val) { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 86e9619d26b2002ae794052b6097d3cc745f9104..662a7383b3973cce3d7abfdba041f307291010f9 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -50,6 +50,7 @@ comptime { _ = @import("behavior/bugs/4769_b.zig"); _ = @import("behavior/bugs/4769_c.zig"); _ = @import("behavior/bugs/4954.zig"); + _ = @import("behavior/bugs/5398.zig"); _ = @import("behavior/bugs/5413.zig"); _ = @import("behavior/bugs/5474.zig"); _ = @import("behavior/bugs/5487.zig"); diff --git a/test/stage1/behavior/bugs/5398.zig b/test/stage1/behavior/bugs/5398.zig new file mode 100644 index 0000000000000000000000000000000000000000..fdfd0b3698e7fbaa39c3f103f2ae657d1933031a --- /dev/null +++ b/test/stage1/behavior/bugs/5398.zig @@ -0,0 +1,31 @@ +const std = @import("std"); +const testing = std.testing; + +pub const Mesh = struct { + id: u32, +}; +pub const Material = struct { + transparent: bool = true, + emits_shadows: bool = true, + render_color: bool = true, +}; +pub const Renderable = struct { + material: Material, + // The compiler inserts some padding here to ensure Mesh is correctly aligned. + mesh: Mesh, +}; + +var renderable: Renderable = undefined; + +test "assignment of field with padding" { + renderable = Renderable{ + .mesh = Mesh{ .id = 0 }, + .material = Material{ + .transparent = false, + .emits_shadows = false, + }, + }; + testing.expectEqual(false, renderable.material.transparent); + testing.expectEqual(false, renderable.material.emits_shadows); + testing.expectEqual(true, renderable.material.render_color); +} -- 2.54.0