From 7c236f6dd8194500f459b48621e2eb1997563caf Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 May 2017 12:59:09 -0400 Subject: [PATCH] fix compiler crash when referencing a variable... ...in an if after an if in the 2nd switch prong closes #355 --- src/all_types.hpp | 1 + src/ir.cpp | 10 ++++- test/behavior.zig | 1 + ...ef_var_in_if_after_if_2nd_switch_prong.zig | 37 +++++++++++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig diff --git a/src/all_types.hpp b/src/all_types.hpp index 226fd89abb..99ad25a3dd 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1516,6 +1516,7 @@ struct VariableTableEntry { size_t mem_slot_index; size_t ref_count; VarLinkage linkage; + IrInstruction *decl_instruction; }; struct ErrorTableEntry { diff --git a/src/ir.cpp b/src/ir.cpp index 3c2d7b7d34..ebe5ada52e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2311,7 +2311,10 @@ static IrInstruction *ir_instruction_elemptr_get_dep(IrInstructionElemPtr *instr } static IrInstruction *ir_instruction_varptr_get_dep(IrInstructionVarPtr *instruction, size_t index) { - return nullptr; + switch (index) { + case 0: return instruction->var->decl_instruction; // can be null + default: return nullptr; + } } static IrInstruction *ir_instruction_call_get_dep(IrInstructionCall *instruction, size_t index) { @@ -4646,7 +4649,10 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod if (init_value == irb->codegen->invalid_instruction) return init_value; - return ir_build_var_decl(irb, scope, node, var, type_instruction, init_value); + + IrInstruction *result = ir_build_var_decl(irb, scope, node, var, type_instruction, init_value); + var->decl_instruction = result; + return result; } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { diff --git a/test/behavior.zig b/test/behavior.zig index 98d0277f78..bd8822f0a1 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -24,6 +24,7 @@ comptime { _ = @import("cases/namespace_depends_on_compile_var/index.zig"); _ = @import("cases/null.zig"); _ = @import("cases/pub_enum/index.zig"); + _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("cases/sizeof_and_typeof.zig"); _ = @import("cases/struct.zig"); _ = @import("cases/struct_contains_slice_of_itself.zig"); diff --git a/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig b/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig new file mode 100644 index 0000000000..099b12a811 --- /dev/null +++ b/test/cases/ref_var_in_if_after_if_2nd_switch_prong.zig @@ -0,0 +1,37 @@ +const assert = @import("std").debug.assert; +const mem = @import("std").mem; + +var ok: bool = false; +test "reference a variable in an if after an if in the 2nd switch prong" { + foo(true, Num.Two, false, "aoeu"); + assert(!ok); + foo(false, Num.One, false, "aoeu"); + assert(!ok); + foo(true, Num.One, false, "aoeu"); + assert(ok); +} + +const Num = enum { + One, + Two, +}; + +fn foo(c: bool, k: Num, c2: bool, b: []const u8) { + switch (k) { + Num.Two => {}, + Num.One => { + if (c) { + const output_path = b; + + if (c2) { } + + a(output_path); + } + }, + } +} + +fn a(x: []const u8) { + assert(mem.eql(u8, x, "aoeu")); + ok = true; +}