Commit f50bfb94b5

Andrew Kelley <andrew@ziglang.org>
2019-09-09 21:54:03
fix bad LLVM IR when for target expr needs to be spilled
Also reduce the size of ZigVar in memory by making the name a `const char *` rather than a `Buf`.
1 parent e4c3067
src/all_types.hpp
@@ -2070,7 +2070,7 @@ struct CodeGen {
 };
 
 struct ZigVar {
-    Buf name;
+    const char *name;
     ConstExprValue *const_value;
     ZigType *var_type;
     LLVMValueRef value_ref;
@@ -2085,7 +2085,6 @@ struct ZigVar {
     LLVMValueRef param_value_ref;
     size_t mem_slot_index;
     IrExecutable *owner_exec;
-    size_t ref_count;
 
     // In an inline loop, multiple variables may be created,
     // In this case, a reference to a variable should follow
@@ -2095,6 +2094,7 @@ struct ZigVar {
     ZigList<GlobalExport> export_list;
 
     uint32_t align_bytes;
+    uint32_t ref_count;
 
     bool shadowable;
     bool src_is_const;
src/analyze.cpp
@@ -3148,26 +3148,26 @@ ZigType *get_test_fn_type(CodeGen *g) {
     return g->test_fn_type;
 }
 
-void add_var_export(CodeGen *g, ZigVar *var, Buf *symbol_name, GlobalLinkageId linkage) {
+void add_var_export(CodeGen *g, ZigVar *var, const char *symbol_name, GlobalLinkageId linkage) {
     GlobalExport *global_export = var->export_list.add_one();
     memset(global_export, 0, sizeof(GlobalExport));
-    buf_init_from_buf(&global_export->name, symbol_name);
+    buf_init_from_str(&global_export->name, symbol_name);
     global_export->linkage = linkage;
 }
 
-void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc) {
+void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, bool ccc) {
     if (ccc) {
-        if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) {
+        if (strcmp(symbol_name, "main") == 0 && g->libc_link_lib != nullptr) {
             g->have_c_main = true;
-        } else if (buf_eql_str(symbol_name, "WinMain") &&
+        } else if (strcmp(symbol_name, "WinMain") == 0 &&
             g->zig_target->os == OsWindows)
         {
             g->have_winmain = true;
-        } else if (buf_eql_str(symbol_name, "WinMainCRTStartup") &&
+        } else if (strcmp(symbol_name, "WinMainCRTStartup") == 0 &&
             g->zig_target->os == OsWindows)
         {
             g->have_winmain_crt_startup = true;
-        } else if (buf_eql_str(symbol_name, "DllMainCRTStartup") &&
+        } else if (strcmp(symbol_name, "DllMainCRTStartup") == 0 &&
             g->zig_target->os == OsWindows)
         {
             g->have_dllmain_crt_startup = true;
@@ -3176,7 +3176,7 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
 
     GlobalExport *fn_export = fn_table_entry->export_list.add_one();
     memset(fn_export, 0, sizeof(GlobalExport));
-    buf_init_from_buf(&fn_export->name, symbol_name);
+    buf_init_from_str(&fn_export->name, symbol_name);
     fn_export->linkage = linkage;
 }
 
@@ -3200,7 +3200,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) {
 
         if (fn_proto->is_export) {
             bool ccc = (fn_proto->cc == CallingConventionUnspecified || fn_proto->cc == CallingConventionC);
-            add_fn_export(g, fn_table_entry, &fn_table_entry->symbol_name, GlobalLinkageIdStrong, ccc);
+            add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), GlobalLinkageIdStrong, ccc);
         }
 
         if (!is_extern) {
@@ -3559,7 +3559,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf
     variable_entry->src_arg_index = SIZE_MAX;
 
     assert(name);
-    buf_init_from_buf(&variable_entry->name, name);
+    variable_entry->name = strdup(buf_ptr(name));
 
     if ((err = type_resolve(g, var_type, ResolveStatusAlignmentKnown))) {
         variable_entry->var_type = g->builtin_types.entry_invalid;
@@ -3707,7 +3707,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) {
     }
 
     if (is_export) {
-        add_var_export(g, tld_var->var, &tld_var->var->name, GlobalLinkageIdStrong);
+        add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong);
     }
 
     g->global_vars.append(tld_var);
@@ -3916,7 +3916,7 @@ ZigVar *find_variable(CodeGen *g, Scope *scope, Buf *name, ScopeFnDef **crossed_
     while (scope) {
         if (scope->id == ScopeIdVarDecl) {
             ScopeVarDecl *var_scope = (ScopeVarDecl *)scope;
-            if (buf_eql_buf(name, &var_scope->var->name)) {
+            if (buf_eql_str(name, var_scope->var->name)) {
                 if (crossed_fndef_scope != nullptr)
                     *crossed_fndef_scope = my_crossed_fndef_scope;
                 return var_scope->var;
src/analyze.hpp
@@ -189,8 +189,8 @@ ZigType *get_align_amt_type(CodeGen *g);
 ZigPackage *new_anonymous_package(void);
 
 Buf *const_value_to_buffer(ConstExprValue *const_val);
-void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage, bool ccc);
-void add_var_export(CodeGen *g, ZigVar *fn_table_entry, Buf *symbol_name, GlobalLinkageId linkage);
+void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, bool ccc);
+void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage);
 
 
 ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
src/buffer.hpp
@@ -57,6 +57,11 @@ static inline void buf_deinit(Buf *buf) {
     buf->list.deinit();
 }
 
+static inline void buf_destroy(Buf *buf) {
+    buf_deinit(buf);
+    free(buf);
+}
+
 static inline void buf_init_from_mem(Buf *buf, const char *ptr, size_t len) {
     assert(len != SIZE_MAX);
     buf->list.resize(len + 1);
src/codegen.cpp
@@ -234,18 +234,23 @@ static void addLLVMArgAttrInt(LLVMValueRef fn_val, unsigned param_index, const c
     return addLLVMAttrInt(fn_val, param_index + 1, attr_name, attr_val);
 }
 
-static bool is_symbol_available(CodeGen *g, Buf *name) {
-    return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
+static bool is_symbol_available(CodeGen *g, const char *name) {
+    Buf *buf_name = buf_create_from_str(name);
+    bool result =
+        g->exported_symbol_names.maybe_get(buf_name) == nullptr &&
+        g->external_prototypes.maybe_get(buf_name) == nullptr;
+    buf_destroy(buf_name);
+    return result;
 }
 
-static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) {
+static const char *get_mangled_name(CodeGen *g, const char *original_name, bool external_linkage) {
     if (external_linkage || is_symbol_available(g, original_name)) {
         return original_name;
     }
 
     int n = 0;
     for (;; n += 1) {
-        Buf *new_name = buf_sprintf("%s.%d", buf_ptr(original_name), n);
+        const char *new_name = buf_ptr(buf_sprintf("%s.%d", original_name, n));
         if (is_symbol_available(g, new_name)) {
             return new_name;
         }
@@ -387,8 +392,8 @@ static bool codegen_have_frame_pointer(CodeGen *g) {
 }
 
 static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
-    Buf *unmangled_name = &fn->symbol_name;
-    Buf *symbol_name;
+    const char *unmangled_name = buf_ptr(&fn->symbol_name);
+    const char *symbol_name;
     GlobalLinkageId linkage;
     if (fn->body_node == nullptr) {
         symbol_name = unmangled_name;
@@ -398,7 +403,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
         linkage = GlobalLinkageIdInternal;
     } else {
         GlobalExport *fn_export = &fn->export_list.items[0];
-        symbol_name = &fn_export->name;
+        symbol_name = buf_ptr(&fn_export->name);
         linkage = fn_export->linkage;
     }
 
@@ -408,7 +413,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
         g->zig_target->arch == ZigLLVM_x86)
     {
         // prevent llvm name mangling
-        symbol_name = buf_sprintf("\x01_%s", buf_ptr(symbol_name));
+        symbol_name = buf_ptr(buf_sprintf("\x01_%s", symbol_name));
     }
 
     bool is_async = fn_is_async(fn);
@@ -420,13 +425,16 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
     LLVMTypeRef fn_llvm_type = fn->raw_type_ref;
     LLVMValueRef llvm_fn = nullptr;
     if (fn->body_node == nullptr) {
-        LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, buf_ptr(symbol_name));
+        LLVMValueRef existing_llvm_fn = LLVMGetNamedFunction(g->module, symbol_name);
         if (existing_llvm_fn) {
             return LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
         } else {
-            auto entry = g->exported_symbol_names.maybe_get(symbol_name);
+            Buf *buf_symbol_name = buf_create_from_str(symbol_name);
+            auto entry = g->exported_symbol_names.maybe_get(buf_symbol_name);
+            buf_destroy(buf_symbol_name);
+
             if (entry == nullptr) {
-                llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+                llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type);
 
                 if (target_is_wasm(g->zig_target)) {
                     assert(fn->proto_node->type == NodeTypeFnProto);
@@ -440,7 +448,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
                 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
                 // Make the raw_type_ref populated
                 resolve_llvm_types_fn(g, tld_fn->fn_entry);
-                tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
+                tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, symbol_name,
                         tld_fn->fn_entry->raw_type_ref);
                 llvm_fn = LLVMConstBitCast(tld_fn->fn_entry->llvm_value, LLVMPointerType(fn_llvm_type, 0));
                 return llvm_fn;
@@ -448,7 +456,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) {
         }
     } else {
         if (llvm_fn == nullptr) {
-            llvm_fn = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
+            llvm_fn = LLVMAddFunction(g->module, symbol_name, fn_llvm_type);
         }
 
         for (size_t i = 1; i < fn->export_list.length; i += 1) {
@@ -1058,8 +1066,8 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
 
-    Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false);
-    LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+    const char *fn_name = get_mangled_name(g, "__zig_add_err_ret_trace_addr", false);
+    LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref);
     addLLVMFnAttr(fn_val, "alwaysinline");
     LLVMSetLinkage(fn_val, LLVMInternalLinkage);
     LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
@@ -1138,8 +1146,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
 
-    Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
-    LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+    const char *fn_name = get_mangled_name(g, "__zig_return_error", false);
+    LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref);
     addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address
     addLLVMFnAttr(fn_val, "cold");
     LLVMSetLinkage(fn_val, LLVMInternalLinkage);
@@ -1208,7 +1216,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
     LLVMSetLinkage(msg_prefix, LLVMInternalLinkage);
     LLVMSetGlobalConstant(msg_prefix, true);
 
-    Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_fail_unwrap"), false);
+    const char *fn_name = get_mangled_name(g, "__zig_fail_unwrap", false);
     LLVMTypeRef fn_type_ref;
     if (g->have_err_ret_tracing) {
         LLVMTypeRef arg_types[] = {
@@ -1222,7 +1230,7 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) {
         };
         fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
     }
-    LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+    LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref);
     addLLVMFnAttr(fn_val, "noreturn");
     addLLVMFnAttr(fn_val, "cold");
     LLVMSetLinkage(fn_val, LLVMInternalLinkage);
@@ -1805,7 +1813,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                 fn_walk->data.types.param_di_types->append(get_llvm_di_type(g, ty));
                 break;
             case FnWalkIdVars: {
-                var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
+                var->value_ref = build_alloca(g, ty, var->name, var->align_bytes);
                 di_arg_index = fn_walk->data.vars.gen_i;
                 fn_walk->data.vars.gen_i += 1;
                 dest_ty = ty;
@@ -1916,7 +1924,7 @@ static bool iter_function_params_c_abi(CodeGen *g, ZigType *fn_type, FnWalk *fn_
                 }
                 case FnWalkIdVars: {
                     di_arg_index = fn_walk->data.vars.gen_i;
-                    var->value_ref = build_alloca(g, ty, buf_ptr(&var->name), var->align_bytes);
+                    var->value_ref = build_alloca(g, ty, var->name, var->align_bytes);
                     fn_walk->data.vars.gen_i += 1;
                     dest_ty = ty;
                     goto var_ok;
@@ -1949,7 +1957,7 @@ var_ok:
     if (dest_ty != nullptr && var->decl_node) {
         // arg index + 1 because the 0 index is return value
         var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
-                buf_ptr(&var->name), fn_walk->data.vars.import->data.structure.root_struct->di_file,
+                var->name, fn_walk->data.vars.import->data.structure.root_struct->di_file,
                 (unsigned)(var->decl_node->line + 1),
                 get_llvm_di_type(g, dest_ty), !g->strip_debug_symbols, 0, di_arg_index + 1);
     }
@@ -2060,8 +2068,8 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
     };
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
 
-    Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
-    LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+    const char *fn_name = get_mangled_name(g, "__zig_merge_error_return_traces", false);
+    LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref);
     LLVMSetLinkage(fn_val, LLVMInternalLinkage);
     LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
     addLLVMFnAttr(fn_val, "nounwind");
@@ -3743,12 +3751,11 @@ static void render_async_spills(CodeGen *g) {
             continue;
         }
 
-        var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index,
-                buf_ptr(&var->name));
+        var->value_ref = LLVMBuildStructGEP(g->builder, g->cur_frame_ptr, async_var_index, var->name);
         async_var_index += 1;
         if (var->decl_node) {
             var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
-                buf_ptr(&var->name), import->data.structure.root_struct->di_file,
+                var->name, import->data.structure.root_struct->di_file,
                 (unsigned)(var->decl_node->line + 1),
                 get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
             gen_var_debug_decl(g, var);
@@ -4653,8 +4660,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) {
     LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMPointerType(get_llvm_type(g, u8_slice_type), 0),
             &tag_int_llvm_type, 1, false);
 
-    Buf *fn_name = get_mangled_name(g, buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name)), false);
-    LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
+    const char *fn_name = get_mangled_name(g,
+            buf_ptr(buf_sprintf("__zig_tag_name_%s", buf_ptr(&enum_type->name))), false);
+    LLVMValueRef fn_val = LLVMAddFunction(g->module, fn_name, fn_type_ref);
     LLVMSetLinkage(fn_val, LLVMInternalLinkage);
     LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
     addLLVMFnAttr(fn_val, "nounwind");
@@ -6919,7 +6927,7 @@ static void generate_error_name_table(CodeGen *g) {
     LLVMValueRef err_name_table_init = LLVMConstArray(get_llvm_type(g, str_type), values, (unsigned)g->errors_by_index.length);
 
     g->err_name_table = LLVMAddGlobal(g->module, LLVMTypeOf(err_name_table_init),
-            buf_ptr(get_mangled_name(g, buf_create_from_str("__zig_err_name_table"), false)));
+            get_mangled_name(g, buf_ptr(buf_create_from_str("__zig_err_name_table")), false));
     LLVMSetInitializer(g->err_name_table, err_name_table_init);
     LLVMSetLinkage(g->err_name_table, LLVMPrivateLinkage);
     LLVMSetGlobalConstant(g->err_name_table, true);
@@ -6960,8 +6968,8 @@ static void gen_global_var(CodeGen *g, ZigVar *var, LLVMValueRef init_val,
     assert(import);
 
     bool is_local_to_unit = true;
-    ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name),
-        buf_ptr(&var->name), import->data.structure.root_struct->di_file,
+    ZigLLVMCreateGlobalVariable(g->dbuilder, get_di_scope(g, var->parent_scope), var->name,
+        var->name, import->data.structure.root_struct->di_file,
         (unsigned)(var->decl_node->line + 1),
         get_llvm_di_type(g, type_entry), is_local_to_unit);
 
@@ -7043,8 +7051,8 @@ static void do_code_gen(CodeGen *g) {
         assert(var->decl_node);
 
         GlobalLinkageId linkage;
-        Buf *unmangled_name = &var->name;
-        Buf *symbol_name;
+        const char *unmangled_name = var->name;
+        const char *symbol_name;
         if (var->export_list.length == 0) {
             if (var->decl_node->data.variable_declaration.is_extern) {
                 symbol_name = unmangled_name;
@@ -7055,19 +7063,19 @@ static void do_code_gen(CodeGen *g) {
             }
         } else {
             GlobalExport *global_export = &var->export_list.items[0];
-            symbol_name = &global_export->name;
+            symbol_name = buf_ptr(&global_export->name);
             linkage = global_export->linkage;
         }
 
         LLVMValueRef global_value;
         bool externally_initialized = var->decl_node->data.variable_declaration.expr == nullptr;
         if (externally_initialized) {
-            LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(symbol_name));
+            LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, symbol_name);
             if (existing_llvm_var) {
                 global_value = LLVMConstBitCast(existing_llvm_var,
                         LLVMPointerType(get_llvm_type(g, var->var_type), 0));
             } else {
-                global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), buf_ptr(symbol_name));
+                global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), symbol_name);
                 // TODO debug info for the extern variable
 
                 LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
