authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-05 20:32:06-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-09-05 20:32:06-04:00
log1d8b8ad687facd25a27b3ff6d083812b45cd529f
tree8f21e06cbbd22156a8d36f214aa4e52bff8f175c
parent8400163e0245f68833e29db22ae3bcc1fb8bf9ae
signaturelock-open Commit is signed but in an unrecognized format.

add compile error for using outer scoped runtime variables

from a fn defined inside it. closes #876

6 files changed, 80 insertions(+), 16 deletions(-)

src/all_types.hpp+1
......@@ -2350,6 +2350,7 @@ struct IrInstructionVarPtr {
23502350 IrInstruction base;
23512351
23522352 ZigVar *var;
2353 ScopeFnDef *crossed_fndef_scope;
23532354};
23542355
23552356struct IrInstructionCall {
src/analyze.cpp+13-4
......@@ -3519,7 +3519,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
35193519 if (!type_is_invalid(value->type)) {
35203520 variable_entry->align_bytes = get_abi_alignment(g, value->type);
35213521
3522 ZigVar *existing_var = find_variable(g, parent_scope, name);
3522 ZigVar *existing_var = find_variable(g, parent_scope, name, nullptr);
35233523 if (existing_var && !existing_var->shadowable) {
35243524 ErrorMsg *msg = add_node_error(g, source_node,
35253525 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
......@@ -3726,12 +3726,16 @@ Tld *find_decl(CodeGen *g, Scope *scope, Buf *name) {
37263726 return nullptr;
37273727}
37283728
3729ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) {
3729ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name, ScopeFnDef **crossed_fndef_scope) {
3730 ScopeFnDef *my_crossed_fndef_scope = nullptr;
37303731 while (scope) {
37313732 if (scope->id == ScopeIdVarDecl) {
37323733 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;
37343737 return var_scope->var;
3738 }
37353739 } else if (scope->id == ScopeIdDecls) {
37363740 ScopeDecls *decls_scope = (ScopeDecls *)scope;
37373741 auto entry = decls_scope->decl_table.maybe_get(name);
......@@ -3739,10 +3743,15 @@ ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name) {
37393743 Tld *tld = entry->value;
37403744 if (tld->id == TldIdVar) {
37413745 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;
37433749 return tld_var->var;
3750 }
37443751 }
37453752 }
3753 } else if (scope->id == ScopeIdFnDef) {
3754 my_crossed_fndef_scope = (ScopeFnDef *)scope;
37463755 }
37473756 scope = scope->parent;
37483757 }
src/analyze.hpp+1-1
......@@ -48,7 +48,7 @@ bool type_has_bits(ZigType *type_entry);
4848ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *abs_full_path, Buf *source_code);
4949
5050
51ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name);
51ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope);
5252Tld *find_decl(CodeGen *g, Scope *scope, Buf *name);
5353void resolve_top_level_decl(CodeGen *g, Tld *tld, bool pointer_only, AstNode *source_node);
5454bool 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
11141114 return new_instruction;
11151115}
11161116
1117static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var) {
1117static IrInstruction *ir_build_var_ptr_x(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var,
1118 ScopeFnDef *crossed_fndef_scope)
1119{
11181120 IrInstructionVarPtr *instruction = ir_build_instruction<IrInstructionVarPtr>(irb, scope, source_node);
11191121 instruction->var = var;
1122 instruction->crossed_fndef_scope = crossed_fndef_scope;
11201123
11211124 ir_ref_var(var);
11221125
11231126 return &instruction->base;
11241127}
11251128
1129static 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
11261133static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr,
11271134 IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len)
11281135{
......@@ -3336,7 +3343,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
33363343 buf_init_from_buf(&variable_entry->name, name);
33373344
33383345 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);
33403347 if (existing_var && !existing_var->shadowable) {
33413348 ErrorMsg *msg = add_node_error(codegen, node,
33423349 buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
......@@ -3799,9 +3806,10 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node,
37993806 }
38003807 }
38013808
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);
38033811 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);
38053813 if (lval == LValPtr)
38063814 return var_ptr;
38073815 else
......@@ -5822,7 +5830,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
58225830 output_types[i] = return_type;
58235831 } else {
58245832 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);
58265836 if (var) {
58275837 output_vars[i] = var;
58285838 } else {
......@@ -14157,17 +14167,26 @@ static ZigType *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPhi *phi
1415714167 return resolved_type;
1415814168}
1415914169
14160static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
14161 ZigVar *var)
14162{
14170static ZigType *ir_analyze_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var) {
1416314171 IrInstruction *result = ir_get_var_ptr(ira, instruction, var);
1416414172 ir_link_new_instruction(result, instruction);
1416514173 return result->value.type;
1416614174}
1416714175
14168static 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);
14176static 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;
1417114190}
1417214191
1417314192static 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" {
176176 assert(pt.addPointCoords() == 3);
177177 }
178178}
179
180fn 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
190test "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 @@
11const tests = @import("tests.zig");
22
33pub 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
424 cases.add(
525 "non int passed to @intToFloat",
626 \\export fn entry() void {