From 4d8a6f6fea1b6922e7904b33c5b575249213fe53 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Aug 2019 12:48:48 -0400 Subject: fix compiler not checking alignment of function frames closes #3086 --- src/ir.cpp | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 0129081e22..15c570ddd9 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -12110,7 +12110,26 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst array_type->data.array.child_type, source_node, !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); + // If the pointers both have ABI align, it works. + bool ok_align = slice_ptr_type->data.pointer.explicit_alignment == 0 && + actual_type->data.pointer.explicit_alignment == 0; + if (!ok_align) { + // If either one has non ABI align, we have to resolve them both + if ((err = type_resolve(ira->codegen, actual_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + if ((err = type_resolve(ira->codegen, slice_ptr_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + ok_align = get_ptr_align(ira->codegen, actual_type) >= get_ptr_align(ira->codegen, slice_ptr_type); + } + if (ok_align) { + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); + } } } @@ -15421,7 +15440,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *casted_new_stack = nullptr; if (call_instruction->new_stack != nullptr) { ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, - false, false, PtrLenUnknown, 0, 0, 0, false); + false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); IrInstruction *new_stack = call_instruction->new_stack->child; if (type_is_invalid(new_stack->value.type)) -- cgit v1.2.3 From 0ff396c34f93b60a000e1ee50e881a8c25122b79 Mon Sep 17 00:00:00 2001 From: Vexu <15308111+Vexu@users.noreply.github.com> Date: Sat, 17 Aug 2019 22:51:25 +0300 Subject: add compile error for incorrect atomic ordering in fence #3082 --- src/ir.cpp | 6 ++++++ test/compile_errors.zig | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 15c570ddd9..51f849ce19 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -20860,6 +20860,12 @@ static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstruction if (!ir_resolve_atomic_order(ira, order_value, &order)) return ira->codegen->invalid_instruction; + if (order < AtomicOrderAcquire) { + ir_add_error(ira, order_value, + buf_sprintf("atomic ordering must be Acquire or stricter")); + return ira->codegen->invalid_instruction; + } + IrInstruction *result = ir_build_fence(&ira->new_irb, instruction->base.scope, instruction->base.source_node, order_value, order); result->value.type = ira->codegen->builtin_types.entry_void; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 2088b32d98..d0c12e7cf6 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -14,6 +14,15 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { "tmp.zig:4:21: error: expected type '[]align(16) u8', found '*[64]u8'", ); + cases.add( + "atomic orderings of fence Acquire or stricter", + \\export fn entry() void { + \\ @fence(.Monotonic); + \\} + , + "tmp.zig:2:12: error: atomic ordering must be Acquire or stricter", + ); + cases.add( "bad alignment in implicit cast from array pointer to slice", \\export fn a() void { -- cgit v1.2.3 From 66a490c27c01c958d8d20dbc289c6b2b934a724e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Aug 2019 16:49:23 -0400 Subject: detect non-async function pointer of inferred async function closes #3075 --- src/all_types.hpp | 1 + src/analyze.cpp | 11 +++++++++-- src/ir.cpp | 18 ++++++++++++++++++ test/compile_errors.zig | 15 +++++++++++++++ 4 files changed, 43 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index f1c699ba10..f075dd7c58 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1396,6 +1396,7 @@ struct ZigFn { AstNode *set_cold_node; const AstNode *inferred_async_node; ZigFn *inferred_async_fn; + AstNode *non_async_node; ZigList export_list; ZigList call_list; diff --git a/src/analyze.cpp b/src/analyze.cpp index 4aff6da8e9..16e66a5906 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4144,8 +4144,15 @@ void semantic_analyze(CodeGen *g) { // second pass over functions for detecting async for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { - ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); - analyze_fn_async(g, fn_entry, true); + ZigFn *fn = g->fn_defs.at(g->fn_defs_index); + analyze_fn_async(g, fn, true); + if (fn_is_async(fn) && fn->non_async_node != nullptr) { + ErrorMsg *msg = add_node_error(g, fn->proto_node, + buf_sprintf("'%s' cannot be async", buf_ptr(&fn->symbol_name))); + add_error_note(g, msg, fn->non_async_node, + buf_sprintf("required to be non-async here")); + add_async_error_notes(g, msg, fn); + } } } diff --git a/src/ir.cpp b/src/ir.cpp index 51f849ce19..c37fac2f52 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15160,6 +15160,20 @@ no_mem_slot: return var_ptr_instruction; } +// This function is called when a comptime value becomes accessible at runtime. +static void mark_comptime_value_escape(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *val) { + ir_assert(value_is_comptime(val), source_instr); + if (val->special == ConstValSpecialUndef) + return; + + if (val->type->id == ZigTypeIdFn && val->type->data.fn.fn_type_id.cc == CallingConventionUnspecified) { + ir_assert(val->data.x_ptr.special == ConstPtrSpecialFunction, source_instr); + if (val->data.x_ptr.data.fn.fn_entry->non_async_node == nullptr) { + val->data.x_ptr.data.fn.fn_entry->non_async_node = source_instr->source_node; + } + } +} + static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *ptr, IrInstruction *uncasted_value, bool allow_write_through_const) { @@ -15256,6 +15270,10 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source break; } + if (instr_is_comptime(value)) { + mark_comptime_value_escape(ira, source_instr, &value->value); + } + IrInstructionStorePtr *store_ptr = ir_build_store_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, ptr, value); return &store_ptr->base; diff --git a/test/compile_errors.zig b/test/compile_errors.zig index d0c12e7cf6..654171f553 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,21 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "non-async function pointer eventually is inferred to become async", + \\export fn a() void { + \\ var non_async_fn: fn () void = undefined; + \\ non_async_fn = func; + \\} + \\fn func() void { + \\ suspend; + \\} + , + "tmp.zig:5:1: error: 'func' cannot be async", + "tmp.zig:3:20: note: required to be non-async here", + "tmp.zig:6:5: note: suspends here", + ); + cases.add( "bad alignment in @asyncCall", \\export fn entry() void { -- cgit v1.2.3 From 57b90d2d98154e382c58f1b385de2bcef132f7d9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 17 Aug 2019 17:22:20 -0400 Subject: allow implicit cast of fn to async fn it forces the fn to be async. closes #3079 --- src/ir.cpp | 29 ++++++++++++++++++++++++----- test/stage1/behavior/async_fn.zig | 27 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index c37fac2f52..31b354be3a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9485,10 +9485,6 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted result.id = ConstCastResultIdFnAlign; return result; } - if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) { - result.id = ConstCastResultIdFnCC; - return result; - } if (wanted_type->data.fn.fn_type_id.is_var_args != actual_type->data.fn.fn_type_id.is_var_args) { result.id = ConstCastResultIdFnVarArgs; return result; @@ -9546,6 +9542,11 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted return result; } } + if (wanted_type->data.fn.fn_type_id.cc != actual_type->data.fn.fn_type_id.cc) { + // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. + result.id = ConstCastResultIdFnCC; + return result; + } return result; } @@ -11780,8 +11781,11 @@ static void report_recursive_error(IrAnalyze *ira, AstNode *source_node, ConstCa add_error_note(ira->codegen, parent_msg, source_node, buf_sprintf("only one of the functions is generic")); break; + case ConstCastResultIdFnCC: + add_error_note(ira->codegen, parent_msg, source_node, + buf_sprintf("calling convention mismatch")); + break; case ConstCastResultIdFnAlign: // TODO - case ConstCastResultIdFnCC: // TODO case ConstCastResultIdFnVarArgs: // TODO case ConstCastResultIdFnReturnType: // TODO case ConstCastResultIdFnArgCount: // TODO @@ -11891,6 +11895,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop); } + if (const_cast_result.id == ConstCastResultIdFnCC) { + ir_assert(value->value.type->id == ZigTypeIdFn, source_instr); + // ConstCastResultIdFnCC is guaranteed to be the last one reported, meaning everything else is ok. + if (wanted_type->data.fn.fn_type_id.cc == CallingConventionAsync && + actual_type->data.fn.fn_type_id.cc == CallingConventionUnspecified) + { + ir_assert(value->value.data.x_ptr.special == ConstPtrSpecialFunction, source_instr); + ZigFn *fn = value->value.data.x_ptr.data.fn.fn_entry; + if (fn->inferred_async_node == nullptr) { + fn->inferred_async_node = source_instr->source_node; + } + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop); + } + } + // cast from T to ?T // note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism if (wanted_type->id == ZigTypeIdOptional) { diff --git a/test/stage1/behavior/async_fn.zig b/test/stage1/behavior/async_fn.zig index cb9bf2c1ea..ccfc4d1ea6 100644 --- a/test/stage1/behavior/async_fn.zig +++ b/test/stage1/behavior/async_fn.zig @@ -817,3 +817,30 @@ test "struct parameter to async function is copied to the frame" { }; S.doTheTest(); } + +test "cast fn to async fn when it is inferred to be async" { + const S = struct { + var frame: anyframe = undefined; + var ok = false; + + fn doTheTest() void { + var ptr: async fn () i32 = undefined; + ptr = func; + var buf: [100]u8 align(16) = undefined; + var result: i32 = undefined; + _ = await @asyncCall(&buf, &result, ptr); + expect(result == 1234); + ok = true; + } + + fn func() i32 { + suspend { + frame = @frame(); + } + return 1234; + } + }; + _ = async S.doTheTest(); + resume S.frame; + expect(S.ok); +} -- cgit v1.2.3 From 5a0275c247730040af91666518a6aa3f518e6905 Mon Sep 17 00:00:00 2001 From: Nick Erdmann Date: Mon, 19 Aug 2019 00:20:07 +0200 Subject: fix error message when dependency requires position independent code --- src/ir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 31b354be3a..65a66c8416 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17179,7 +17179,7 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, buf_sprintf("dependency on dynamic library '%s' requires enabling Position Independent Code", buf_ptr(lib_name))); add_error_note(ira->codegen, msg, source_node, - buf_sprintf("fixed by `--library %s` or `--enable-pic`", buf_ptr(lib_name))); + buf_sprintf("fixed by `--library %s` or `-fPIC`", buf_ptr(lib_name))); ira->codegen->reported_bad_link_libc_error = true; } -- cgit v1.2.3 From 44fb5275c1babed97a38b4b3c97e59740a2a5cc5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Aug 2019 14:46:12 -0400 Subject: fix array multiplication not setting parent value info closes #3095 --- src/ir.cpp | 7 +++++-- test/stage1/behavior/array.zig | 22 ++++++++++++++++++++-- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 65a66c8416..3b855b374f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13963,8 +13963,11 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * uint64_t i = 0; for (uint64_t x = 0; x < mult_amt; x += 1) { for (uint64_t y = 0; y < old_array_len; y += 1) { - copy_const_val(&out_val->data.x_array.data.s_none.elements[i], - &array_val->data.x_array.data.s_none.elements[y], false); + ConstExprValue *elem_dest_val = &out_val->data.x_array.data.s_none.elements[i]; + copy_const_val(elem_dest_val, &array_val->data.x_array.data.s_none.elements[y], false); + elem_dest_val->parent.id = ConstParentIdArray; + elem_dest_val->parent.data.p_array.array_val = out_val; + elem_dest_val->parent.data.p_array.elem_index = i; i += 1; } } diff --git a/test/stage1/behavior/array.zig b/test/stage1/behavior/array.zig index 49f9885702..9349af573c 100644 --- a/test/stage1/behavior/array.zig +++ b/test/stage1/behavior/array.zig @@ -1,5 +1,6 @@ -const expect = @import("std").testing.expect; -const mem = @import("std").mem; +const std = @import("std"); +const expect = std.testing.expect; +const mem = std.mem; test "arrays" { var array: [5]u32 = undefined; @@ -274,3 +275,20 @@ test "double nested array to const slice cast in array literal" { S.entry(2); comptime S.entry(2); } + +test "read/write through global variable array of struct fields initialized via array mult" { + const S = struct { + fn doTheTest() void { + expect(storage[0].term == 1); + storage[0] = MyStruct{ .term = 123 }; + expect(storage[0].term == 123); + } + + pub const MyStruct = struct { + term: usize, + }; + + var storage: [1]MyStruct = [_]MyStruct{MyStruct{ .term = 1 }} ** 1; + }; + S.doTheTest(); +} -- cgit v1.2.3 From d067a037cce906d600851e9b88df251451f9a93e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Aug 2019 15:58:31 -0400 Subject: fix void array as a local variable initializer Related: #1767 --- src/ir.cpp | 12 ++++++++++-- test/stage1/behavior/void.zig | 5 +++++ 2 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 3b855b374f..ccdd34f893 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -13940,8 +13940,7 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * uint64_t old_array_len = array_type->data.array.len; uint64_t new_array_len; - if (mul_u64_overflow(old_array_len, mult_amt, &new_array_len)) - { + if (mul_u64_overflow(old_array_len, mult_amt, &new_array_len)) { ir_add_error(ira, &instruction->base, buf_sprintf("operation results in overflow")); return ira->codegen->invalid_instruction; } @@ -13956,6 +13955,15 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * return result; } + switch (type_has_one_possible_value(ira->codegen, result->value.type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return result; + case OnePossibleValueNo: + break; + } + // TODO optimize the buf case expand_undef_array(ira->codegen, array_val); out_val->data.x_array.data.s_none.elements = create_const_vals(new_array_len); diff --git a/test/stage1/behavior/void.zig b/test/stage1/behavior/void.zig index 9722791946..19e879d157 100644 --- a/test/stage1/behavior/void.zig +++ b/test/stage1/behavior/void.zig @@ -33,3 +33,8 @@ test "void optional" { var x: ?void = {}; expect(x != null); } + +test "void array as a local variable initializer" { + var x = [_]void{{}} ** 1004; + var y = x[0]; +} -- cgit v1.2.3 From 24deb1a7fe955202335ed7540fa20a43ae6eca36 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Tue, 6 Aug 2019 12:24:52 -0400 Subject: fix @bitCast segfault with literal array param closes #3010 --- src/ir.cpp | 2 +- test/stage1/behavior/bitcast.zig | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index ccdd34f893..a018477e0d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24561,7 +24561,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false, true); - if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) + if (result_loc != nullptr && !(type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) return result_loc; return instruction->result_loc_bit_cast->parent->gen_instruction; diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index 394ade1a21..a8d90b6ae6 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -125,3 +125,8 @@ test "implicit cast to error union by returning" { S.entry(); comptime S.entry(); } + +// issue #3010: compiler segfault +test "bitcast literal [4]u8 param to u32" { + const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); +} -- cgit v1.2.3 From 6bc520ab957e25f9ae6d0f4d8a8ad4b96e145ac3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Aug 2019 17:35:19 -0400 Subject: solve it a slightly different way the error handling of result locations is a bit awkward but it should basically be the same everywhere --- src/ir.cpp | 8 ++++++-- test/stage1/behavior/bitcast.zig | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index a018477e0d..e98f028e31 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -24561,10 +24561,14 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false, true); - if (result_loc != nullptr && !(type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) + if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) return result_loc; - return instruction->result_loc_bit_cast->parent->gen_instruction; + if (instruction->result_loc_bit_cast->parent->gen_instruction != nullptr) { + return instruction->result_loc_bit_cast->parent->gen_instruction; + } + + return result_loc; } static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *ira, diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index a8d90b6ae6..92777e3d12 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -129,4 +129,5 @@ test "implicit cast to error union by returning" { // issue #3010: compiler segfault test "bitcast literal [4]u8 param to u32" { const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); + expect(ip == maxInt(u32)); } -- cgit v1.2.3 From 3dbed54294bc6769f64fc8bd23b98605d009677c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 19 Aug 2019 17:50:37 -0400 Subject: fix @bitCast of packed struct literal closes #3042 --- src/ir.cpp | 3 +++ test/stage1/behavior/bitcast.zig | 8 ++++++++ 2 files changed, 11 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index e98f028e31..8f27c9ea2c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14802,6 +14802,9 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return ira->codegen->invalid_instruction; } uint64_t parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); + if ((err = type_resolve(ira->codegen, value_type, ResolveStatusAlignmentKnown))) { + return ira->codegen->invalid_instruction; + } ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type, parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); diff --git a/test/stage1/behavior/bitcast.zig b/test/stage1/behavior/bitcast.zig index 92777e3d12..125e4cce54 100644 --- a/test/stage1/behavior/bitcast.zig +++ b/test/stage1/behavior/bitcast.zig @@ -131,3 +131,11 @@ test "bitcast literal [4]u8 param to u32" { const ip = @bitCast(u32, [_]u8{ 255, 255, 255, 255 }); expect(ip == maxInt(u32)); } + +test "bitcast packed struct literal to byte" { + const Foo = packed struct { + value: u8, + }; + const casted = @bitCast(u8, Foo{ .value = 0xF }); + expect(casted == 0xf); +} -- cgit v1.2.3 From 2addec8ea1f35241e9399c5da6855c427481985f Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Sat, 17 Aug 2019 14:16:51 +0200 Subject: compiler error when variable in asm template cannot be found --- src/ir.cpp | 35 +++++++++++++++++++++++++++++++++++ test/compile_errors.zig | 12 ++++++++++++ 2 files changed, 47 insertions(+) (limited to 'src/ir.cpp') diff --git a/src/ir.cpp b/src/ir.cpp index 8f27c9ea2c..cdddce1b18 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -6743,6 +6743,25 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t return ErrorNone; } +static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_template) { + const char *ptr = buf_ptr(src_template) + tok->start + 2; + size_t len = tok->end - tok->start - 2; + size_t result = 0; + for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { + AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); + if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { + return result; + } + } + for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { + AsmInput *asm_input = node->data.asm_expr.input_list.at(i); + if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { + return result; + } + } + return SIZE_MAX; +} + static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) { Error err; assert(node->type == NodeTypeAsmExpr); @@ -6830,6 +6849,22 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod input_list[i] = input_value; } + for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) { + AsmToken asm_token = tok_list.at(token_i); + if (asm_token.id == AsmTokenIdVar) { + size_t index = find_asm_index(irb->codegen, node, &asm_token, template_buf); + if (index == SIZE_MAX) { + const char *ptr = buf_ptr(template_buf) + asm_token.start + 2; + uint32_t len = asm_token.end - asm_token.start - 2; + + add_node_error(irb->codegen, node, + buf_sprintf("could not find '%.*s' in the inputs or outputs.", + len, ptr)); + return irb->codegen->invalid_instruction; + } + } + } + return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length, input_list, output_types, output_vars, return_count, is_volatile); } diff --git a/test/compile_errors.zig b/test/compile_errors.zig index cecb37620c..690db2c4eb 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -2,6 +2,18 @@ const tests = @import("tests.zig"); const builtin = @import("builtin"); pub fn addCases(cases: *tests.CompileErrorContext) void { + cases.add( + "variable in inline assembly template cannot be found", + \\export fn entry() void { + \\ var sp = asm volatile ( + \\ "mov %[foo], sp" + \\ : [bar] "=r" (-> usize) + \\ ); + \\} + , + "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs." + ); + cases.add( "indirect recursion of async functions detected", \\var frame: ?anyframe = null; -- cgit v1.2.3