diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2018-08-28 15:24:28 -0400 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2018-08-28 15:24:28 -0400 |
| commit | 09cc1dc66067f378a1508e34c0714b659b445724 (patch) | |
| tree | e5fc5298f5240934716609d7727c01071f869707 /src/ir.cpp | |
| parent | 048f506aa6b78dd13a593b6bb12a317c5a047bc7 (diff) | |
| download | zig-09cc1dc66067f378a1508e34c0714b659b445724.tar.gz zig-09cc1dc66067f378a1508e34c0714b659b445724.zip | |
fix crash when var in inline loop has different types
closes #917
closes #845
closes #741
closes #740
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 64 |
1 files changed, 38 insertions, 26 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index 3117410cd2..4e64b3e002 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3280,7 +3280,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, } static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope, - Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) + Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, + bool skip_name_check) { VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1); variable_entry->parent_scope = parent_scope; @@ -3293,29 +3294,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco if (name) { buf_init_from_buf(&variable_entry->name, name); - VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); - if (existing_var && !existing_var->shadowable) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); - add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); - variable_entry->value->type = codegen->builtin_types.entry_invalid; - } else { - TypeTableEntry *type = get_primitive_type(codegen, name); - if (type != nullptr) { - add_node_error(codegen, node, - buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); + if (!skip_name_check) { + VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name); + if (existing_var && !existing_var->shadowable) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); + add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here")); variable_entry->value->type = codegen->builtin_types.entry_invalid; } else { - Tld *tld = find_decl(codegen, parent_scope, name); - if (tld != nullptr) { - ErrorMsg *msg = add_node_error(codegen, node, - buf_sprintf("redefinition of '%s'", buf_ptr(name))); - add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); + TypeTableEntry *type = get_primitive_type(codegen, name); + if (type != nullptr) { + add_node_error(codegen, node, + buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name))); variable_entry->value->type = codegen->builtin_types.entry_invalid; + } else { + Tld *tld = find_decl(codegen, parent_scope, name); + if (tld != nullptr) { + ErrorMsg *msg = add_node_error(codegen, node, + buf_sprintf("redefinition of '%s'", buf_ptr(name))); + add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here")); + variable_entry->value->type = codegen->builtin_types.entry_invalid; + } } } } - } else { assert(is_shadowable); // TODO make this name not actually be in scope. user should be able to make a variable called "_anon" @@ -3338,14 +3340,9 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime) { bool is_underscored = name ? buf_eql_str(name, "_") : false; - VariableTableEntry *var = create_local_var( irb->codegen - , node - , scope - , (is_underscored ? nullptr : name) - , src_is_const - , gen_is_const - , (is_underscored ? true : is_shadowable) - , is_comptime ); + VariableTableEntry *var = create_local_var(irb->codegen, node, scope, + (is_underscored ? nullptr : name), src_is_const, gen_is_const, + (is_underscored ? true : is_shadowable), is_comptime, false); if (is_comptime != nullptr || gen_is_const) { var->mem_slot_index = exec_next_mem_slot(irb->exec); var->owner_exec = irb->exec; @@ -12495,6 +12492,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc } } + if (var->value->type != nullptr && var->value->type != result_type && !is_comptime_var) { + // This is at least the second time we've seen this variable declaration during analysis. + // This means that this is actually a different variable due to, e.g. an inline while loop. + // We make a new variable so that it can hold a different type, and so the debug info can + // be distinct. + VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope, + &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true); + var->next_var = new_var; + var = new_var; + } + var->value->type = result_type; assert(var->value->type); @@ -12977,6 +12985,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, VariableTableEntry *var) { Error err; + while (var->next_var != nullptr) { + var = var->next_var; + } + if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) { assert(ira->codegen->errors.length != 0); return ira->codegen->invalid_instruction; |