@@ -7078,8 +7086,8 @@ static void do_code_gen(CodeGen *g) {
             }
         } else {
             bool exported = (linkage != GlobalLinkageIdInternal);
-            render_const_val(g, var->const_value, buf_ptr(symbol_name));
-            render_const_val_global(g, var->const_value, buf_ptr(symbol_name));
+            render_const_val(g, var->const_value, symbol_name);
+            render_const_val_global(g, var->const_value, symbol_name);
             global_value = var->const_value->global_refs->llvm_global;
 
             if (exported) {
@@ -7234,7 +7242,7 @@ static void do_code_gen(CodeGen *g) {
 
             if (var->src_arg_index == SIZE_MAX) {
                 var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
-                        buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1),
+                        var->name, import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1),
                         get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0);
 
             } else if (is_c_abi) {
@@ -7254,11 +7262,11 @@ static void do_code_gen(CodeGen *g) {
                     var->value_ref = LLVMGetParam(fn, gen_info->gen_index);
                 } else {
                     gen_type = var->var_type;
-                    var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes);
+                    var->value_ref = build_alloca(g, var->var_type, var->name, var->align_bytes);
                 }
                 if (var->decl_node) {
                     var->di_loc_var = ZigLLVMCreateParameterVariable(g->dbuilder, get_di_scope(g, var->parent_scope),
-                        buf_ptr(&var->name), import->data.structure.root_struct->di_file,
+                        var->name, import->data.structure.root_struct->di_file,
                         (unsigned)(var->decl_node->line + 1),
                         get_llvm_di_type(g, gen_type), !g->strip_debug_symbols, 0, (unsigned)(gen_info->gen_index+1));
                 }
