From 3b40aaa01fb15799cf27d662229597ac98e2ab77 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 24 Feb 2017 13:57:00 -0500 Subject: [PATCH] add compile error for control flow using comptime var at runtime closes #266 --- src/all_types.hpp | 4 ++++ src/ir.cpp | 12 ++++++++++++ test/run_tests.cpp | 13 +++++++++++++ 3 files changed, 29 insertions(+) diff --git a/src/all_types.hpp b/src/all_types.hpp index 785ae98163..3e0296c0d6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1589,6 +1589,10 @@ struct IrBasicBlock { // analyze the basic block. If the same instruction wants us to emit // the same basic block, then we re-generate it instead of saving it. IrInstruction *ref_instruction; + // When this is non-null, a branch to this basic block is only allowed + // if the branch is comptime. The instruction points to the reason + // the basic block must be comptime. + IrInstruction *must_be_comptime_source_instr; }; enum IrInstructionId { diff --git a/src/ir.cpp b/src/ir.cpp index 28ae1bd1ad..43040fd7a2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8601,6 +8601,15 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr return ir_inline_bb(ira, &br_instruction->base, old_dest_block); IrBasicBlock *new_bb = ir_get_new_bb(ira, old_dest_block, &br_instruction->base); + + if (new_bb->must_be_comptime_source_instr) { + ErrorMsg *msg = ir_add_error(ira, &br_instruction->base, + buf_sprintf("control flow attempts to use compile-time variable at runtime")); + add_error_note(ira->codegen, msg, new_bb->must_be_comptime_source_instr->source_node, + buf_sprintf("compile-time variable assigned here")); + return ir_unreach_error(ira); + } + ir_build_br_from(&ira->new_irb, &br_instruction->base, new_bb); return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable); } @@ -9392,6 +9401,9 @@ static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstru ConstExprValue *dest_val = const_ptr_pointee(&ptr->value); if (dest_val->special != ConstValSpecialRuntime) { *dest_val = casted_value->value; + if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { + ira->new_irb.current_basic_block->must_be_comptime_source_instr = &store_ptr_instruction->base; + } return ir_analyze_void(ira, &store_ptr_instruction->base); } } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 58affc1cce..a160abbd9f 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1678,6 +1678,19 @@ fn assert(ok: bool) { ".tmp_source.zig:11:14: error: unable to evaluate constant expression", ".tmp_source.zig:7:20: note: called from here"); + add_compile_fail_case("control flow uses comptime var at runtime", R"SOURCE( +fn foo() { + comptime var i = 0; + while (i < 5; i += 1) { + bar(); + } +} + +fn bar() { } + )SOURCE", 2, + ".tmp_source.zig:4:5: error: control flow attempts to use compile-time variable at runtime", + ".tmp_source.zig:4:21: note: compile-time variable assigned here"); + } //////////////////////////////////////////////////////////////////////////////