Commit 4dc2b82506

Andrew Kelley <superjoe30@gmail.com>
2015-12-15 07:49:56
constant initializers allow simple expressions
1 parent 83b68c9
src/analyze.cpp
@@ -1027,8 +1027,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
             {
                 AstNode *op1 = node->data.bin_op_expr.op1;
                 AstNode *op2 = node->data.bin_op_expr.op2;
-                TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1);
-                TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2);
+                TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);
+                TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);
 
                 TypeTableEntry *return_type = nullptr;
 
@@ -1191,21 +1191,25 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
 
         case NodeTypeReturnExpr:
             {
-                TypeTableEntry *expected_return_type = get_return_type(context);
-                TypeTableEntry *actual_return_type;
-                if (node->data.return_expr.expr) {
-                    actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
-                } else {
-                    actual_return_type = g->builtin_types.entry_void;
-                }
+                if (context->fn_entry) {
+                    TypeTableEntry *expected_return_type = get_return_type(context);
+                    TypeTableEntry *actual_return_type;
+                    if (node->data.return_expr.expr) {
+                        actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
+                    } else {
+                        actual_return_type = g->builtin_types.entry_void;
+                    }
 
-                if (actual_return_type->id == TypeTableEntryIdUnreachable) {
-                    // "return exit(0)" should just be "exit(0)".
-                    add_node_error(g, node, buf_sprintf("returning is unreachable"));
-                    actual_return_type = g->builtin_types.entry_invalid;
-                }
+                    if (actual_return_type->id == TypeTableEntryIdUnreachable) {
+                        // "return exit(0)" should just be "exit(0)".
+                        add_node_error(g, node, buf_sprintf("returning is unreachable"));
+                        actual_return_type = g->builtin_types.entry_invalid;
+                    }
 
-                check_type_compatibility(g, node, expected_return_type, actual_return_type);
+                    check_type_compatibility(g, node, expected_return_type, actual_return_type);
+                } else {
+                    add_node_error(g, node, buf_sprintf("return expression outside function definition"));
+                }
                 return_type = g->builtin_types.entry_unreachable;
                 break;
             }
src/analyze.hpp
@@ -270,6 +270,10 @@ struct NumberLiteralNode {
     TypeTableEntry *resolved_type;
 };
 
+struct VarDeclNode {
+    TypeTableEntry *type;
+};
+
 struct CodeGenNode {
     union {
         TypeNode type_node; // for NodeTypeType
@@ -282,6 +286,7 @@ struct CodeGenNode {
         FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
         CastNode cast_node; // for NodeTypeCastExpr
         NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
+        VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
     } data;
     ExprNode expr_node; // for all the expression nodes
 };
src/codegen.cpp
@@ -103,6 +103,8 @@ static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
 }
 
 static void add_debug_source_node(CodeGen *g, AstNode *node) {
+    if (!g->cur_block_context)
+        return;
     LLVMZigSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1,
             g->cur_block_context->di_scope);
 }
@@ -1040,12 +1042,16 @@ static void do_code_gen(CodeGen *g) {
     for (int i = 0; i < g->global_vars.length; i += 1) {
         VariableTableEntry *var = g->global_vars.at(i);
 
-        LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr);
-
         // TODO if the global is exported, set external linkage
-        LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), "");
+        LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, "");
         LLVMSetLinkage(global_value, LLVMPrivateLinkage);
-        LLVMSetInitializer(global_value, init_val);
+
+        if (var->is_const) {
+            LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr);
+            LLVMSetInitializer(global_value, init_val);
+        } else {
+            LLVMSetInitializer(global_value, LLVMConstNull(var->type->type_ref));
+        }
         LLVMSetGlobalConstant(global_value, var->is_const);
         LLVMSetUnnamedAddr(global_value, true);
 
test/run_tests.cpp
@@ -496,6 +496,21 @@ fn test_foo(foo : Foo) {
     if foo.b {
         print_str("OK\n" as string);
     }
+}
+    )SOURCE", "OK\n");
+
+    add_simple_case("global variables", R"SOURCE(
+use "std.zig";
+
+const g1 : i32 = 1233 + 1;
+var g2 : i32;
+
+export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+    if g2 != 0 { print_str("BAD\n" as string); }
+    g2 = g1;
+    if g2 != 1234 { print_str("BAD\n" as string); }
+    print_str("OK\n" as string);
+    return 0;
 }
     )SOURCE", "OK\n");
 }
@@ -682,6 +697,13 @@ fn f() {
     add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
 fn f(...) {}
     )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions");
+
+    add_compile_fail_case("write to const global variable", R"SOURCE(
+const x : i32 = 99;
+fn f() {
+    x = 1;
+}
+    )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant variable");
 }
 
 static void print_compiler_invocation(TestCase *test_case) {