diff --git a/src/all_types.hpp b/src/all_types.hpp index fd66b77ad2..230dba9a42 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -691,15 +691,17 @@ struct AstNodePointerType { AstNode *align_expr; BigInt *bit_offset_start; BigInt *host_int_bytes; + AstNode *op_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; - AstNode *op_expr; }; struct AstNodeArrayType { AstNode *size; AstNode *child_type; AstNode *align_expr; + Token *allow_zero_token; bool is_const; bool is_volatile; }; @@ -1050,6 +1052,7 @@ struct ZigTypePointer { uint32_t host_int_bytes; // size of host integer. 0 means no host integer; this field is aligned bool is_const; bool is_volatile; + bool allow_zero; }; struct ZigTypeInt { @@ -1499,11 +1502,12 @@ struct TypeId { struct { ZigType *child_type; PtrLen ptr_len; - bool is_const; - bool is_volatile; uint32_t alignment; uint32_t bit_offset_in_host; uint32_t host_int_bytes; + bool is_const; + bool is_volatile; + bool allow_zero; } pointer; struct { ZigType *child_type; @@ -2592,6 +2596,7 @@ struct IrInstructionPtrType { PtrLen ptr_len; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionPromiseType { @@ -2607,6 +2612,7 @@ struct IrInstructionSliceType { IrInstruction *child_type; bool is_const; bool is_volatile; + bool allow_zero; }; struct IrInstructionAsm { diff --git a/src/analyze.cpp b/src/analyze.cpp index ab2afba561..900def52d4 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -433,6 +433,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes) { + // TODO when implementing https://github.com/ziglang/zig/issues/1953 + // move this to a parameter + bool allow_zero = (ptr_len == PtrLenC); assert(!type_is_invalid(child_type)); assert(ptr_len != PtrLenUnknown || child_type->id != ZigTypeIdOpaque); @@ -452,7 +455,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons TypeId type_id = {}; ZigType **parent_pointer = nullptr; - if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle) { + if (host_int_bytes != 0 || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || allow_zero) { type_id.id = ZigTypeIdPointer; type_id.data.pointer.child_type = child_type; type_id.data.pointer.is_const = is_const; @@ -461,6 +464,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons type_id.data.pointer.bit_offset_in_host = bit_offset_in_host; type_id.data.pointer.host_int_bytes = host_int_bytes; type_id.data.pointer.ptr_len = ptr_len; + type_id.data.pointer.allow_zero = allow_zero; auto existing_entry = g->type_table.maybe_get(type_id); if (existing_entry) @@ -481,18 +485,28 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons const char *star_str = ptr_len_to_star_str(ptr_len); const char *const_str = is_const ? "const " : ""; const char *volatile_str = is_volatile ? "volatile " : ""; + const char *allow_zero_str; + if (ptr_len == PtrLenC) { + assert(allow_zero); + allow_zero_str = ""; + } else { + allow_zero_str = allow_zero ? "allowzero " : ""; + } buf_resize(&entry->name, 0); if (host_int_bytes == 0 && byte_alignment == 0) { - buf_appendf(&entry->name, "%s%s%s%s", star_str, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%s%s%s%s%s", + star_str, const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (host_int_bytes == 0) { - buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s", star_str, byte_alignment, - const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + const_str, volatile_str, allow_zero_str, buf_ptr(&child_type->name)); } else if (byte_alignment == 0) { - buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(:%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } else { - buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s", star_str, byte_alignment, - bit_offset_in_host, host_int_bytes, const_str, volatile_str, buf_ptr(&child_type->name)); + buf_appendf(&entry->name, "%salign(%" PRIu32 ":%" PRIu32 ":%" PRIu32 ") %s%s%s%s", star_str, byte_alignment, + bit_offset_in_host, host_int_bytes, const_str, volatile_str, allow_zero_str, + buf_ptr(&child_type->name)); } assert(child_type->id != ZigTypeIdInvalid); @@ -500,7 +514,9 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->zero_bits = !type_has_bits(child_type); if (!entry->zero_bits) { - if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || bit_offset_in_host != 0) { + if (is_const || is_volatile || byte_alignment != 0 || ptr_len != PtrLenSingle || + bit_offset_in_host != 0 || allow_zero) + { ZigType *peer_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenSingle, 0, 0, host_int_bytes); entry->type_ref = peer_type->type_ref; @@ -534,6 +550,7 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons entry->data.pointer.explicit_alignment = byte_alignment; entry->data.pointer.bit_offset_in_host = bit_offset_in_host; entry->data.pointer.host_int_bytes = host_int_bytes; + entry->data.pointer.allow_zero = allow_zero; if (parent_pointer) { *parent_pointer = entry; @@ -850,7 +867,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_type = ptr_type->data.pointer.child_type; if (ptr_type->data.pointer.is_const || ptr_type->data.pointer.is_volatile || - ptr_type->data.pointer.explicit_alignment != 0) + ptr_type->data.pointer.explicit_alignment != 0 || ptr_type->data.pointer.allow_zero) { ZigType *peer_ptr_type = get_pointer_to_type_extra(g, child_type, false, false, PtrLenUnknown, 0, 0, 0); @@ -873,7 +890,7 @@ ZigType *get_slice_type(CodeGen *g, ZigType *ptr_type) { ZigType *child_ptr_type = child_type->data.structure.fields[slice_ptr_index].type_entry; assert(child_ptr_type->id == ZigTypeIdPointer); if (child_ptr_type->data.pointer.is_const || child_ptr_type->data.pointer.is_volatile || - child_ptr_type->data.pointer.explicit_alignment != 0) + child_ptr_type->data.pointer.explicit_alignment != 0 || child_ptr_type->data.pointer.allow_zero) { ZigType *grand_child_type = child_ptr_type->data.pointer.child_type; ZigType *bland_child_ptr_type = get_pointer_to_type_extra(g, grand_child_type, false, false, @@ -4053,7 +4070,9 @@ ZigType *get_src_ptr_type(ZigType *type) { if (type->id == ZigTypeIdFn) return type; if (type->id == ZigTypeIdPromise) return type; if (type->id == ZigTypeIdOptional) { - if (type->data.maybe.child_type->id == ZigTypeIdPointer) return type->data.maybe.child_type; + if (type->data.maybe.child_type->id == ZigTypeIdPointer) { + return type->data.maybe.child_type->data.pointer.allow_zero ? nullptr : type->data.maybe.child_type; + } if (type->data.maybe.child_type->id == ZigTypeIdFn) return type->data.maybe.child_type; if (type->data.maybe.child_type->id == ZigTypeIdPromise) return type->data.maybe.child_type; } @@ -6289,6 +6308,7 @@ uint32_t type_id_hash(TypeId x) { ((x.data.pointer.ptr_len == PtrLenSingle) ? (uint32_t)1120226602 : (uint32_t)3200913342) + (x.data.pointer.is_const ? (uint32_t)2749109194 : (uint32_t)4047371087) + (x.data.pointer.is_volatile ? (uint32_t)536730450 : (uint32_t)1685612214) + + (x.data.pointer.allow_zero ? (uint32_t)3324284834 : (uint32_t)3584904923) + (((uint32_t)x.data.pointer.alignment) ^ (uint32_t)0x777fbe0e) + (((uint32_t)x.data.pointer.bit_offset_in_host) ^ (uint32_t)2639019452) + (((uint32_t)x.data.pointer.host_int_bytes) ^ (uint32_t)529908881); @@ -6339,6 +6359,7 @@ bool type_id_eql(TypeId a, TypeId b) { a.data.pointer.ptr_len == b.data.pointer.ptr_len && a.data.pointer.is_const == b.data.pointer.is_const && a.data.pointer.is_volatile == b.data.pointer.is_volatile && + a.data.pointer.allow_zero == b.data.pointer.allow_zero && a.data.pointer.alignment == b.data.pointer.alignment && a.data.pointer.bit_offset_in_host == b.data.pointer.bit_offset_in_host && a.data.pointer.host_int_bytes == b.data.pointer.host_int_bytes; diff --git a/src/ir.cpp b/src/ir.cpp index 50b5661e12..19bec193d5 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -61,7 +61,7 @@ enum ConstCastResultId { ConstCastResultIdType, ConstCastResultIdUnresolvedInferredErrSet, ConstCastResultIdAsyncAllocatorType, - ConstCastResultIdNullWrapPtr + ConstCastResultIdBadAllowsZero, }; struct ConstCastOnly; @@ -83,6 +83,7 @@ struct ConstCastErrUnionErrSetMismatch; struct ConstCastErrUnionPayloadMismatch; struct ConstCastErrSetMismatch; struct ConstCastTypeMismatch; +struct ConstCastBadAllowsZero; struct ConstCastOnly { ConstCastResultId id; @@ -99,6 +100,7 @@ struct ConstCastOnly { ConstCastOnly *null_wrap_ptr_child; ConstCastArg fn_arg; ConstCastArgNoAlias arg_no_alias; + ConstCastBadAllowsZero *bad_allows_zero; } data; }; @@ -141,6 +143,12 @@ struct ConstCastErrSetMismatch { ZigList missing_errors; }; +struct ConstCastBadAllowsZero { + ZigType *wanted_type; + ZigType *actual_type; +}; + + enum UndefAllowed { UndefOk, UndefBad, @@ -8636,6 +8644,14 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp return err_set_type; } +static bool ptr_allows_addr_zero(ZigType *ptr_type) { + if (ptr_type->id == ZigTypeIdPointer) { + return ptr_type->data.pointer.allow_zero; + } else if (ptr_type->id == ZigTypeIdOptional) { + return true; + } + return false; +} static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted_type, ZigType *actual_type, AstNode *source_node, bool wanted_is_mutable) @@ -8649,34 +8665,35 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted if (wanted_type == actual_type) return result; - // *T and [*]T may const-cast-only to ?*U and ?[*]U, respectively - // but not if we want a mutable pointer - // and not if the actual pointer has zero bits - if (!wanted_is_mutable && wanted_type->id == ZigTypeIdOptional && - wanted_type->data.maybe.child_type->id == ZigTypeIdPointer && - actual_type->id == ZigTypeIdPointer && type_has_bits(actual_type)) - { - ConstCastOnly child = types_match_const_cast_only(ira, - wanted_type->data.maybe.child_type, actual_type, source_node, wanted_is_mutable); - if (child.id == ConstCastResultIdInvalid) - return child; - if (child.id != ConstCastResultIdOk) { - result.id = ConstCastResultIdNullWrapPtr; - result.data.null_wrap_ptr_child = allocate_nonzero(1); - *result.data.null_wrap_ptr_child = child; - } - return result; - } - - // pointer const + // If pointers have the same representation in memory, they can be "const-casted". + // `const` attribute can be gained + // `volatile` attribute can be gained + // `allowzero` attribute can be gained (whether from explicit attribute, C pointer, or optional pointer) + // but only if !wanted_is_mutable + // alignment can be decreased + // bit offset attributes must match exactly + // PtrLenSingle/PtrLenUnknown must match exactly, but PtrLenC matches either one ZigType *wanted_ptr_type = get_src_ptr_type(wanted_type); ZigType *actual_ptr_type = get_src_ptr_type(actual_type); + bool wanted_allows_zero = ptr_allows_addr_zero(wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(actual_type); bool wanted_is_c_ptr = wanted_type->id == ZigTypeIdPointer && wanted_type->data.pointer.ptr_len == PtrLenC; bool actual_is_c_ptr = actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenC; - if ((wanted_type->id == ZigTypeIdPointer && actual_type->id == ZigTypeIdPointer) || - (wanted_ptr_type != nullptr && actual_is_c_ptr) || - (actual_ptr_type != nullptr && wanted_is_c_ptr)) - { + bool wanted_opt_or_ptr = wanted_ptr_type != nullptr && + (wanted_type->id == ZigTypeIdPointer || wanted_type->id == ZigTypeIdOptional); + bool actual_opt_or_ptr = actual_ptr_type != nullptr && + (actual_type->id == ZigTypeIdPointer || actual_type->id == ZigTypeIdOptional); + if (wanted_opt_or_ptr && actual_opt_or_ptr) { + bool ok_allows_zero = (wanted_allows_zero && + (actual_allows_zero || wanted_ptr_type->data.pointer.is_const)) || + (!wanted_allows_zero && !actual_allows_zero); + if (!ok_allows_zero) { + result.id = ConstCastResultIdBadAllowsZero; + result.data.bad_allows_zero = allocate_nonzero(1); + result.data.bad_allows_zero->wanted_type = wanted_type; + result.data.bad_allows_zero->actual_type = actual_type; + return result; + } ConstCastOnly child = types_match_const_cast_only(ira, wanted_ptr_type->data.pointer.child_type, actual_ptr_type->data.pointer.child_type, source_node, !wanted_ptr_type->data.pointer.is_const); if (child.id == ConstCastResultIdInvalid) @@ -8699,6 +8716,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted } bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && + type_has_bits(wanted_type) == type_has_bits(actual_type) && (!actual_ptr_type->data.pointer.is_const || wanted_ptr_type->data.pointer.is_const) && (!actual_ptr_type->data.pointer.is_volatile || wanted_ptr_type->data.pointer.is_volatile) && actual_ptr_type->data.pointer.bit_offset_in_host == wanted_ptr_type->data.pointer.bit_offset_in_host && @@ -9922,7 +9940,7 @@ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, Un if (undef_allowed == UndefOk) { return &value->value; } else { - ir_add_error(ira, value, buf_sprintf("use of undefined value")); + ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior")); return nullptr; } } @@ -10828,6 +10846,26 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa report_recursive_error(ira, source_node, cast_result->data.fn_arg.child, msg); break; } + case ConstCastResultIdBadAllowsZero: { + bool wanted_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->wanted_type); + bool actual_allows_zero = ptr_allows_addr_zero(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->wanted_type); + ZigType *actual_ptr_type = get_src_ptr_type(cast_result->data.bad_allows_zero->actual_type); + ZigType *wanted_elem_type = wanted_ptr_type->data.pointer.child_type; + ZigType *actual_elem_type = actual_ptr_type->data.pointer.child_type; + if (actual_allows_zero && !wanted_allows_zero) { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("'%s' could have null values which are illegal in type '%s'", + buf_ptr(&actual_elem_type->name), + buf_ptr(&wanted_elem_type->name))); + } else { + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("mutable '%s' allows illegal null values stored to type '%s'", + buf_ptr(&cast_result->data.bad_allows_zero->wanted_type->name), + buf_ptr(&cast_result->data.bad_allows_zero->actual_type->name))); + } + break; + } case ConstCastResultIdFnAlign: // TODO case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO @@ -10838,7 +10876,6 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa case ConstCastResultIdFnArgNoAlias: // TODO case ConstCastResultIdUnresolvedInferredErrSet: // TODO case ConstCastResultIdAsyncAllocatorType: // TODO - case ConstCastResultIdNullWrapPtr: // TODO break; } } @@ -20589,12 +20626,14 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ // We have a check for zero bits later so we use get_src_ptr_type to // validate src_type and dest_type. - if (get_src_ptr_type(src_type) == nullptr) { + ZigType *src_ptr_type = get_src_ptr_type(src_type); + if (src_ptr_type == nullptr) { ir_add_error(ira, ptr, buf_sprintf("expected pointer, found '%s'", buf_ptr(&src_type->name))); return ira->codegen->invalid_instruction; } - if (get_src_ptr_type(dest_type) == nullptr) { + ZigType *dest_ptr_type = get_src_ptr_type(dest_type); + if (dest_ptr_type == nullptr) { ir_add_error(ira, dest_type_src, buf_sprintf("expected pointer, found '%s'", buf_ptr(&dest_type->name))); return ira->codegen->invalid_instruction; @@ -20606,6 +20645,8 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } if (instr_is_comptime(ptr)) { + // Undefined is OK here; @ptrCast is defined to reinterpret the bit pattern + // of the pointer as the new pointer type. ConstExprValue *val = ir_resolve_const(ira, ptr, UndefOk); if (!val) return ira->codegen->invalid_instruction; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 8f8e2a0bdf..c51a65cadf 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -1,6 +1,30 @@ const tests = @import("tests.zig"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.addTest( + "implicit casting C pointers which would mess up null semantics", + \\export fn entry() void { + \\ var slice: []const u8 = "aoeu"; + \\ const opt_many_ptr: [*]const u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]const u8 = ptr_opt_many_ptr; + \\ ptr_opt_many_ptr = c_ptr; + \\} + \\export fn entry2() void { + \\ var buf: [4]u8 = "aoeu"; + \\ var slice: []u8 = &buf; + \\ var opt_many_ptr: [*]u8 = slice.ptr; + \\ var ptr_opt_many_ptr = &opt_many_ptr; + \\ var c_ptr: [*c]const [*c]u8 = ptr_opt_many_ptr; + \\} + , + ".tmp_source.zig:6:24: error: expected type '*const [*]const u8', found '[*c]const [*c]const u8'", + ".tmp_source.zig:6:24: note: '[*c]const u8' could have null values which are illegal in type '[*]const u8'", + ".tmp_source.zig:13:35: error: expected type '[*c]const [*c]u8', found '*[*]u8'", + ".tmp_source.zig:13:35: note: pointer type child '[*]u8' cannot cast into pointer type child '[*c]u8'", + ".tmp_source.zig:13:35: note: mutable '[*c]u8' allows illegal null values stored to type '[*]u8'", + ); + cases.addTest( "implicit casting too big integers to C pointers", \\export fn a() void { @@ -31,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ var z = @truncate(u8, u16(undefined)); \\} , - ".tmp_source.zig:2:30: error: use of undefined value", + ".tmp_source.zig:2:30: error: use of undefined value here causes undefined behavior", ); cases.addTest( @@ -392,7 +416,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ f(i32); \\} , - ".tmp_source.zig:4:5: error: use of undefined value", + ".tmp_source.zig:4:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -792,7 +816,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -805,7 +829,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ command.exec(); \\} , - ".tmp_source.zig:6:12: error: use of undefined value", + ".tmp_source.zig:6:12: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2776,7 +2800,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ \\export fn entry() usize { return @sizeOf(@typeOf(x)); } , - ".tmp_source.zig:1:15: error: use of undefined value", + ".tmp_source.zig:1:15: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2786,7 +2810,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a / a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2796,7 +2820,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a /= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2806,7 +2830,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a % a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2816,7 +2840,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a %= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2826,7 +2850,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a + a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2836,7 +2860,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a += a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2846,7 +2870,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a +% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2856,7 +2880,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a +%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2866,7 +2890,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a - a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2876,7 +2900,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2886,7 +2910,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a -% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2896,7 +2920,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a -%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2906,7 +2930,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a * a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2916,7 +2940,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2926,7 +2950,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a *% a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2936,7 +2960,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a *%= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2946,7 +2970,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a << 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2956,7 +2980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a <<= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2966,7 +2990,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >> 2; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2976,7 +3000,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a >>= 2; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2986,7 +3010,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a & a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -2996,7 +3020,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a &= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3006,7 +3030,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a | a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3016,7 +3040,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a |= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3026,7 +3050,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a ^ a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3036,7 +3060,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ a ^= a; \\} , - ".tmp_source.zig:3:5: error: use of undefined value", + ".tmp_source.zig:3:5: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3046,7 +3070,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a == a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3056,7 +3080,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a != a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3066,7 +3090,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a > a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3076,7 +3100,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a >= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3086,7 +3110,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a < a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3096,7 +3120,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a <= a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3106,7 +3130,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a and a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3116,7 +3140,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a or a; \\} , - ".tmp_source.zig:3:9: error: use of undefined value", + ".tmp_source.zig:3:9: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3126,7 +3150,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3136,7 +3160,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = -%a; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3146,7 +3170,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = ~a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3156,7 +3180,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = !a; \\} , - ".tmp_source.zig:3:10: error: use of undefined value", + ".tmp_source.zig:3:10: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3166,7 +3190,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a orelse false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add( @@ -3176,7 +3200,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { \\ _ = a catch |err| false; \\} , - ".tmp_source.zig:3:11: error: use of undefined value", + ".tmp_source.zig:3:11: error: use of undefined value here causes undefined behavior", ); cases.add(