authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-07 00:20:26-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-01-07 00:28:37-05:00
logbb39e503c0179b18c4e440bae021e786c70deb06
tree9f65059a937a5377435f04ed1defad51d0224315
parentad438cfd40aba682a0bcd88ed607c2cbd378f647

fix struct inside function referencing local const

closes #672 the crash and compile errors are fixed but structs inside functions still get named after the functions they're in. this will be fixed later.

4 files changed, 82 insertions(+), 44 deletions(-)

src/all_types.hpp+3-8
...@@ -37,13 +37,7 @@ struct ScopeDecls;...@@ -37,13 +37,7 @@ struct ScopeDecls;
37struct ZigWindowsSDK;37struct ZigWindowsSDK;
38struct Tld;38struct Tld;
39struct TldExport;39struct TldExport;
4040struct IrAnalyze;
41struct IrGotoItem {
42 AstNode *source_node;
43 IrBasicBlock *bb;
44 size_t instruction_index;
45 Scope *scope;
46};
4741
48struct IrExecutable {42struct IrExecutable {
49 ZigList<IrBasicBlock *> basic_block_list;43 ZigList<IrBasicBlock *> basic_block_list;
...@@ -53,13 +47,13 @@ struct IrExecutable {...@@ -53,13 +47,13 @@ struct IrExecutable {
53 size_t *backward_branch_count;47 size_t *backward_branch_count;
54 size_t backward_branch_quota;48 size_t backward_branch_quota;
55 bool invalid;49 bool invalid;
56 ZigList<IrGotoItem> goto_list;
57 bool is_inline;50 bool is_inline;
58 FnTableEntry *fn_entry;51 FnTableEntry *fn_entry;
59 Buf *c_import_buf;52 Buf *c_import_buf;
60 AstNode *source_node;53 AstNode *source_node;
61 IrExecutable *parent_exec;54 IrExecutable *parent_exec;
62 IrExecutable *source_exec;55 IrExecutable *source_exec;
56 IrAnalyze *analysis;
63 Scope *begin_scope;57 Scope *begin_scope;
64 ZigList<Tld *> tld_list;58 ZigList<Tld *> tld_list;
65};59};
...@@ -1626,6 +1620,7 @@ struct VariableTableEntry {...@@ -1626,6 +1620,7 @@ struct VariableTableEntry {
1626 LLVMValueRef param_value_ref;1620 LLVMValueRef param_value_ref;
1627 bool shadowable;1621 bool shadowable;
1628 size_t mem_slot_index;1622 size_t mem_slot_index;
1623 IrExecutable *owner_exec;
1629 size_t ref_count;1624 size_t ref_count;
1630 VarLinkage linkage;1625 VarLinkage linkage;
1631 IrInstruction *decl_instruction;1626 IrInstruction *decl_instruction;
src/ir.cpp+48-36
...@@ -2530,8 +2530,10 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s...@@ -2530,8 +2530,10 @@ static VariableTableEntry *ir_create_var(IrBuilder *irb, AstNode *node, Scope *s
2530 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)2530 bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime)
2531{2531{
2532 VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_comptime);2532 VariableTableEntry *var = create_local_var(irb->codegen, node, scope, name, src_is_const, gen_is_const, is_shadowable, is_comptime);
2533 if (is_comptime != nullptr || gen_is_const)2533 if (is_comptime != nullptr || gen_is_const) {
2534 var->mem_slot_index = exec_next_mem_slot(irb->exec);2534 var->mem_slot_index = exec_next_mem_slot(irb->exec);
2535 var->owner_exec = irb->exec;
2536 }
2535 assert(var->child_scope);2537 assert(var->child_scope);
2536 return var;2538 return var;
2537}2539}
...@@ -7037,48 +7039,48 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node...@@ -7037,48 +7039,48 @@ IrInstruction *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node
7037 if (expected_type != nullptr && type_is_invalid(expected_type))7039 if (expected_type != nullptr && type_is_invalid(expected_type))
7038 return codegen->invalid_instruction;7040 return codegen->invalid_instruction;
70397041
7040 IrExecutable ir_executable = {0};7042 IrExecutable *ir_executable = allocate<IrExecutable>(1);
7041 ir_executable.source_node = source_node;7043 ir_executable->source_node = source_node;
7042 ir_executable.parent_exec = parent_exec;7044 ir_executable->parent_exec = parent_exec;
7043 ir_executable.name = exec_name;7045 ir_executable->name = exec_name;
7044 ir_executable.is_inline = true;7046 ir_executable->is_inline = true;
7045 ir_executable.fn_entry = fn_entry;7047 ir_executable->fn_entry = fn_entry;
7046 ir_executable.c_import_buf = c_import_buf;7048 ir_executable->c_import_buf = c_import_buf;
7047 ir_executable.begin_scope = scope;7049 ir_executable->begin_scope = scope;
7048 ir_gen(codegen, node, scope, &ir_executable);7050 ir_gen(codegen, node, scope, ir_executable);
70497051
7050 if (ir_executable.invalid)7052 if (ir_executable->invalid)
7051 return codegen->invalid_instruction;7053 return codegen->invalid_instruction;
70527054
7053 if (codegen->verbose_ir) {7055 if (codegen->verbose_ir) {
7054 fprintf(stderr, "\nSource: ");7056 fprintf(stderr, "\nSource: ");
7055 ast_render(codegen, stderr, node, 4);7057 ast_render(codegen, stderr, node, 4);
7056 fprintf(stderr, "\n{ // (IR)\n");7058 fprintf(stderr, "\n{ // (IR)\n");
7057 ir_print(codegen, stderr, &ir_executable, 4);7059 ir_print(codegen, stderr, ir_executable, 4);
7058 fprintf(stderr, "}\n");7060 fprintf(stderr, "}\n");
7059 }7061 }
7060 IrExecutable analyzed_executable = {0};7062 IrExecutable *analyzed_executable = allocate<IrExecutable>(1);
7061 analyzed_executable.source_node = source_node;7063 analyzed_executable->source_node = source_node;
7062 analyzed_executable.parent_exec = parent_exec;7064 analyzed_executable->parent_exec = parent_exec;
7063 analyzed_executable.source_exec = &ir_executable;7065 analyzed_executable->source_exec = ir_executable;
7064 analyzed_executable.name = exec_name;7066 analyzed_executable->name = exec_name;
7065 analyzed_executable.is_inline = true;7067 analyzed_executable->is_inline = true;
7066 analyzed_executable.fn_entry = fn_entry;7068 analyzed_executable->fn_entry = fn_entry;
7067 analyzed_executable.c_import_buf = c_import_buf;7069 analyzed_executable->c_import_buf = c_import_buf;
7068 analyzed_executable.backward_branch_count = backward_branch_count;7070 analyzed_executable->backward_branch_count = backward_branch_count;
7069 analyzed_executable.backward_branch_quota = backward_branch_quota;7071 analyzed_executable->backward_branch_quota = backward_branch_quota;
7070 analyzed_executable.begin_scope = scope;7072 analyzed_executable->begin_scope = scope;
7071 TypeTableEntry *result_type = ir_analyze(codegen, &ir_executable, &analyzed_executable, expected_type, node);7073 TypeTableEntry *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, node);
7072 if (type_is_invalid(result_type))7074 if (type_is_invalid(result_type))
7073 return codegen->invalid_instruction;7075 return codegen->invalid_instruction;
70747076
7075 if (codegen->verbose_ir) {7077 if (codegen->verbose_ir) {
7076 fprintf(stderr, "{ // (analyzed)\n");7078 fprintf(stderr, "{ // (analyzed)\n");
7077 ir_print(codegen, stderr, &analyzed_executable, 4);7079 ir_print(codegen, stderr, analyzed_executable, 4);
7078 fprintf(stderr, "}\n");7080 fprintf(stderr, "}\n");
7079 }7081 }
70807082
7081 return ir_exec_const_result(codegen, &analyzed_executable);7083 return ir_exec_const_result(codegen, analyzed_executable);
7082}7084}
70837085
7084static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {7086static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
...@@ -9334,6 +9336,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -9334,6 +9336,8 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
9334 IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);9336 IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type);
9335 bool is_comptime_var = ir_get_var_is_comptime(var);9337 bool is_comptime_var = ir_get_var_is_comptime(var);
93369338
9339 bool var_class_requires_const = false;
9340
9337 TypeTableEntry *result_type = casted_init_value->value.type;9341 TypeTableEntry *result_type = casted_init_value->value.type;
9338 if (type_is_invalid(result_type)) {9342 if (type_is_invalid(result_type)) {
9339 result_type = ira->codegen->builtin_types.entry_invalid;9343 result_type = ira->codegen->builtin_types.entry_invalid;
...@@ -9345,6 +9349,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -9345,6 +9349,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
9345 result_type = ira->codegen->builtin_types.entry_invalid;9349 result_type = ira->codegen->builtin_types.entry_invalid;
9346 break;9350 break;
9347 case VarClassRequiredConst:9351 case VarClassRequiredConst:
9352 var_class_requires_const = true;
9348 if (!var->src_is_const && !is_comptime_var) {9353 if (!var->src_is_const && !is_comptime_var) {
9349 ir_add_error_node(ira, source_node,9354 ir_add_error_node(ira, source_node,
9350 buf_sprintf("variable of type '%s' must be const or comptime",9355 buf_sprintf("variable of type '%s' must be const or comptime",
...@@ -9366,8 +9371,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -9366,8 +9371,6 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
9366 return ira->codegen->builtin_types.entry_void;9371 return ira->codegen->builtin_types.entry_void;
9367 }9372 }
93689373
9369 bool is_comptime = ir_get_var_is_comptime(var);
9370
9371 if (decl_var_instruction->align_value == nullptr) {9374 if (decl_var_instruction->align_value == nullptr) {
9372 var->align_bytes = get_abi_alignment(ira->codegen, result_type);9375 var->align_bytes = get_abi_alignment(ira->codegen, result_type);
9373 } else {9376 } else {
...@@ -9382,12 +9385,12 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc...@@ -9382,12 +9385,12 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc
9382 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];9385 ConstExprValue *mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];
9383 *mem_slot = casted_init_value->value;9386 *mem_slot = casted_init_value->value;
93849387
9385 if (is_comptime) {9388 if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) {
9386 ir_build_const_from(ira, &decl_var_instruction->base);9389 ir_build_const_from(ira, &decl_var_instruction->base);
9387 return ira->codegen->builtin_types.entry_void;9390 return ira->codegen->builtin_types.entry_void;
9388 }9391 }
9389 }9392 }
9390 } else if (is_comptime) {9393 } else if (is_comptime_var) {
9391 ir_add_error(ira, &decl_var_instruction->base,9394 ir_add_error(ira, &decl_var_instruction->base,
9392 buf_sprintf("cannot store runtime value in compile time variable"));9395 buf_sprintf("cannot store runtime value in compile time variable"));
9393 var->value->type = ira->codegen->builtin_types.entry_invalid;9396 var->value->type = ira->codegen->builtin_types.entry_invalid;
...@@ -9690,6 +9693,10 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in...@@ -9690,6 +9693,10 @@ static VariableTableEntry *get_fn_var_by_index(FnTableEntry *fn_entry, size_t in
9690static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,9693static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
9691 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)9694 VariableTableEntry *var, bool is_const_ptr, bool is_volatile_ptr)
9692{9695{
9696 if (var->mem_slot_index != SIZE_MAX && var->owner_exec->analysis == nullptr) {
9697 assert(ira->codegen->errors.length != 0);
9698 return ira->codegen->invalid_instruction;
9699 }
9693 assert(var->value->type);9700 assert(var->value->type);
9694 if (type_is_invalid(var->value->type))9701 if (type_is_invalid(var->value->type))
9695 return ira->codegen->invalid_instruction;9702 return ira->codegen->invalid_instruction;
...@@ -9700,9 +9707,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,...@@ -9700,9 +9707,14 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
9700 if (var->value->special == ConstValSpecialStatic) {9707 if (var->value->special == ConstValSpecialStatic) {
9701 mem_slot = var->value;9708 mem_slot = var->value;
9702 } else {9709 } else {
9703 // TODO once the analyze code is fully ported over to IR we won't need this SIZE_MAX thing.9710 if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) {
9704 if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const))9711 // find the relevant exec_context
9705 mem_slot = &ira->exec_context.mem_slot_list[var->mem_slot_index];9712 assert(var->owner_exec != nullptr);
9713 assert(var->owner_exec->analysis != nullptr);
9714 IrExecContext *exec_context = &var->owner_exec->analysis->exec_context;
9715 assert(var->mem_slot_index < exec_context->mem_slot_count);
9716 mem_slot = &exec_context->mem_slot_list[var->mem_slot_index];
9717 }
9706 }9718 }
97079719
9708 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;9720 bool is_const = (var->value->type->id == TypeTableEntryIdMetaType) ? is_const_ptr : var->src_is_const;
...@@ -15328,8 +15340,8 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl...@@ -15328,8 +15340,8 @@ TypeTableEntry *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutabl
15328 assert(!old_exec->invalid);15340 assert(!old_exec->invalid);
15329 assert(expected_type == nullptr || !type_is_invalid(expected_type));15341 assert(expected_type == nullptr || !type_is_invalid(expected_type));
1533015342
15331 IrAnalyze ir_analyze_data = {};15343 IrAnalyze *ira = allocate<IrAnalyze>(1);
15332 IrAnalyze *ira = &ir_analyze_data;15344 old_exec->analysis = ira;
15333 ira->codegen = codegen;15345 ira->codegen = codegen;
15334 ira->explicit_return_type = expected_type;15346 ira->explicit_return_type = expected_type;
1533515347
test/cases/misc.zig+19
...@@ -577,3 +577,22 @@ test "implicit comptime while" {...@@ -577,3 +577,22 @@ test "implicit comptime while" {
577 @compileError("bad");577 @compileError("bad");
578 }578 }
579}579}
580
581test "struct inside function" {
582 testStructInFn();
583 comptime testStructInFn();
584}
585
586fn testStructInFn() {
587 const BlockKind = u32;
588
589 const Block = struct {
590 kind: BlockKind,
591 };
592
593 var block = Block { .kind = 1234 };
594
595 block.kind += 1;
596
597 assert(block.kind == 1235);
598}
test/compile_errors.zig+12
...@@ -1,6 +1,18 @@...@@ -1,6 +1,18 @@
1const tests = @import("tests.zig");1const tests = @import("tests.zig");
22
3pub fn addCases(cases: &tests.CompileErrorContext) {3pub fn addCases(cases: &tests.CompileErrorContext) {
4 cases.add("bad identifier in function with struct defined inside function which references local const",
5 \\export fn entry() {
6 \\ const BlockKind = u32;
7 \\
8 \\ const Block = struct {
9 \\ kind: BlockKind,
10 \\ };
11 \\
12 \\ bogus;
13 \\}
14 , ".tmp_source.zig:8:5: error: use of undeclared identifier 'bogus'");
15
4 cases.add("labeled break not found",16 cases.add("labeled break not found",
5 \\export fn entry() {17 \\export fn entry() {
6 \\ blah: while (true) {18 \\ blah: while (true) {