| 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 | 2350 | IrInstruction base; |
| 2351 | 2351 | |
| 2352 | 2352 | ZigVar *var; |
| 2353 | ScopeFnDef *crossed_fndef_scope; | |
| 2353 | 2354 | }; |
| 2354 | 2355 | |
| 2355 | 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 | 3519 | if (!type_is_invalid(value->type)) { |
| 3520 | 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 | 3523 | if (existing_var && !existing_var->shadowable) { |
| 3524 | 3524 | ErrorMsg *msg = add_node_error(g, source_node, |
| 3525 | 3525 | buf_sprintf("redeclaration of variable '%s'", buf_ptr(name))); |
| ... | ... | @@ -3726,12 +3726,16 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) { |
| 3726 | 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 | 3731 | while (scope) { |
| 3731 | 3732 | if (scope->id == ScopeIdVarDecl) { |
| 3732 | 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 | 3737 | return var_scope->var; |
| 3738 | } | |
| 3735 | 3739 | } else if (scope->id == ScopeIdDecls) { |
| 3736 | 3740 | ScopeDecls *decls_scope = (ScopeDecls *)scope; |
| 3737 | 3741 | auto entry = decls_scope->decl_table.maybe_get(name); |
| ... | ... | @@ -3739,10 +3743,15 @@ ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) { |
| 3739 | 3743 | Tld *tld = entry->value; |
| 3740 | 3744 | if (tld->id == TldIdVar) { |
| 3741 | 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 | 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 | 3756 | scope = scope->parent; |
| 3748 | 3757 | } |
src/analyze.hpp+1-1| ... | ... | @@ -48,7 +48,7 @@ bool type_has_bits(ZigType *type_entry); |
| 48 | 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 | 52 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 53 | 53 | void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node); |
| 54 | 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 | 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 | 1120 | IrInstructionVarPtr *instruction = ir_build_instruction<IrInstructionVarPtr>(irb, scope, source_node); |
| 1119 | 1121 | instruction->var = var; |
| 1122 | instruction->crossed_fndef_scope = crossed_fndef_scope; | |
| 1120 | 1123 | |
| 1121 | 1124 | ir_ref_var(var); |
| 1122 | 1125 | |
| 1123 | 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 | 1133 | static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, |
| 1127 | 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 | 3343 | buf_init_from_buf(&variable_entry->name, name); |
| 3337 | 3344 | |
| 3338 | 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 | 3347 | if (existing_var && !existing_var->shadowable) { |
| 3341 | 3348 | ErrorMsg *msg = add_node_error(codegen, node, |
| 3342 | 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 | 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 | 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 | 3813 | if (lval == LValPtr) |
| 3806 | 3814 | return var_ptr; |
| 3807 | 3815 | else |
| ... | ... | @@ -5822,7 +5830,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 5822 | 5830 | output_types[i] = return_type; |
| 5823 | 5831 | } else { |
| 5824 | 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 | 5836 | if (var) { |
| 5827 | 5837 | output_vars[i] = var; |
| 5828 | 5838 | } else { |
| ... | ... | @@ -14157,17 +14167,26 @@ static ZigType *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi |
| 14157 | 14167 | return resolved_type; |
| 14158 | 14168 | } |
| 14159 | 14169 | |
| 14160 | static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | |
| 14161 | ZigVar *var) | |
| 14162 | { | |
| 14170 | static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) { | |
| 14163 | 14171 | IrInstruction *result = ir_get_var_ptr(ira, instruction, var); |
| 14164 | 14172 | ir_link_new_instruction(result, instruction); |
| 14165 | 14173 | return result->value.type; |
| 14166 | 14174 | } |
| 14167 | 14175 | |
| 14168 | static ZigType *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *var_ptr_instruction) { | |
| 14169 | ZigVar *var = var_ptr_instruction->var; | |
| 14170 | return ir_analyze_var_ptr(ira, &var_ptr_instruction->base, var); | |
| 14176 | static ZigType *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructionVarPtr *instruction) { | |
| 14177 | ZigVar *var = instruction->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 | 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 | 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 | 1 | const tests = @import("tests.zig"); |
| 2 | 2 | |
| 3 | 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 | 24 | cases.add( |
| 5 | 25 | "non int passed to @intToFloat", |
| 6 | 26 | \\export fn entry() void { |