authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-28 15:24:28-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-08-28 15:24:28-04:00
log09cc1dc66067f378a1508e34c0714b659b445724
treee5fc5298f5240934716609d7727c01071f869707
parent048f506aa6b78dd13a593b6bb12a317c5a047bc7
signaturelock-open Commit is signed but in an unrecognized format.

fix crash when var in inline loop has different types

closes #917 closes #845 closes #741 closes #740

4 files changed, 58 insertions(+), 30 deletions(-)

src/all_types.hpp+5
......@@ -1807,6 +1807,11 @@ struct VariableTableEntry {
18071807 VarLinkage linkage;
18081808 IrInstruction *decl_instruction;
18091809 uint32_t align_bytes;
1810
1811 // In an inline loop, multiple variables may be created,
1812 // In this case, a reference to a variable should follow
1813 // this pointer to the redefined variable.
1814 VariableTableEntry *next_var;
18101815};
18111816
18121817struct ErrorTableEntry {
src/ir.cpp+38-26
......@@ -3280,7 +3280,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
32803280}
32813281
32823282static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_scope,
3283 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
3283 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime,
3284 bool skip_name_check)
32843285{
32853286 VariableTableEntry *variable_entry = allocate<VariableTableEntry>(1);
32863287 variable_entry->parent_scope = parent_scope;
......@@ -3293,29 +3294,30 @@ static VariableTableEntry *create_local_var(CodeGen *codegen, AstNode *node, Sco
32933294 if (name) {
32943295 buf_init_from_buf(&variable_entry->name, name);
32953296
3296 VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name);
3297 if (existing_var && !existing_var->shadowable) {
3298 ErrorMsg *msg = add_node_error(codegen, node,
3299 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
3300 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
3301 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3302 } else {
3303 TypeTableEntry *type = get_primitive_type(codegen, name);
3304 if (type != nullptr) {
3305 add_node_error(codegen, node,
3306 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
3297 if (!skip_name_check) {
3298 VariableTableEntry *existing_var = find_variable(codegen, parent_scope, name);
3299 if (existing_var && !existing_var->shadowable) {
3300 ErrorMsg *msg = add_node_error(codegen, node,
3301 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
3302 add_error_note(codegen, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
33073303 variable_entry->value->type = codegen->builtin_types.entry_invalid;
33083304 } else {
3309 Tld *tld = find_decl(codegen, parent_scope, name);
3310 if (tld != nullptr) {
3311 ErrorMsg *msg = add_node_error(codegen, node,
3312 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
3313 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
3305 TypeTableEntry *type = get_primitive_type(codegen, name);
3306 if (type != nullptr) {
3307 add_node_error(codegen, node,
3308 buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
33143309 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3310 } else {
3311 Tld *tld = find_decl(codegen, parent_scope, name);
3312 if (tld != nullptr) {
3313 ErrorMsg *msg = add_node_error(codegen, node,
3314 buf_sprintf("redefinition of '%s'", buf_ptr(name)));
3315 add_error_note(codegen, msg, tld->source_node, buf_sprintf("previous definition is here"));
3316 variable_entry->value->type = codegen->builtin_types.entry_invalid;
3317 }
33153318 }
33163319 }
33173320 }
3318
33193321 } else {
33203322 assert(is_shadowable);
33213323 // 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
33383340 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
33393341{
33403342 bool is_underscored = name ? buf_eql_str(name, "_") : false;
3341 VariableTableEntry *var = create_local_var( irb->codegen
3342 , node
3343 , scope
3344 , (is_underscored ? nullptr : name)
3345 , src_is_const
3346 , gen_is_const
3347 , (is_underscored ? true : is_shadowable)
3348 , is_comptime );
3343 VariableTableEntry *var = create_local_var(irb->codegen, node, scope,
3344 (is_underscored ? nullptr : name), src_is_const, gen_is_const,
3345 (is_underscored ? true : is_shadowable), is_comptime, false);
33493346 if (is_comptime != nullptr || gen_is_const) {
33503347 var->mem_slot_index = exec_next_mem_slot(irb->exec);
33513348 var->owner_exec = irb->exec;
......@@ -12495,6 +12492,17 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
1249512492 }
1249612493 }
1249712494
12495 if (var->value->type != nullptr && var->value->type != result_type && !is_comptime_var) {
12496 // This is at least the second time we've seen this variable declaration during analysis.
12497 // This means that this is actually a different variable due to, e.g. an inline while loop.
12498 // We make a new variable so that it can hold a different type, and so the debug info can
12499 // be distinct.
12500 VariableTableEntry *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope,
12501 &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true);
12502 var->next_var = new_var;
12503 var = new_var;
12504 }
12505
1249812506 var->value->type = result_type;
1249912507 assert(var->value->type);
1250012508
......@@ -12977,6 +12985,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
1297712985 VariableTableEntry *var)
1297812986{
1297912987 Error err;
12988 while (var->next_var != nullptr) {
12989 var = var->next_var;
12990 }
12991
1298012992 if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {
1298112993 assert(ira->codegen->errors.length != 0);
1298212994 return ira->codegen->invalid_instruction;
test/cases/eval.zig+13
......@@ -652,3 +652,16 @@ fn loopNTimes(comptime n: usize) void {
652652 comptime var i = 0;
653653 inline while (i < n) : (i += 1) {}
654654}
655
656test "variable inside inline loop that has different types on different iterations" {
657 testVarInsideInlineLoop(true, u32(42));
658}
659
660fn testVarInsideInlineLoop(args: ...) void {
661 comptime var i = 0;
662 inline while (i < args.len) : (i += 1) {
663 const x = args[i];
664 if (i == 0) assert(x);
665 if (i == 1) assert(x == 42);
666 }
667}
test/cases/for.zig+2-4
......@@ -71,8 +71,7 @@ fn testBreakOuter() void {
7171 var array = "aoeu";
7272 var count: usize = 0;
7373 outer: for (array) |_| {
74 // TODO shouldn't get error for redeclaring "_"
75 for (array) |_2| {
74 for (array) |_| {
7675 count += 1;
7776 break :outer;
7877 }
......@@ -89,8 +88,7 @@ fn testContinueOuter() void {
8988 var array = "aoeu";
9089 var counter: usize = 0;
9190 outer: for (array) |_| {
92 // TODO shouldn't get error for redeclaring "_"
93 for (array) |_2| {
91 for (array) |_| {
9492 counter += 1;
9593 continue :outer;
9694 }