src/ir.cpp
@@ -3628,7 +3628,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
     }
 
     if (name) {
-        buf_init_from_buf(&variable_entry->name, name);
+        variable_entry->name = strdup(buf_ptr(name));
 
         if (!skip_name_check) {
             ZigVar *existing_var = find_variable(codegen, parent_scope, name, nullptr);
@@ -3661,7 +3661,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
         // TODO make this name not actually be in scope. user should be able to make a variable called "_anon"
         // might already be solved, let's just make sure it has test coverage
         // maybe we put a prefix on this so the debug info doesn't clobber user debug info for same named variables
-        buf_init_from_str(&variable_entry->name, "_anon");
+        variable_entry->name = "_anon";
     }
 
     variable_entry->src_is_const = src_is_const;
@@ -6467,15 +6467,15 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo
     }
     assert(elem_node->type == NodeTypeSymbol);
 
-    IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr, nullptr);
+    ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, parent_scope);
+
+    IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, &spill_scope->base, LValPtr, nullptr);
     if (array_val_ptr == irb->codegen->invalid_instruction)
         return array_val_ptr;
 
     IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node,
         ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline);
 
-    ScopeExpr *spill_scope = create_expr_scope(irb->codegen, node, parent_scope);
-
     AstNode *index_var_source_node;
     ZigVar *index_var;
     const char *index_var_name;
@@ -14559,7 +14559,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
         // We make a new variable so that it can hold a different type, and so the debug info can
         // be distinct.
         ZigVar *new_var = create_local_var(ira->codegen, var->decl_node, var->child_scope,
-            &var->name, var->src_is_const, var->gen_is_const, var->shadowable, var->is_comptime, true);
+            buf_create_from_str(var->name), var->src_is_const, var->gen_is_const,
+            var->shadowable, var->is_comptime, true);
         new_var->owner_exec = var->owner_exec;
         new_var->align_bytes = var->align_bytes;
         if (var->mem_slot_index != SIZE_MAX) {
@@ -14702,7 +14703,8 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
                 case CallingConventionNaked:
                 case CallingConventionCold:
                 case CallingConventionStdcall:
-                    add_fn_export(ira->codegen, fn_entry, symbol_name, global_linkage_id, cc == CallingConventionC);
+                    add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id,
+                            cc == CallingConventionC);
                     break;
             }
         } break;
@@ -14840,7 +14842,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
         if (load_ptr->ptr->id == IrInstructionIdVarPtr) {
             IrInstructionVarPtr *var_ptr = reinterpret_cast<IrInstructionVarPtr *>(load_ptr->ptr);
             ZigVar *var = var_ptr->var;
-            add_var_export(ira->codegen, var, symbol_name, global_linkage_id);
+            add_var_export(ira->codegen, var, buf_ptr(symbol_name), global_linkage_id);
         }
     }
 
@@ -17023,7 +17025,7 @@ static IrInstruction *ir_analyze_instruction_var_ptr(IrAnalyze *ira, IrInstructi
     IrInstruction *result = ir_get_var_ptr(ira, &instruction->base, var);
     if (instruction->crossed_fndef_scope != nullptr && !instr_is_comptime(result)) {
         ErrorMsg *msg = ir_add_error(ira, &instruction->base,
-            buf_sprintf("'%s' not accessible from inner function", buf_ptr(&var->name)));
+            buf_sprintf("'%s' not accessible from inner function", var->name));
         add_error_note(ira->codegen, msg, instruction->crossed_fndef_scope->base.source_node,
                 buf_sprintf("crossed function definition here"));
         add_error_note(ira->codegen, msg, var->decl_node,
@@ -17735,7 +17737,8 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_
                 return ir_error_dependency_loop(ira, source_instruction);
             }
             if (tld_var->extern_lib_name != nullptr) {
-                add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node);
+                add_link_lib_symbol(ira, tld_var->extern_lib_name, buf_create_from_str(var->name),
+                        source_instruction->source_node);
             }
 
             return ir_get_var_ptr(ira, source_instruction, var);
@@ -20189,8 +20192,9 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr
                     for (size_t fn_arg_index = 0; fn_arg_index < fn_arg_count; fn_arg_index++) {
                         ZigVar *arg_var = fn_entry->variable_list.at(fn_arg_index);
                         ConstExprValue *fn_arg_name_val = &fn_arg_name_array->data.x_array.data.s_none.elements[fn_arg_index];
-                        ConstExprValue *arg_name = create_const_str_lit(ira->codegen, &arg_var->name);
-                        init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, buf_len(&arg_var->name), true);
+                        ConstExprValue *arg_name = create_const_str_lit(ira->codegen,
+                                buf_create_from_str(arg_var->name));
+                        init_const_slice(ira->codegen, fn_arg_name_val, arg_name, 0, strlen(arg_var->name), true);
                         fn_arg_name_val->parent.id = ConstParentIdArray;
                         fn_arg_name_val->parent.data.p_array.array_val = fn_arg_name_array;
                         fn_arg_name_val->parent.data.p_array.elem_index = fn_arg_index;
src/ir_print.cpp
@@ -531,7 +531,7 @@ static void ir_print_bin_op(IrPrint *irp, IrInstructionBinOp *bin_op_instruction
 
 static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_var_instruction) {
     const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
-    const char *name = buf_ptr(&decl_var_instruction->var->name);
+    const char *name = decl_var_instruction->var->name;
     if (decl_var_instruction->var_type) {
         fprintf(irp->f, "%s %s: ", var_or_const, name);
         ir_print_other_instruction(irp, decl_var_instruction->var_type);
@@ -747,7 +747,7 @@ static void ir_print_elem_ptr(IrPrint *irp, IrInstructionElemPtr *instruction) {
 }
 
 static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) {
-    fprintf(irp->f, "&%s", buf_ptr(&instruction->var->name));
+    fprintf(irp->f, "&%s", instruction->var->name);
 }
 
 static void ir_print_return_ptr(IrPrint *irp, IrInstructionReturnPtr *instruction) {
@@ -1852,7 +1852,7 @@ static void ir_print_mul_add(IrPrint *irp, IrInstructionMulAdd *instruction) {
 static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_var_instruction) {
     ZigVar *var = decl_var_instruction->var;
     const char *var_or_const = decl_var_instruction->var->gen_is_const ? "const" : "var";
-    const char *name = buf_ptr(&decl_var_instruction->var->name);
+    const char *name = decl_var_instruction->var->name;
     fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name),
             var->align_bytes);
 
test/stage1/behavior/async_fn.zig
@@ -1201,3 +1201,35 @@ test "correctly spill when returning the error union result of another async fn"
     resume S.global_frame;
 }
 
+
+test "spill target expr in a for loop" {
+    const S = struct {
+        var global_frame: anyframe = undefined;
+
+        fn doTheTest() void {
+            var foo = Foo{
+                .slice = [_]i32{1, 2},
+            };
+            expect(atest(&foo) == 3);
+        }
+
+        const Foo = struct {
+            slice: []i32,
+        };
+
+        fn atest(foo: *Foo) i32 {
+            var sum: i32 = 0;
+            for (foo.slice) |x| {
+                suspend {
+                    global_frame = @frame();
+                }
+                sum += x;
+            }
+            return sum;
+        }
+    };
+    _ = async S.doTheTest();
+    resume S.global_frame;
+    resume S.global_frame;
+}
+