authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-04 15:28:13-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-04 15:28:35-04:00
log68db9d5074cece234efa3a5352fe6cd36d210455
treeb79ead870777d9d90ab809b70a687c77af20df0d
parent36828a2e6aa6879641bf6980379dd806b6f479a1
signaturelock-open Commit is signed but in an unrecognized format.

add compile error for comptime control flow inside runtime block

closes #834

7 files changed, 241 insertions(+), 29 deletions(-)

src/all_types.hpp+18
...@@ -1836,6 +1836,7 @@ enum ScopeId {...@@ -1836,6 +1836,7 @@ enum ScopeId {
1836 ScopeIdFnDef,1836 ScopeIdFnDef,
1837 ScopeIdCompTime,1837 ScopeIdCompTime,
1838 ScopeIdCoroPrelude,1838 ScopeIdCoroPrelude,
1839 ScopeIdRuntime,
1839};1840};
18401841
1841struct Scope {1842struct Scope {
...@@ -1928,6 +1929,15 @@ struct ScopeLoop {...@@ -1928,6 +1929,15 @@ struct ScopeLoop {
1928 ZigList<IrBasicBlock *> *incoming_blocks;1929 ZigList<IrBasicBlock *> *incoming_blocks;
1929};1930};
19301931
1932// This scope blocks certain things from working such as comptime continue
1933// inside a runtime if expression.
1934// NodeTypeIfBoolExpr, NodeTypeWhileExpr, NodeTypeForExpr
1935struct ScopeRuntime {
1936 Scope base;
1937
1938 IrInstruction *is_comptime;
1939};
1940
1931// This scope is created for a suspend block in order to have labeled1941// This scope is created for a suspend block in order to have labeled
1932// suspend for breaking out of a suspend and for detecting if a suspend1942// suspend for breaking out of a suspend and for detecting if a suspend
1933// block is inside a suspend block.1943// block is inside a suspend block.
...@@ -2147,6 +2157,7 @@ enum IrInstructionId {...@@ -2147,6 +2157,7 @@ enum IrInstructionId {
2147 IrInstructionIdErrSetCast,2157 IrInstructionIdErrSetCast,
2148 IrInstructionIdToBytes,2158 IrInstructionIdToBytes,
2149 IrInstructionIdFromBytes,2159 IrInstructionIdFromBytes,
2160 IrInstructionIdCheckRuntimeScope,
2150};2161};
21512162
2152struct IrInstruction {2163struct IrInstruction {
...@@ -3236,6 +3247,13 @@ struct IrInstructionSqrt {...@@ -3236,6 +3247,13 @@ struct IrInstructionSqrt {
3236 IrInstruction *op;3247 IrInstruction *op;
3237};3248};
32383249
3250struct IrInstructionCheckRuntimeScope {
3251 IrInstruction base;
3252
3253 IrInstruction *scope_is_comptime;
3254 IrInstruction *is_comptime;
3255};
3256
3239static const size_t slice_ptr_index = 0;3257static const size_t slice_ptr_index = 0;
3240static const size_t slice_len_index = 1;3258static const size_t slice_len_index = 1;
32413259
src/analyze.cpp+8
...@@ -157,6 +157,13 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {...@@ -157,6 +157,13 @@ ScopeLoop *create_loop_scope(AstNode *node, Scope *parent) {
157 return scope;157 return scope;
158}158}
159159
160Scope *create_runtime_scope(AstNode *node, Scope *parent, IrInstruction *is_comptime) {
161 ScopeRuntime *scope = allocate<ScopeRuntime>(1);
162 scope->is_comptime = is_comptime;
163 init_scope(&scope->base, ScopeIdRuntime, node, parent);
164 return &scope->base;
165}
166
160ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent) {167ScopeSuspend *create_suspend_scope(AstNode *node, Scope *parent) {
161 assert(node->type == NodeTypeSuspend);168 assert(node->type == NodeTypeSuspend);
162 ScopeSuspend *scope = allocate<ScopeSuspend>(1);169 ScopeSuspend *scope = allocate<ScopeSuspend>(1);
...@@ -3770,6 +3777,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {...@@ -3770,6 +3777,7 @@ FnTableEntry *scope_get_fn_if_root(Scope *scope) {
3770 case ScopeIdSuspend:3777 case ScopeIdSuspend:
3771 case ScopeIdCompTime:3778 case ScopeIdCompTime:
3772 case ScopeIdCoroPrelude:3779 case ScopeIdCoroPrelude:
3780 case ScopeIdRuntime:
3773 scope = scope->parent;3781 scope = scope->parent;
3774 continue;3782 continue;
3775 case ScopeIdFnDef:3783 case ScopeIdFnDef:
src/analyze.hpp+1
...@@ -111,6 +111,7 @@ ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_en...@@ -111,6 +111,7 @@ ScopeFnDef *create_fndef_scope(AstNode *node, Scope *parent, FnTableEntry *fn_en
111ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);111ScopeDecls *create_decls_scope(AstNode *node, Scope *parent, TypeTableEntry *container_type, ImportTableEntry *import);
112Scope *create_comptime_scope(AstNode *node, Scope *parent);112Scope *create_comptime_scope(AstNode *node, Scope *parent);
113Scope *create_coro_prelude_scope(AstNode *node, Scope *parent);113Scope *create_coro_prelude_scope(AstNode *node, Scope *parent);
114Scope *create_runtime_scope(AstNode *node, Scope *parent, IrInstruction *is_comptime);
114115
115void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);116void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str);
116ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);117ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str);
src/codegen.cpp+2
...@@ -678,6 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {...@@ -678,6 +678,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) {
678 case ScopeIdSuspend:678 case ScopeIdSuspend:
679 case ScopeIdCompTime:679 case ScopeIdCompTime:
680 case ScopeIdCoroPrelude:680 case ScopeIdCoroPrelude:
681 case ScopeIdRuntime:
681 return get_di_scope(g, scope->parent);682 return get_di_scope(g, scope->parent);
682 }683 }
683 zig_unreachable();684 zig_unreachable();
...@@ -4869,6 +4870,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4869,6 +4870,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4869 case IrInstructionIdFromBytes:4870 case IrInstructionIdFromBytes:
4870 case IrInstructionIdToBytes:4871 case IrInstructionIdToBytes:
4871 case IrInstructionIdEnumToInt:4872 case IrInstructionIdEnumToInt:
4873 case IrInstructionIdCheckRuntimeScope:
4872 zig_unreachable();4874 zig_unreachable();
48734875
4874 case IrInstructionIdReturn:4876 case IrInstructionIdReturn:
src/ir.cpp+91-29
...@@ -832,6 +832,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {...@@ -832,6 +832,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSqrt *) {
832 return IrInstructionIdSqrt;832 return IrInstructionIdSqrt;
833}833}
834834
835static constexpr IrInstructionId ir_instruction_id(IrInstructionCheckRuntimeScope *) {
836 return IrInstructionIdCheckRuntimeScope;
837}
838
835template<typename T>839template<typename T>
836static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {840static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
837 T *special_instruction = allocate<T>(1);841 T *special_instruction = allocate<T>(1);
...@@ -2974,6 +2978,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc...@@ -2974,6 +2978,17 @@ static IrInstruction *ir_build_sqrt(IrBuilder *irb, Scope *scope, AstNode *sourc
2974 return &instruction->base;2978 return &instruction->base;
2975}2979}
29762980
2981static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *scope_is_comptime, IrInstruction *is_comptime) {
2982 IrInstructionCheckRuntimeScope *instruction = ir_build_instruction<IrInstructionCheckRuntimeScope>(irb, scope, source_node);
2983 instruction->scope_is_comptime = scope_is_comptime;
2984 instruction->is_comptime = is_comptime;
2985
2986 ir_ref_instruction(scope_is_comptime, irb->current_basic_block);
2987 ir_ref_instruction(is_comptime, irb->current_basic_block);
2988
2989 return &instruction->base;
2990}
2991
2977static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2992static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2978 results[ReturnKindUnconditional] = 0;2993 results[ReturnKindUnconditional] = 0;
2979 results[ReturnKindError] = 0;2994 results[ReturnKindError] = 0;
...@@ -2999,6 +3014,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco...@@ -2999,6 +3014,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco
2999 case ScopeIdLoop:3014 case ScopeIdLoop:
3000 case ScopeIdSuspend:3015 case ScopeIdSuspend:
3001 case ScopeIdCompTime:3016 case ScopeIdCompTime:
3017 case ScopeIdRuntime:
3002 scope = scope->parent;3018 scope = scope->parent;
3003 continue;3019 continue;
3004 case ScopeIdDeferExpr:3020 case ScopeIdDeferExpr:
...@@ -3051,6 +3067,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -3051,6 +3067,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
3051 case ScopeIdLoop:3067 case ScopeIdLoop:
3052 case ScopeIdSuspend:3068 case ScopeIdSuspend:
3053 case ScopeIdCompTime:3069 case ScopeIdCompTime:
3070 case ScopeIdRuntime:
3054 scope = scope->parent;3071 scope = scope->parent;
3055 continue;3072 continue;
3056 case ScopeIdDeferExpr:3073 case ScopeIdDeferExpr:
...@@ -4980,7 +4997,8 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode...@@ -4980,7 +4997,8 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
49804997
4981 ir_set_cursor_at_end_and_append_block(irb, then_block);4998 ir_set_cursor_at_end_and_append_block(irb, then_block);
49824999
4983 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, scope);5000 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5001 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope);
4984 if (then_expr_result == irb->codegen->invalid_instruction)5002 if (then_expr_result == irb->codegen->invalid_instruction)
4985 return then_expr_result;5003 return then_expr_result;
4986 IrBasicBlock *after_then_block = irb->current_basic_block;5004 IrBasicBlock *after_then_block = irb->current_basic_block;
...@@ -4990,7 +5008,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode...@@ -4990,7 +5008,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
4990 ir_set_cursor_at_end_and_append_block(irb, else_block);5008 ir_set_cursor_at_end_and_append_block(irb, else_block);
4991 IrInstruction *else_expr_result;5009 IrInstruction *else_expr_result;
4992 if (else_node) {5010 if (else_node) {
4993 else_expr_result = ir_gen_node(irb, else_node, scope);5011 else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
4994 if (else_expr_result == irb->codegen->invalid_instruction)5012 if (else_expr_result == irb->codegen->invalid_instruction)
4995 return else_expr_result;5013 return else_expr_result;
4996 } else {5014 } else {
...@@ -5271,6 +5289,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5271,6 +5289,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
5271 ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);5289 ir_should_inline(irb->exec, scope) || node->data.while_expr.is_inline);
5272 ir_build_br(irb, scope, node, cond_block, is_comptime);5290 ir_build_br(irb, scope, node, cond_block, is_comptime);
52735291
5292 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5274 Buf *var_symbol = node->data.while_expr.var_symbol;5293 Buf *var_symbol = node->data.while_expr.var_symbol;
5275 Buf *err_symbol = node->data.while_expr.err_symbol;5294 Buf *err_symbol = node->data.while_expr.err_symbol;
5276 if (err_symbol != nullptr) {5295 if (err_symbol != nullptr) {
...@@ -5281,13 +5300,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5281,13 +5300,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
5281 VariableTableEntry *payload_var;5300 VariableTableEntry *payload_var;
5282 if (var_symbol) {5301 if (var_symbol) {
5283 // TODO make it an error to write to payload variable5302 // TODO make it an error to write to payload variable
5284 payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,5303 payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
5285 true, false, false, is_comptime);5304 true, false, false, is_comptime);
5286 payload_scope = payload_var->child_scope;5305 payload_scope = payload_var->child_scope;
5287 } else {5306 } else {
5288 payload_scope = scope;5307 payload_scope = subexpr_scope;
5289 }5308 }
5290 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LValPtr);5309 IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
5291 if (err_val_ptr == irb->codegen->invalid_instruction)5310 if (err_val_ptr == irb->codegen->invalid_instruction)
5292 return err_val_ptr;5311 return err_val_ptr;
5293 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);5312 IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr);
...@@ -5367,12 +5386,14 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5367,12 +5386,14 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
5367 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);5386 return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items);
5368 } else if (var_symbol != nullptr) {5387 } else if (var_symbol != nullptr) {
5369 ir_set_cursor_at_end_and_append_block(irb, cond_block);5388 ir_set_cursor_at_end_and_append_block(irb, cond_block);
5389 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5370 // TODO make it an error to write to payload variable5390 // TODO make it an error to write to payload variable
5371 AstNode *symbol_node = node; // TODO make more accurate5391 AstNode *symbol_node = node; // TODO make more accurate
5372 VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, scope, var_symbol,5392
5393 VariableTableEntry *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol,
5373 true, false, false, is_comptime);5394 true, false, false, is_comptime);
5374 Scope *child_scope = payload_var->child_scope;5395 Scope *child_scope = payload_var->child_scope;
5375 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, scope, LValPtr);5396 IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr);
5376 if (maybe_val_ptr == irb->codegen->invalid_instruction)5397 if (maybe_val_ptr == irb->codegen->invalid_instruction)
5377 return maybe_val_ptr;5398 return maybe_val_ptr;
5378 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);5399 IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr);
...@@ -5456,7 +5477,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5456,7 +5477,9 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
5456 ZigList<IrInstruction *> incoming_values = {0};5477 ZigList<IrInstruction *> incoming_values = {0};
5457 ZigList<IrBasicBlock *> incoming_blocks = {0};5478 ZigList<IrBasicBlock *> incoming_blocks = {0};
54585479
5459 ScopeLoop *loop_scope = create_loop_scope(node, scope);5480 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5481
5482 ScopeLoop *loop_scope = create_loop_scope(node, subexpr_scope);
5460 loop_scope->break_block = end_block;5483 loop_scope->break_block = end_block;
5461 loop_scope->continue_block = continue_block;5484 loop_scope->continue_block = continue_block;
5462 loop_scope->is_comptime = is_comptime;5485 loop_scope->is_comptime = is_comptime;
...@@ -5474,7 +5497,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5474,7 +5497,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
54745497
5475 if (continue_expr_node) {5498 if (continue_expr_node) {
5476 ir_set_cursor_at_end_and_append_block(irb, continue_block);5499 ir_set_cursor_at_end_and_append_block(irb, continue_block);
5477 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, scope);5500 IrInstruction *expr_result = ir_gen_node(irb, continue_expr_node, subexpr_scope);
5478 if (expr_result == irb->codegen->invalid_instruction)5501 if (expr_result == irb->codegen->invalid_instruction)
5479 return expr_result;5502 return expr_result;
5480 if (!instr_is_unreachable(expr_result))5503 if (!instr_is_unreachable(expr_result))
...@@ -5485,7 +5508,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n...@@ -5485,7 +5508,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n
5485 if (else_node) {5508 if (else_node) {
5486 ir_set_cursor_at_end_and_append_block(irb, else_block);5509 ir_set_cursor_at_end_and_append_block(irb, else_block);
54875510
5488 else_result = ir_gen_node(irb, else_node, scope);5511 else_result = ir_gen_node(irb, else_node, subexpr_scope);
5489 if (else_result == irb->codegen->invalid_instruction)5512 if (else_result == irb->codegen->invalid_instruction)
5490 return else_result;5513 return else_result;
5491 if (!instr_is_unreachable(else_result))5514 if (!instr_is_unreachable(else_result))
...@@ -5828,20 +5851,21 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no...@@ -5828,20 +5851,21 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
58285851
5829 ir_set_cursor_at_end_and_append_block(irb, then_block);5852 ir_set_cursor_at_end_and_append_block(irb, then_block);
58305853
5854 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5831 Scope *var_scope;5855 Scope *var_scope;
5832 if (var_symbol) {5856 if (var_symbol) {
5833 IrInstruction *var_type = nullptr;5857 IrInstruction *var_type = nullptr;
5834 bool is_shadowable = false;5858 bool is_shadowable = false;
5835 bool is_const = true;5859 bool is_const = true;
5836 VariableTableEntry *var = ir_create_var(irb, node, scope,5860 VariableTableEntry *var = ir_create_var(irb, node, subexpr_scope,
5837 var_symbol, is_const, is_const, is_shadowable, is_comptime);5861 var_symbol, is_const, is_const, is_shadowable, is_comptime);
58385862
5839 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, scope, node, maybe_val_ptr, false);5863 IrInstruction *var_ptr_value = ir_build_unwrap_maybe(irb, subexpr_scope, node, maybe_val_ptr, false);
5840 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);5864 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
5841 ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);5865 ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
5842 var_scope = var->child_scope;5866 var_scope = var->child_scope;
5843 } else {5867 } else {
5844 var_scope = scope;5868 var_scope = subexpr_scope;
5845 }5869 }
5846 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);5870 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
5847 if (then_expr_result == irb->codegen->invalid_instruction)5871 if (then_expr_result == irb->codegen->invalid_instruction)
...@@ -5853,7 +5877,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no...@@ -5853,7 +5877,7 @@ static IrInstruction *ir_gen_test_expr(IrBuilder *irb, Scope *scope, AstNode *no
5853 ir_set_cursor_at_end_and_append_block(irb, else_block);5877 ir_set_cursor_at_end_and_append_block(irb, else_block);
5854 IrInstruction *else_expr_result;5878 IrInstruction *else_expr_result;
5855 if (else_node) {5879 if (else_node) {
5856 else_expr_result = ir_gen_node(irb, else_node, scope);5880 else_expr_result = ir_gen_node(irb, else_node, subexpr_scope);
5857 if (else_expr_result == irb->codegen->invalid_instruction)5881 if (else_expr_result == irb->codegen->invalid_instruction)
5858 return else_expr_result;5882 return else_expr_result;
5859 } else {5883 } else {
...@@ -5902,20 +5926,21 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -5902,20 +5926,21 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
59025926
5903 ir_set_cursor_at_end_and_append_block(irb, ok_block);5927 ir_set_cursor_at_end_and_append_block(irb, ok_block);
59045928
5929 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
5905 Scope *var_scope;5930 Scope *var_scope;
5906 if (var_symbol) {5931 if (var_symbol) {
5907 IrInstruction *var_type = nullptr;5932 IrInstruction *var_type = nullptr;
5908 bool is_shadowable = false;5933 bool is_shadowable = false;
5909 IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, err_val);5934 IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val);
5910 VariableTableEntry *var = ir_create_var(irb, node, scope,5935 VariableTableEntry *var = ir_create_var(irb, node, subexpr_scope,
5911 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);5936 var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime);
59125937
5913 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, scope, node, err_val_ptr, false);5938 IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false);
5914 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, node, var_ptr_value);5939 IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value);
5915 ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);5940 ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
5916 var_scope = var->child_scope;5941 var_scope = var->child_scope;
5917 } else {5942 } else {
5918 var_scope = scope;5943 var_scope = subexpr_scope;
5919 }5944 }
5920 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);5945 IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope);
5921 if (then_expr_result == irb->codegen->invalid_instruction)5946 if (then_expr_result == irb->codegen->invalid_instruction)
...@@ -5933,14 +5958,14 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -5933,14 +5958,14 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *
5933 IrInstruction *var_type = nullptr;5958 IrInstruction *var_type = nullptr;
5934 bool is_shadowable = false;5959 bool is_shadowable = false;
5935 bool is_const = true;5960 bool is_const = true;
5936 VariableTableEntry *var = ir_create_var(irb, node, scope,5961 VariableTableEntry *var = ir_create_var(irb, node, subexpr_scope,
5937 err_symbol, is_const, is_const, is_shadowable, is_comptime);5962 err_symbol, is_const, is_const, is_shadowable, is_comptime);
59385963
5939 IrInstruction *var_value = ir_build_unwrap_err_code(irb, scope, node, err_val_ptr);5964 IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr);
5940 ir_build_var_decl(irb, scope, node, var, var_type, nullptr, var_value);5965 ir_build_var_decl(irb, subexpr_scope, node, var, var_type, nullptr, var_value);
5941 err_var_scope = var->child_scope;5966 err_var_scope = var->child_scope;
5942 } else {5967 } else {
5943 err_var_scope = scope;5968 err_var_scope = subexpr_scope;
5944 }5969 }
5945 else_expr_result = ir_gen_node(irb, else_node, err_var_scope);5970 else_expr_result = ir_gen_node(irb, else_node, err_var_scope);
5946 if (else_expr_result == irb->codegen->invalid_instruction)5971 if (else_expr_result == irb->codegen->invalid_instruction)
...@@ -6037,6 +6062,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -6037,6 +6062,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
6037 ZigList<IrInstructionCheckSwitchProngsRange> check_ranges = {0};6062 ZigList<IrInstructionCheckSwitchProngsRange> check_ranges = {0};
60386063
6039 // First do the else and the ranges6064 // First do the else and the ranges
6065 Scope *subexpr_scope = create_runtime_scope(node, scope, is_comptime);
6040 Scope *comptime_scope = create_comptime_scope(node, scope);6066 Scope *comptime_scope = create_comptime_scope(node, scope);
6041 AstNode *else_prong = nullptr;6067 AstNode *else_prong = nullptr;
6042 for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {6068 for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) {
...@@ -6054,7 +6080,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -6054,7 +6080,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
60546080
6055 IrBasicBlock *prev_block = irb->current_basic_block;6081 IrBasicBlock *prev_block = irb->current_basic_block;
6056 ir_set_cursor_at_end_and_append_block(irb, else_block);6082 ir_set_cursor_at_end_and_append_block(irb, else_block);
6057 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,6083 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6058 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))6084 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
6059 {6085 {
6060 return irb->codegen->invalid_instruction;6086 return irb->codegen->invalid_instruction;
...@@ -6121,7 +6147,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -6121,7 +6147,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
6121 range_block_no, is_comptime));6147 range_block_no, is_comptime));
61226148
6123 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);6149 ir_set_cursor_at_end_and_append_block(irb, range_block_yes);
6124 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,6150 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6125 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))6151 is_comptime, var_is_comptime, target_value_ptr, nullptr, &incoming_blocks, &incoming_values))
6126 {6152 {
6127 return irb->codegen->invalid_instruction;6153 return irb->codegen->invalid_instruction;
...@@ -6165,7 +6191,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *...@@ -6165,7 +6191,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *
61656191
6166 IrBasicBlock *prev_block = irb->current_basic_block;6192 IrBasicBlock *prev_block = irb->current_basic_block;
6167 ir_set_cursor_at_end_and_append_block(irb, prong_block);6193 ir_set_cursor_at_end_and_append_block(irb, prong_block);
6168 if (!ir_gen_switch_prong_expr(irb, scope, node, prong_node, end_block,6194 if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block,
6169 is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))6195 is_comptime, var_is_comptime, target_value_ptr, only_item_value, &incoming_blocks, &incoming_values))
6170 {6196 {
6171 return irb->codegen->invalid_instruction;6197 return irb->codegen->invalid_instruction;
...@@ -6308,6 +6334,8 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -6308,6 +6334,8 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
6308 // * defer expression scope => error, cannot break out of defer expression6334 // * defer expression scope => error, cannot break out of defer expression
6309 // * loop scope => OK6335 // * loop scope => OK
63106336
6337 ZigList<ScopeRuntime *> runtime_scopes = {};
6338
6311 Scope *search_scope = continue_scope;6339 Scope *search_scope = continue_scope;
6312 ScopeLoop *loop_scope;6340 ScopeLoop *loop_scope;
6313 for (;;) {6341 for (;;) {
...@@ -6330,6 +6358,9 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -6330,6 +6358,9 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
6330 loop_scope = this_loop_scope;6358 loop_scope = this_loop_scope;
6331 break;6359 break;
6332 }6360 }
6361 } else if (search_scope->id == ScopeIdRuntime) {
6362 ScopeRuntime *scope_runtime = (ScopeRuntime *)search_scope;
6363 runtime_scopes.append(scope_runtime);
6333 }6364 }
6334 search_scope = search_scope->parent;6365 search_scope = search_scope->parent;
6335 }6366 }
...@@ -6341,6 +6372,11 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -6341,6 +6372,11 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
6341 is_comptime = loop_scope->is_comptime;6372 is_comptime = loop_scope->is_comptime;
6342 }6373 }
63436374
6375 for (size_t i = 0; i < runtime_scopes.length; i += 1) {
6376 ScopeRuntime *scope_runtime = runtime_scopes.at(i);
6377 ir_mark_gen(ir_build_check_runtime_scope(irb, continue_scope, node, scope_runtime->is_comptime, is_comptime));
6378 }
6379
6344 IrBasicBlock *dest_block = loop_scope->continue_block;6380 IrBasicBlock *dest_block = loop_scope->continue_block;
6345 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);6381 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);
6346 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));6382 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));
...@@ -20910,6 +20946,29 @@ static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInst...@@ -20910,6 +20946,29 @@ static TypeTableEntry *ir_analyze_instruction_int_to_enum(IrAnalyze *ira, IrInst
20910 return result->value.type;20946 return result->value.type;
20911}20947}
2091220948
20949static TypeTableEntry *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira, IrInstructionCheckRuntimeScope *instruction) {
20950 IrInstruction *block_comptime_inst = instruction->scope_is_comptime->other;
20951 bool scope_is_comptime;
20952 if (!ir_resolve_bool(ira, block_comptime_inst, &scope_is_comptime))
20953 return ira->codegen->builtin_types.entry_invalid;
20954
20955 IrInstruction *is_comptime_inst = instruction->is_comptime->other;
20956 bool is_comptime;
20957 if (!ir_resolve_bool(ira, is_comptime_inst, &is_comptime))
20958 return ira->codegen->builtin_types.entry_invalid;
20959
20960 if (!scope_is_comptime && is_comptime) {
20961 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
20962 buf_sprintf("comptime control flow inside runtime block"));
20963 add_error_note(ira->codegen, msg, block_comptime_inst->source_node,
20964 buf_sprintf("runtime block created here"));
20965 return ira->codegen->builtin_types.entry_invalid;
20966 }
20967
20968 ir_build_const_from(ira, &instruction->base);
20969 return ira->codegen->builtin_types.entry_void;
20970}
20971
20913static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {20972static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
20914 switch (instruction->id) {20973 switch (instruction->id) {
20915 case IrInstructionIdInvalid:20974 case IrInstructionIdInvalid:
...@@ -21186,6 +21245,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -21186,6 +21245,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
21186 return ir_analyze_instruction_int_to_enum(ira, (IrInstructionIntToEnum *)instruction);21245 return ir_analyze_instruction_int_to_enum(ira, (IrInstructionIntToEnum *)instruction);
21187 case IrInstructionIdEnumToInt:21246 case IrInstructionIdEnumToInt:
21188 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);21247 return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction);
21248 case IrInstructionIdCheckRuntimeScope:
21249 return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction);
21189 }21250 }
21190 zig_unreachable();21251 zig_unreachable();
21191}21252}
...@@ -21301,6 +21362,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -21301,6 +21362,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
21301 case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free21362 case IrInstructionIdOverflowOp: // TODO when we support multiple returns this can be side effect free
21302 case IrInstructionIdCheckSwitchProngs:21363 case IrInstructionIdCheckSwitchProngs:
21303 case IrInstructionIdCheckStatementIsVoid:21364 case IrInstructionIdCheckStatementIsVoid:
21365 case IrInstructionIdCheckRuntimeScope:
21304 case IrInstructionIdPanic:21366 case IrInstructionIdPanic:
21305 case IrInstructionIdSetEvalBranchQuota:21367 case IrInstructionIdSetEvalBranchQuota:
21306 case IrInstructionIdPtrType:21368 case IrInstructionIdPtrType:
src/ir_print.cpp+11
...@@ -957,6 +957,14 @@ static void ir_print_enum_to_int(IrPrint *irp, IrInstructionEnumToInt *instructi...@@ -957,6 +957,14 @@ static void ir_print_enum_to_int(IrPrint *irp, IrInstructionEnumToInt *instructi
957 fprintf(irp->f, ")");957 fprintf(irp->f, ")");
958}958}
959959
960static void ir_print_check_runtime_scope(IrPrint *irp, IrInstructionCheckRuntimeScope *instruction) {
961 fprintf(irp->f, "@checkRuntimeScope(");
962 ir_print_other_instruction(irp, instruction->scope_is_comptime);
963 fprintf(irp->f, ",");
964 ir_print_other_instruction(irp, instruction->is_comptime);
965 fprintf(irp->f, ")");
966}
967
960static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {968static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) {
961 fprintf(irp->f, "inttoerr ");969 fprintf(irp->f, "inttoerr ");
962 ir_print_other_instruction(irp, instruction->target);970 ir_print_other_instruction(irp, instruction->target);
...@@ -1749,6 +1757,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1749,6 +1757,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1749 case IrInstructionIdEnumToInt:1757 case IrInstructionIdEnumToInt:
1750 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);1758 ir_print_enum_to_int(irp, (IrInstructionEnumToInt *)instruction);
1751 break;1759 break;
1760 case IrInstructionIdCheckRuntimeScope:
1761 ir_print_check_runtime_scope(irp, (IrInstructionCheckRuntimeScope *)instruction);
1762 break;
1752 }1763 }
1753 fprintf(irp->f, "\n");1764 fprintf(irp->f, "\n");
1754}1765}
test/compile_errors.zig+110
...@@ -1,6 +1,116 @@...@@ -1,6 +1,116 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: *tests.CompileErrorContext) void {3pub fn addCases(cases: *tests.CompileErrorContext) void {
4 cases.add(
5 "comptime continue inside runtime switch",
6 \\export fn entry() void {
7 \\ var p: i32 = undefined;
8 \\ comptime var q = true;
9 \\ inline while (q) {
10 \\ switch (p) {
11 \\ 11 => continue,
12 \\ else => {},
13 \\ }
14 \\ q = false;
15 \\ }
16 \\}
17 ,
18 ".tmp_source.zig:6:19: error: comptime control flow inside runtime block",
19 ".tmp_source.zig:5:9: note: runtime block created here",
20 );
21
22 cases.add(
23 "comptime continue inside runtime while error",
24 \\export fn entry() void {
25 \\ var p: error!usize = undefined;
26 \\ comptime var q = true;
27 \\ outer: inline while (q) {
28 \\ while (p) |_| {
29 \\ continue :outer;
30 \\ } else |_| {}
31 \\ q = false;
32 \\ }
33 \\}
34 ,
35 ".tmp_source.zig:6:13: error: comptime control flow inside runtime block",
36 ".tmp_source.zig:5:9: note: runtime block created here",
37 );
38
39 cases.add(
40 "comptime continue inside runtime while optional",
41 \\export fn entry() void {
42 \\ var p: ?usize = undefined;
43 \\ comptime var q = true;
44 \\ outer: inline while (q) {
45 \\ while (p) |_| continue :outer;
46 \\ q = false;
47 \\ }
48 \\}
49 ,
50 ".tmp_source.zig:5:23: error: comptime control flow inside runtime block",
51 ".tmp_source.zig:5:9: note: runtime block created here",
52 );
53
54 cases.add(
55 "comptime continue inside runtime while bool",
56 \\export fn entry() void {
57 \\ var p: usize = undefined;
58 \\ comptime var q = true;
59 \\ outer: inline while (q) {
60 \\ while (p == 11) continue :outer;
61 \\ q = false;
62 \\ }
63 \\}
64 ,
65 ".tmp_source.zig:5:25: error: comptime control flow inside runtime block",
66 ".tmp_source.zig:5:9: note: runtime block created here",
67 );
68
69 cases.add(
70 "comptime continue inside runtime if error",
71 \\export fn entry() void {
72 \\ var p: error!i32 = undefined;
73 \\ comptime var q = true;
74 \\ inline while (q) {
75 \\ if (p) |_| continue else |_| {}
76 \\ q = false;
77 \\ }
78 \\}
79 ,
80 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
81 ".tmp_source.zig:5:9: note: runtime block created here",
82 );
83
84 cases.add(
85 "comptime continue inside runtime if optional",
86 \\export fn entry() void {
87 \\ var p: ?i32 = undefined;
88 \\ comptime var q = true;
89 \\ inline while (q) {
90 \\ if (p) |_| continue;
91 \\ q = false;
92 \\ }
93 \\}
94 ,
95 ".tmp_source.zig:5:20: error: comptime control flow inside runtime block",
96 ".tmp_source.zig:5:9: note: runtime block created here",
97 );
98
99 cases.add(
100 "comptime continue inside runtime if bool",
101 \\export fn entry() void {
102 \\ var p: usize = undefined;
103 \\ comptime var q = true;
104 \\ inline while (q) {
105 \\ if (p == 11) continue;
106 \\ q = false;
107 \\ }
108 \\}
109 ,
110 ".tmp_source.zig:5:22: error: comptime control flow inside runtime block",
111 ".tmp_source.zig:5:9: note: runtime block created here",
112 );
113
4 cases.add(114 cases.add(
5 "switch with invalid expression parameter",115 "switch with invalid expression parameter",
6 \\export fn entry() void {116 \\export fn entry() void {