Commit 55c9ae1193

Andrew Kelley <superjoe30@gmail.com>
2016-01-31 09:51:33
codegen extern global variables correctly
1 parent 3c2093f
Changed files (2)
src/codegen.cpp
@@ -2533,26 +2533,34 @@ static void do_code_gen(CodeGen *g) {
             continue;
         }
 
-        // TODO if the global is exported, set external linkage
-        LLVMValueRef init_val;
-
         assert(var->decl_node);
         assert(var->decl_node->type == NodeTypeVariableDeclaration);
-        AstNode *expr_node = var->decl_node->data.variable_declaration.expr;
-        if (expr_node) {
-            Expr *expr = get_resolved_expr(expr_node);
-            ConstExprValue *const_val = &expr->const_val;
-            assert(const_val->ok);
-            TypeTableEntry *type_entry = expr->type_entry;
-            init_val = gen_const_val(g, type_entry, const_val);
+
+        LLVMValueRef global_value;
+        if (var->decl_node->data.variable_declaration.is_extern) {
+            global_value = LLVMAddGlobal(g->module, var->type->type_ref, buf_ptr(&var->name));
+
+            LLVMSetLinkage(global_value, LLVMExternalLinkage);
         } else {
-            init_val = LLVMConstNull(var->type->type_ref);
+            AstNode *expr_node = var->decl_node->data.variable_declaration.expr;
+            LLVMValueRef init_val;
+            if (expr_node) {
+                Expr *expr = get_resolved_expr(expr_node);
+                ConstExprValue *const_val = &expr->const_val;
+                assert(const_val->ok);
+                TypeTableEntry *type_entry = expr->type_entry;
+                init_val = gen_const_val(g, type_entry, const_val);
+            } else {
+                init_val = LLVMConstNull(var->type->type_ref);
+            }
+
+            global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), buf_ptr(&var->name));
+            LLVMSetInitializer(global_value, init_val);
+            LLVMSetLinkage(global_value, LLVMInternalLinkage);
+            LLVMSetUnnamedAddr(global_value, true);
         }
-        LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), buf_ptr(&var->name));
-        LLVMSetInitializer(global_value, init_val);
+
         LLVMSetGlobalConstant(global_value, var->is_const);
-        LLVMSetUnnamedAddr(global_value, true);
-        LLVMSetLinkage(global_value, LLVMInternalLinkage);
 
         var->value_ref = global_value;
     }
src/parser.cpp
@@ -2256,7 +2256,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
 }
 
 /*
-ExternDecl : "extern" FnProto ";"
+ExternDecl = "extern" (FnProto | VariableDeclaration) ";"
 */
 static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool mandatory,
         ZigList<AstNode *> *directives, VisibMod visib_mod)
@@ -2271,13 +2271,28 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool m
     }
     *token_index += 1;
 
-    AstNode *node = ast_parse_fn_proto(pc, token_index, true, directives, visib_mod);
+    AstNode *fn_proto_node = ast_parse_fn_proto(pc, token_index, false, directives, visib_mod);
+    if (fn_proto_node) {
+        ast_eat_token(pc, token_index, TokenIdSemicolon);
 
-    ast_eat_token(pc, token_index, TokenIdSemicolon);
+        fn_proto_node->data.fn_proto.is_extern = true;
 
-    node->data.fn_proto.is_extern = true;
-    normalize_parent_ptrs(node);
-    return node;
+        normalize_parent_ptrs(fn_proto_node);
+        return fn_proto_node;
+    }
+
+    AstNode *var_decl_node = ast_parse_variable_declaration_expr(pc, token_index, false, directives, visib_mod);
+    if (var_decl_node) {
+        ast_eat_token(pc, token_index, TokenIdSemicolon);
+
+        var_decl_node->data.variable_declaration.is_extern = true;
+
+        normalize_parent_ptrs(var_decl_node);
+        return var_decl_node;
+    }
+
+    Token *token = &pc->tokens->at(*token_index);
+    ast_invalid_token_error(pc, token);
 }
 
 /*