autofree: fix free before return
							parent
							
								
									88097125f7
								
							
						
					
					
						commit
						4e62bc0b81
					
				| 
						 | 
					@ -4539,7 +4539,7 @@ fn (mut g Gen) return_statement(node ast.Return) {
 | 
				
			||||||
			styp := g.typ(g.fn_decl.return_type)
 | 
								styp := g.typ(g.fn_decl.return_type)
 | 
				
			||||||
			g.writeln('return ($styp){0};')
 | 
								g.writeln('return ($styp){0};')
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			if g.is_autofree && !g.is_builtin_mod {
 | 
								if g.is_autofree {
 | 
				
			||||||
				g.writeln('// free before return (no values returned)')
 | 
									g.writeln('// free before return (no values returned)')
 | 
				
			||||||
				g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
 | 
									g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -4680,13 +4680,24 @@ fn (mut g Gen) return_statement(node ast.Return) {
 | 
				
			||||||
			g.writeln('return $opt_tmp;')
 | 
								g.writeln('return $opt_tmp;')
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							// autofree before `return`
 | 
				
			||||||
 | 
							// set free_parent_scopes to true, since all variables defined in parent
 | 
				
			||||||
 | 
							// scopes need to be freed before the return
 | 
				
			||||||
 | 
							if g.is_autofree {
 | 
				
			||||||
 | 
								expr := node.exprs[0]
 | 
				
			||||||
 | 
								if expr is ast.Ident {
 | 
				
			||||||
 | 
									g.returned_var_name = expr.name
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		// free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
 | 
							// free := g.is_autofree && !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
 | 
				
			||||||
 | 
							// Create a temporary variable for the return expression
 | 
				
			||||||
		free := !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
 | 
							free := !g.is_builtin_mod // node.exprs[0] is ast.CallExpr
 | 
				
			||||||
		mut tmp := ''
 | 
							mut tmp := ''
 | 
				
			||||||
		if free {
 | 
							if free {
 | 
				
			||||||
			// `return foo(a, b, c)`
 | 
								// `return foo(a, b, c)`
 | 
				
			||||||
			// `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;`
 | 
								// `tmp := foo(a, b, c); free(a); free(b); free(c); return tmp;`
 | 
				
			||||||
			// Save return value in a temp var so that it all args (a,b,c) can be freed
 | 
								// Save return value in a temp var so that all args (a,b,c) can be freed
 | 
				
			||||||
			// Don't use a tmp var if a variable is simply returned: `return x`
 | 
								// Don't use a tmp var if a variable is simply returned: `return x`
 | 
				
			||||||
			if node.exprs[0] !is ast.Ident {
 | 
								if node.exprs[0] !is ast.Ident {
 | 
				
			||||||
				tmp = g.new_tmp_var()
 | 
									tmp = g.new_tmp_var()
 | 
				
			||||||
| 
						 | 
					@ -4712,18 +4723,8 @@ fn (mut g Gen) return_statement(node ast.Return) {
 | 
				
			||||||
			g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
 | 
								g.expr_with_cast(node.exprs[0], node.types[0], g.fn_decl.return_type)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if free {
 | 
							if free {
 | 
				
			||||||
			expr := node.exprs[0]
 | 
					 | 
				
			||||||
			if expr is ast.Ident {
 | 
					 | 
				
			||||||
				g.returned_var_name = expr.name
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			g.writeln(';')
 | 
								g.writeln(';')
 | 
				
			||||||
			has_semicolon = true
 | 
								has_semicolon = true
 | 
				
			||||||
			// autofree before `return`
 | 
					 | 
				
			||||||
			// set free_parent_scopes to true, since all variables defined in parent
 | 
					 | 
				
			||||||
			// scopes need to be freed before the return
 | 
					 | 
				
			||||||
			if g.pref.autofree {
 | 
					 | 
				
			||||||
				g.autofree_scope_vars(node.pos.pos - 1, node.pos.line_nr, true)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			if tmp != '' {
 | 
								if tmp != '' {
 | 
				
			||||||
				g.write('return $tmp')
 | 
									g.write('return $tmp')
 | 
				
			||||||
				has_semicolon = false
 | 
									has_semicolon = false
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -318,6 +318,11 @@ fn get_user() User {
 | 
				
			||||||
	return user
 | 
						return user
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn get_user2() User {
 | 
				
			||||||
 | 
						users := [User{'Peter', 25}, User{'Alice', 21}]
 | 
				
			||||||
 | 
						return users[0] // has to be cloned, since `users` are going to be freed at the end of the function
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn string_array_get() {
 | 
					fn string_array_get() {
 | 
				
			||||||
	s := ['a', 'b', 'c']
 | 
						s := ['a', 'b', 'c']
 | 
				
			||||||
	x := s[0]
 | 
						x := s[0]
 | 
				
			||||||
| 
						 | 
					@ -361,7 +366,7 @@ fn main() {
 | 
				
			||||||
	free_before_break()
 | 
						free_before_break()
 | 
				
			||||||
	// free_map()
 | 
						// free_map()
 | 
				
			||||||
	// loop_map()
 | 
						// loop_map()
 | 
				
			||||||
	// free_array_except_returned_element()
 | 
						free_array_except_returned_element()
 | 
				
			||||||
	println('end')
 | 
						println('end')
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue