Commit f8f054b354

Andrew Kelley <andrew@ziglang.org>
2019-06-14 23:23:24
fix `@export` for arrays not respecting the symbol name
Previously, the symbol name parameter of `@export` would be ignored for variables, and the variable name would be used for the symbol name. Now it works as expected. See #2679
1 parent 42ea2d0
doc/langref.html.in
@@ -6648,7 +6648,7 @@ test "main" {
       {#header_close#}
 
       {#header_open|@export#}
-      <pre>{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}</pre>
+      <pre>{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) void{#endsyntax#}</pre>
       <p>
       Creates a symbol in the output object file.
       </p>
src/all_types.hpp
@@ -1334,7 +1334,7 @@ enum FnInline {
     FnInlineNever,
 };
 
-struct FnExport {
+struct GlobalExport {
     Buf name;
     GlobalLinkageId linkage;
 };
@@ -1372,7 +1372,7 @@ struct ZigFn {
 
     AstNode *set_cold_node;
 
-    ZigList<FnExport> export_list;
+    ZigList<GlobalExport> export_list;
 
     LLVMValueRef valgrind_client_request_array;
 
@@ -1896,14 +1896,6 @@ struct CodeGen {
     size_t clang_argv_len;
 };
 
-enum VarLinkage {
-    VarLinkageInternal,
-    VarLinkageExportStrong,
-    VarLinkageExportWeak,
-    VarLinkageExportLinkOnce,
-    VarLinkageExternal,
-};
-
 struct ZigVar {
     Buf name;
     ConstExprValue *const_value;
@@ -1926,8 +1918,9 @@ struct ZigVar {
     // this pointer to the redefined variable.
     ZigVar *next_var;
 
+    ZigList<GlobalExport> export_list;
+
     uint32_t align_bytes;
-    VarLinkage linkage;
 
     bool shadowable;
     bool src_is_const;
src/analyze.cpp
@@ -2712,6 +2712,13 @@ 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) {
+    GlobalExport *global_export = var->export_list.add_one();
+    memset(global_export, 0, sizeof(GlobalExport));
+    buf_init_from_buf(&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) {
     if (ccc) {
         if (buf_eql_str(symbol_name, "main") && g->libc_link_lib != nullptr) {
@@ -2731,8 +2738,8 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, Buf *symbol_name, GlobalLi
         }
     }
 
-    FnExport *fn_export = fn_table_entry->export_list.add_one();
-    memset(fn_export, 0, sizeof(FnExport));
+    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);
     fn_export->linkage = linkage;
 }
@@ -3189,15 +3196,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
 
     assert(!is_export || !is_extern);
 
-    VarLinkage linkage;
-    if (is_export) {
-        linkage = VarLinkageExportStrong;
-    } else if (is_extern) {
-        linkage = VarLinkageExternal;
-    } else {
-        linkage = VarLinkageInternal;
-    }
-
     ConstExprValue *init_value = nullptr;
 
     // TODO more validation for types that can't be used for export/extern variables
@@ -3212,7 +3210,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
         if (implicit_type->id == ZigTypeIdUnreachable) {
             add_node_error(g, source_node, buf_sprintf("variable initialization is unreachable"));
             implicit_type = g->builtin_types.entry_invalid;
-        } else if ((!is_const || linkage == VarLinkageExternal) &&
+        } else if ((!is_const || is_extern) &&
                 (implicit_type->id == ZigTypeIdComptimeFloat ||
                 implicit_type->id == ZigTypeIdComptimeInt ||
                 implicit_type->id == ZigTypeIdEnumLiteral))
@@ -3227,7 +3225,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
             implicit_type = g->builtin_types.entry_invalid;
         }
         assert(implicit_type->id == ZigTypeIdInvalid || init_value->special != ConstValSpecialRuntime);
-    } else if (linkage != VarLinkageExternal) {
+    } else if (!is_extern) {
         add_node_error(g, source_node, buf_sprintf("variables must be initialized"));
         implicit_type = g->builtin_types.entry_invalid;
     }
@@ -3239,7 +3237,6 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
 
     tld_var->var = add_variable(g, source_node, tld_var->base.parent_scope, var_decl->symbol,
             is_const, init_val, &tld_var->base, type);
-    tld_var->var->linkage = linkage;
     tld_var->var->is_thread_local = is_thread_local;
 
     if (implicit_type != nullptr && type_is_invalid(implicit_type)) {
@@ -3262,6 +3259,10 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) {
         add_node_error(g, source_node, buf_sprintf("threadlocal variable cannot be constant"));
     }
 
+    if (is_export) {
+        add_var_export(g, tld_var->var, &tld_var->var->name, GlobalLinkageIdStrong);
+    }
+
     g->global_vars.append(tld_var);
 }
 
src/analyze.hpp
@@ -198,6 +198,7 @@ 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);
 
 
 ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name);
src/codegen.cpp
@@ -475,7 +475,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
         symbol_name = get_mangled_name(g, unmangled_name, false);
         linkage = GlobalLinkageIdInternal;
     } else {
-        FnExport *fn_export = &fn_table_entry->export_list.items[0];
+        GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
         symbol_name = &fn_export->name;
         linkage = fn_export->linkage;
     }
@@ -529,7 +529,7 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
         }
 
         for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {
-            FnExport *fn_export = &fn_table_entry->export_list.items[i];
+            GlobalExport *fn_export = &fn_table_entry->export_list.items[i];
             LLVMAddAlias(g->module, LLVMTypeOf(fn_table_entry->llvm_value),
                     fn_table_entry->llvm_value, buf_ptr(&fn_export->name));
         }
@@ -6691,27 +6691,14 @@ static void validate_inline_fns(CodeGen *g) {
 }
 
 static void set_global_tls(CodeGen *g, ZigVar *var, LLVMValueRef global_value) {
-    if (var->is_thread_local && (!g->is_single_threaded || var->linkage != VarLinkageInternal)) {
+    bool is_extern = var->decl_node->data.variable_declaration.is_extern;
+    bool is_export = var->decl_node->data.variable_declaration.is_export;
+    bool is_internal_linkage = !is_extern && !is_export;
+    if (var->is_thread_local && (!g->is_single_threaded || !is_internal_linkage)) {
         LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel);
     }
 }
 
-static LLVMLinkage var_linkage_to_llvm(VarLinkage var_linkage) {
-    switch (var_linkage) {
-        case VarLinkageInternal:
-            return LLVMInternalLinkage;
-        case VarLinkageExportStrong:
-            return LLVMExternalLinkage;
-        case VarLinkageExportWeak:
-            return LLVMWeakODRLinkage;
-        case VarLinkageExportLinkOnce:
-            return LLVMLinkOnceODRLinkage;
-        case VarLinkageExternal:
-            return LLVMExternalLinkage;
-    }
-    zig_unreachable();
-}
-
 static void do_code_gen(CodeGen *g) {
     assert(!g->errors.length);
 
@@ -6761,31 +6748,48 @@ static void do_code_gen(CodeGen *g) {
 
         assert(var->decl_node);
 
+        GlobalLinkageId linkage;
+        Buf *unmangled_name = &var->name;
+        Buf *symbol_name;
+        if (var->export_list.length == 0) {
+            if (var->decl_node->data.variable_declaration.is_extern) {
+                symbol_name = unmangled_name;
+                linkage = GlobalLinkageIdStrong;
+            } else {
+                symbol_name = get_mangled_name(g, unmangled_name, false);
+                linkage = GlobalLinkageIdInternal;
+            }
+        } else {
+            GlobalExport *global_export = &var->export_list.items[0];
+            symbol_name = &global_export->name;
+            linkage = global_export->linkage;
+        }
+
         LLVMValueRef global_value;
-        if (var->linkage == VarLinkageExternal) {
-            LLVMValueRef existing_llvm_var = LLVMGetNamedGlobal(g->module, buf_ptr(&var->name));
+        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));
             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(&var->name));
+                global_value = LLVMAddGlobal(g->module, get_llvm_type(g, var->var_type), buf_ptr(symbol_name));
                 // TODO debug info for the extern variable
 
-                LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
+                LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
                 maybe_import_dll(g, global_value, GlobalLinkageIdStrong);
                 LLVMSetAlignment(global_value, var->align_bytes);
                 LLVMSetGlobalConstant(global_value, var->gen_is_const);
                 set_global_tls(g, var, global_value);
             }
         } else {
-            bool exported = (var->linkage != VarLinkageInternal);
-            const char *mangled_name = buf_ptr(get_mangled_name(g, &var->name, exported));
-            render_const_val(g, var->const_value, mangled_name);
-            render_const_val_global(g, var->const_value, mangled_name);
+            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));
             global_value = var->const_value->global_refs->llvm_global;
 
             if (exported) {
-                LLVMSetLinkage(global_value, var_linkage_to_llvm(var->linkage));
+                LLVMSetLinkage(global_value, to_llvm_linkage(linkage));
                 maybe_export_dll(g, global_value, GlobalLinkageIdStrong);
             }
             if (tld_var->section_name) {
@@ -6805,6 +6809,11 @@ static void do_code_gen(CodeGen *g) {
         }
 
         var->value_ref = global_value;
+
+        for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) {
+            GlobalExport *global_export = &var->export_list.items[export_i];
+            LLVMAddAlias(g->module, LLVMTypeOf(var->value_ref), var->value_ref, buf_ptr(&global_export->name));
+        }
     }
 
     // Generate function definitions.
@@ -9168,7 +9177,7 @@ static void gen_h_file(CodeGen *g) {
         if (fn_table_entry->export_list.length == 0) {
             symbol_name = &fn_table_entry->symbol_name;
         } else {
-            FnExport *fn_export = &fn_table_entry->export_list.items[0];
+            GlobalExport *fn_export = &fn_table_entry->export_list.items[0];
             symbol_name = &fn_export->name;
         }
 
src/ir.cpp
@@ -13791,20 +13791,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira,
     return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value);
 }
 
-static VarLinkage global_linkage_to_var_linkage(GlobalLinkageId id) {
-    switch (id) {
-        case GlobalLinkageIdStrong:
-            return VarLinkageExportStrong;
-        case GlobalLinkageIdWeak:
-            return VarLinkageExportWeak;
-        case GlobalLinkageIdLinkOnce:
-            return VarLinkageExportLinkOnce;
-        case GlobalLinkageIdInternal:
-            return VarLinkageInternal;
-    }
-    zig_unreachable();
-}
-
 static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) {
     IrInstruction *name = instruction->name->child;
     Buf *symbol_name = ir_resolve_str(ira, name);
@@ -14002,7 +13988,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;
-            var->linkage = global_linkage_to_var_linkage(global_linkage_id);
+            add_var_export(ira->codegen, var, symbol_name, global_linkage_id);
         }
     }
 
@@ -14295,7 +14281,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction,
     ConstExprValue *mem_slot = nullptr;
 
     bool comptime_var_mem = ir_get_var_is_comptime(var);
-    bool linkage_makes_it_runtime = var->linkage == VarLinkageExternal;
+    bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern;
     bool is_const = var->src_is_const;
     bool is_volatile = false;