diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 908b85e701..3aef5a8f92 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -279,7 +279,7 @@ pub const DeclGen = struct { ty: Type, val: Value, ) error{ OutOfMemory, AnalysisFail }!void { - if (val.isUndef()) { + if (val.isUndefDeep()) { switch (ty.zigTypeTag()) { // Using '{}' for integer and floats seemed to error C compilers (both GCC and Clang) // with 'error: expected expression' (including when built with 'zig cc') @@ -1049,7 +1049,7 @@ pub fn genDecl(o: *Object) !void { } try fwd_decl_writer.writeAll(";\n"); - if (variable.init.isUndef()) { + if (variable.init.isUndefDeep()) { return; } @@ -1602,8 +1602,10 @@ fn airStore(f: *Function, inst: Air.Inst.Index) !CValue { const src_val = try f.resolveInst(bin_op.rhs); const lhs_type = f.air.typeOf(bin_op.lhs); + // TODO Sema should emit a different instruction when the store should + // possibly do the safety 0xaa bytes for undefined. const src_val_is_undefined = - if (f.air.value(bin_op.rhs)) |v| v.isUndef() else false; + if (f.air.value(bin_op.rhs)) |v| v.isUndefDeep() else false; if (src_val_is_undefined) return try airStoreUndefined(f, dest_ptr, lhs_type); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index d0f6d62ad7..306a3df83c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1078,7 +1078,7 @@ pub const DeclGen = struct { }; return self.context.constStruct(&fields, fields.len, .False); }, - .int_u64 => { + .int_u64, .one, .int_big_positive => { const llvm_usize = try self.llvmType(Type.usize); const llvm_int = llvm_usize.constInt(tv.val.toUnsignedInt(), .False); return llvm_int.constIntToPtr(try self.llvmType(tv.ty)); @@ -3464,8 +3464,30 @@ pub const FuncGen = struct { const bin_op = self.air.instructions.items(.data)[inst].bin_op; const dest_ptr = try self.resolveInst(bin_op.lhs); const ptr_ty = self.air.typeOf(bin_op.lhs); - const src_operand = try self.resolveInst(bin_op.rhs); - self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); + + // TODO Sema should emit a different instruction when the store should + // possibly do the safety 0xaa bytes for undefined. + const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; + if (val_is_undef) { + const elem_ty = ptr_ty.childType(); + const target = self.dg.module.getTarget(); + const elem_size = elem_ty.abiSize(target); + const u8_llvm_ty = self.context.intType(8); + const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0); + const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, ""); + const fill_char = u8_llvm_ty.constInt(0xaa, .False); + const dest_ptr_align = ptr_ty.ptrAlignment(target); + const usize_llvm_ty = try self.dg.llvmType(Type.usize); + const len = usize_llvm_ty.constInt(elem_size, .False); + _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr()); + if (self.dg.module.comp.bin_file.options.valgrind) { + // TODO generate valgrind client request to mark byte range as undefined + // see gen_valgrind_undef() in codegen.cpp + } + } else { + const src_operand = try self.resolveInst(bin_op.rhs); + self.store(dest_ptr, ptr_ty, src_operand, .NotAtomic); + } return null; } @@ -3651,7 +3673,7 @@ pub const FuncGen = struct { const dest_ptr = try self.resolveInst(pl_op.operand); const ptr_ty = self.air.typeOf(pl_op.operand); const value = try self.resolveInst(extra.lhs); - const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndef() else false; + const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndefDeep() else false; const len = try self.resolveInst(extra.rhs); const u8_llvm_ty = self.context.intType(8); const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0); diff --git a/src/value.zig b/src/value.zig index 4b571891f4..4eaa865149 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1802,6 +1802,13 @@ pub const Value = extern union { return self.tag() == .undef; } + /// TODO: check for cases such as array that is not marked undef but all the element + /// values are marked undef, or struct that is not marked undef but all fields are marked + /// undef, etc. + pub fn isUndefDeep(self: Value) bool { + return self.isUndef(); + } + /// Asserts the value is not undefined and not unreachable. /// Integer value 0 is considered null because of C pointers. pub fn isNull(self: Value) bool { diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index 5350b09534..607df6a8e8 100644 --- a/test/behavior/cast.zig +++ b/test/behavior/cast.zig @@ -251,8 +251,13 @@ test "*const ?[*]const T to [*c]const [*c]const T" { test "array coersion to undefined at runtime" { @setRuntimeSafety(true); - // setRuntimeSafety isn't recognized on stage2 - if (@import("builtin").zig_is_stage2 and @import("builtin").mode != .Debug and @import("builtin").mode != .ReleaseSafe) return error.SkipZigTest; + // TODO implement @setRuntimeSafety in stage2 + if (@import("builtin").zig_is_stage2 and + @import("builtin").mode != .Debug and + @import("builtin").mode != .ReleaseSafe) + { + return error.SkipZigTest; + } var array = [4]u8{ 3, 4, 5, 6 }; var undefined_val = [4]u8{ 0xAA, 0xAA, 0xAA, 0xAA }; diff --git a/test/behavior/int128.zig b/test/behavior/int128.zig index 6b4e2de895..12367b2e9c 100644 --- a/test/behavior/int128.zig +++ b/test/behavior/int128.zig @@ -20,8 +20,13 @@ test "uint128" { test "undefined 128 bit int" { @setRuntimeSafety(true); - // setRuntimeSafety isn't recognized on stage2 - if (@import("builtin").zig_is_stage2 and @import("builtin").mode != .Debug and @import("builtin").mode != .ReleaseSafe) return error.SkipZigTest; + // TODO implement @setRuntimeSafety in stage2 + if (@import("builtin").zig_is_stage2 and + @import("builtin").mode != .Debug and + @import("builtin").mode != .ReleaseSafe) + { + return error.SkipZigTest; + } var undef: u128 = undefined; var undef_signed: i128 = undefined;