| author | |
| committer | |
| log | 1d8b8ad687facd25a27b3ff6d083812b45cd529f |
| tree | 8f21e06cbbd22156a8d36f214aa4e52bff8f175c |
| parent | 8400163e0245f68833e29db22ae3bcc1fb8bf9ae |
| signature |
from a fn defined inside it. closes #8766 files changed, 80 insertions(+), 16 deletions(-)
src/all_types.hpp+1| ... | @@ -2350,6 +2350,7 @@ struct IrInstructionVarPtr { | ... | @@ -2350,6 +2350,7 @@ struct IrInstructionVarPtr { |
| 2350 | IrInstruction base; | 2350 | IrInstruction base; |
| 2351 | 2351 | ||
| 2352 | ZigVar *var; | 2352 | ZigVar *var; |
| 2353 | ScopeFnDef *crossed_fndef_scope; | ||
| 2353 | }; | 2354 | }; |
| 2354 | 2355 | ||
| 2355 | struct IrInstructionCall { | 2356 | struct IrInstructionCall { |
src/analyze.cpp+13-4| ... | @@ -3519,7 +3519,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3519,7 +3519,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3519 | if (!type_is_invalid(value->type)) { | 3519 | if (!type_is_invalid(value->type)) { |
| 3520 | variable_entry->align_bytes = get_abi_alignment(g, value->type); | 3520 | variable_entry->align_bytes = get_abi_alignment(g, value->type); |
| 3521 | 3521 | ||
| 3522 | ZigVar *existing_var = find_variable(g, parent_scope, name); | 3522 | ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr); |
| 3523 | if (existing_var && !existing_var->shadowable) { | 3523 | if (existing_var && !existing_var->shadowable) { |
| 3524 | ErrorMsg *msg = add_node_error(g, source_node, | 3524 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3525 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 3525 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| ... | @@ -3726,12 +3726,16 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { | ... | @@ -3726,12 +3726,16 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { |
| 3726 | return nullptr; | 3726 | return nullptr; |
| 3727 | } | 3727 | } |
| 3728 | 3728 | ||
| 3729 | ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) { | 3729 | ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name, ScopeFnDef **crossed_fndef_scope) { |
| 3730 | ScopeFnDef *my_crossed_fndef_scope = nullptr; | ||
| 3730 | while (scope) { | 3731 | while (scope) { |
| 3731 | if (scope->id == ScopeIdVarDecl) { | 3732 | if (scope->id == ScopeIdVarDecl) { |
| 3732 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; | 3733 | ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; |
| 3733 | if (buf_eql_buf(name, &var_scope->var->name)) | 3734 | if (buf_eql_buf(name, &var_scope->var->name)) { |
| 3735 | if (crossed_fndef_scope != nullptr) | ||
| 3736 | *crossed_fndef_scope = my_crossed_fndef_scope; | ||
| 3734 | return var_scope->var; | 3737 | return var_scope->var; |
| 3738 | } | ||
| 3735 | } else if (scope->id == ScopeIdDecls) { | 3739 | } else if (scope->id == ScopeIdDecls) { |
| 3736 | ScopeDecls *decls_scope = (ScopeDecls *)scope; | 3740 | ScopeDecls *decls_scope = (ScopeDecls *)scope; |
| 3737 | auto entry = decls_scope->decl_table.maybe_get(name); | 3741 | auto entry = decls_scope->decl_table.maybe_get(name); |
| ... | @@ -3739,10 +3743,15 @@ ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) { | ... | @@ -3739,10 +3743,15 @@ ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) { |
| 3739 | Tld *tld = entry->value; | 3743 | Tld *tld = entry->value; |
| 3740 | if (tld->id == TldIdVar) { | 3744 | if (tld->id == TldIdVar) { |
| 3741 | TldVar *tld_var = (TldVar *)tld; | 3745 | TldVar *tld_var = (TldVar *)tld; |
| 3742 | if (tld_var->var) | 3746 | if (tld_var->var) { |
| 3747 | if (crossed_fndef_scope != nullptr) | ||
| 3748 | *crossed_fndef_scope = nullptr; | ||
| 3743 | return tld_var->var; | 3749 | return tld_var->var; |
| 3750 | } | ||
| 3744 | } | 3751 | } |
| 3745 | } | 3752 | } |
| 3753 | } else if (scope->id == ScopeIdFnDef) { | ||
| 3754 | my_crossed_fndef_scope = (ScopeFnDef *)scope; | ||
| 3746 | } | 3755 | } |
| 3747 | scope = scope->parent; | 3756 | scope = scope->parent; |
| 3748 | } | 3757 | } |
src/analyze.hpp+1-1| ... | @@ -48,7 +48,7 @@ bool type_has_bits(ZigType *type_entry); | ... | @@ -48,7 +48,7 @@ bool type_has_bits(ZigType *type_entry); |
| 48 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); | 48 | ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code); |
| 49 | 49 | ||
| 50 | 50 | ||
| 51 | ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name); | 51 | ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); |
| 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); | 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); | 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); |
| 54 | bool type_is_codegen_pointer(ZigType *type); | 54 | bool type_is_codegen_pointer(ZigType *type); |
src/ir.cpp+30-11| ... | @@ -1114,15 +1114,22 @@ static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_in | ... | @@ -1114,15 +1114,22 @@ static IrInstruction *ir_build_bin_op_from(IrBuilder *irb, IrInstruction *old_in |
| 1114 | return new_instruction; | 1114 | return new_instruction; |
| 1115 | } | 1115 | } |
| 1116 | 1116 | ||
| 1117 | static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) { | 1117 | static IrInstruction *ir_build_var_ptr_x(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, |
| 1118 | ScopeFnDef *crossed_fndef_scope) | ||
| 1119 | { | ||
| 1118 | IrInstructionVarPtr *instruction = ir_build_instruction<IrInstructionVarPtr>(irb, scope, source_node); | 1120 | IrInstructionVarPtr *instruction = ir_build_instruction<IrInstructionVarPtr>(irb, scope, source_node); |
| 1119 | instruction->var = var; | 1121 | instruction->var = var; |
| 1122 | instruction->crossed_fndef_scope = crossed_fndef_scope; | ||
| 1120 | 1123 | ||
| 1121 | ir_ref_var(var); | 1124 | ir_ref_var(var); |
| 1122 | 1125 | ||
| 1123 | return &instruction->base; | 1126 | return &instruction->base; |
| 1124 | } | 1127 | } |
| 1125 | 1128 | ||
| 1129 | static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) { | ||
| 1130 | return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr); | ||
| 1131 | } | ||
| 1132 | |||
| 1126 | static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, | 1133 | static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, |
| 1127 | IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len) | 1134 | IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len) |
| 1128 | { | 1135 | { |
| ... | @@ -3336,7 +3343,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s | ... | @@ -3336,7 +3343,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s |
| 3336 | buf_init_from_buf(&variable_entry->name, name); | 3343 | buf_init_from_buf(&variable_entry->name, name); |
| 3337 | 3344 | ||
| 3338 | if (!skip_name_check) { | 3345 | if (!skip_name_check) { |
| 3339 | ZigVar *existing_var = find_variable(codegen, parent_scope, name); | 3346 | ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr); |
| 3340 | if (existing_var && !existing_var->shadowable) { | 3347 | if (existing_var && !existing_var->shadowable) { |
| 3341 | ErrorMsg *msg = add_node_error(codegen, node, | 3348 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3342 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); | 3349 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| ... | @@ -3799,9 +3806,10 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, | ... | @@ -3799,9 +3806,10 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3799 | } | 3806 | } |
| 3800 | } | 3807 | } |
| 3801 | 3808 | ||
| 3802 | ZigVar *var = find_variable(irb->codegen, scope, variable_name); | 3809 | ScopeFnDef *crossed_fndef_scope; |
| 3810 | ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope); | ||
| 3803 | if (var) { | 3811 | if (var) { |
| 3804 | IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var); | 3812 | IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope); |
| 3805 | if (lval == LValPtr) | 3813 | if (lval == LValPtr) |
| 3806 | return var_ptr; | 3814 | return var_ptr; |
| 3807 | else | 3815 | else |
| ... | @@ -5822,7 +5830,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod | ... | @@ -5822,7 +5830,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5822 | output_types[i] = return_type; | 5830 | output_types[i] = return_type; |
| 5823 | } else { | 5831 | } else { |
| 5824 | Buf *variable_name = asm_output->variable_name; | 5832 | Buf *variable_name = asm_output->variable_name; |
| 5825 | ZigVar *var = find_variable(irb->codegen, scope, variable_name); | 5833 | // TODO there is some duplication here with ir_gen_symbol. I need to do a full audit of how |
| 5834 | // inline assembly works. https://github.com/ziglang/zig/issues/215 | ||
| 5835 | ZigVar *var = find_variable(irb->codegen, scope, variable_name, nullptr); | ||
| 5826 | if (var) { | 5836 | if (var) { |
| 5827 | output_vars[i] = var; | 5837 | output_vars[i] = var; |
| 5828 | } else { | 5838 | } else { |
| ... | @@ -14157,17 +14167,26 @@ static ZigType *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi | ... | @@ -14157,17 +14167,26 @@ static ZigType *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi |
| 14157 | return resolved_type; | 14167 | return resolved_type; |
| 14158 | } | 14168 | } |
| 14159 | 14169 | ||
| 14160 | static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | 14170 | static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { |
| 14161 | ZigVar *var) | ||
| 14162 | { | ||
| 14163 | IrInstruction *result = ir_get_var_ptr(ira, instruction, var); | 14171 | IrInstruction *result = ir_get_var_ptr(ira, instruction, var); |
| 14164 | ir_link_new_instruction(result, instruction); | 14172 | ir_link_new_instruction(result, instruction); |
| 14165 | return result->value.type; | 14173 | return result->value.type; |
| 14166 | } | 14174 | } |
| 14167 | 14175 | ||
| 14168 | static ZigType *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { | 14176 | static ZigType *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *instruction) { |
| 14169 | ZigVar *var = var_ptr_instruction->var; | 14177 | ZigVar *var = instruction->var; |
| 14170 | return ir_analyze_var_ptr(ira, &var_ptr_instruction->base, var); | 14178 | IrInstruction *result = ir_get_var_ptr(ira, &instruction->base, var); |
| 14179 | if (instruction->crossed_fndef_scope != nullptr && !instr_is_comptime(result)) { | ||
| 14180 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, | ||
| 14181 | buf_sprintf("'%s' not accessible from inner function", buf_ptr(&var->name))); | ||
| 14182 | add_error_note(ira->codegen, msg, instruction->crossed_fndef_scope->base.source_node, | ||
| 14183 | buf_sprintf("crossed function definition here")); | ||
| 14184 | add_error_note(ira->codegen, msg, var->decl_node, | ||
| 14185 | buf_sprintf("declared here")); | ||
| 14186 | return ira->codegen->builtin_types.entry_invalid; | ||
| 14187 | } | ||
| 14188 | ir_link_new_instruction(result, &instruction->base); | ||
| 14189 | return result->value.type; | ||
| 14171 | } | 14190 | } |
| 14172 | 14191 | ||
| 14173 | static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) { | 14192 | static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align) { |
test/cases/fn.zig+15| ... | @@ -176,3 +176,18 @@ test "pass by non-copying value as method, at comptime" { | ... | @@ -176,3 +176,18 @@ test "pass by non-copying value as method, at comptime" { |
| 176 | assert(pt.addPointCoords() == 3); | 176 | assert(pt.addPointCoords() == 3); |
| 177 | } | 177 | } |
| 178 | } | 178 | } |
| 179 | |||
| 180 | fn outer(y: u32) fn (u32) u32 { | ||
| 181 | const Y = @typeOf(y); | ||
| 182 | const st = struct { | ||
| 183 | fn get(z: u32) u32 { | ||
| 184 | return z + @sizeOf(Y); | ||
| 185 | } | ||
| 186 | }; | ||
| 187 | return st.get; | ||
| 188 | } | ||
| 189 | |||
| 190 | test "return inner function which references comptime variable of outer function" { | ||
| 191 | var func = outer(10); | ||
| 192 | assert(func(3) == 7); | ||
| 193 | } |
test/compile_errors.zig+20| ... | @@ -1,6 +1,26 @@ | ... | @@ -1,6 +1,26 @@ |
| 1 | const tests = @import("tests.zig"); | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | ||
| 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 3 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4 | cases.add( | ||
| 5 | "accessing runtime parameter from outer function", | ||
| 6 | \\fn outer(y: u32) fn (u32) u32 { | ||
| 7 | \\ const st = struct { | ||
| 8 | \\ fn get(z: u32) u32 { | ||
| 9 | \\ return z + y; | ||
| 10 | \\ } | ||
| 11 | \\ }; | ||
| 12 | \\ return st.get; | ||
| 13 | \\} | ||
| 14 | \\export fn entry() void { | ||
| 15 | \\ var func = outer(10); | ||
| 16 | \\ var x = func(3); | ||
| 17 | \\} | ||
| 18 | , | ||
| 19 | ".tmp_source.zig:4:24: error: 'y' not accessible from inner function", | ||
| 20 | ".tmp_source.zig:3:28: note: crossed function definition here", | ||
| 21 | ".tmp_source.zig:1:10: note: declared here", | ||
| 22 | ); | ||
| 23 | |||
| 4 | cases.add( | 24 | cases.add( |
| 5 | "non int passed to @intToFloat", | 25 | "non int passed to @intToFloat", |
| 6 | \\export fn entry() void { | 26 | \\export fn entry() void { |