diff --git a/src/analyze.cpp b/src/analyze.cpp index 01325ae816..018757b95c 100644 --- a/src/analyze.cpp +++ b/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); + 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; + } + + check_type_compatibility(g, node, expected_return_type, actual_return_type); } else { - actual_return_type = g->builtin_types.entry_void; + add_node_error(g, node, buf_sprintf("return expression outside function definition")); } - - 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); return_type = g->builtin_types.entry_unreachable; break; } diff --git a/src/analyze.hpp b/src/analyze.hpp index 8a262a2c0a..024d96614b 100644 --- a/src/analyze.hpp +++ b/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 }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 6b1b3428ee..1d0e669411 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -103,6 +103,8 @@ static int count_non_void_params(CodeGen *g, ZigList *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); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 91d00d3373..9696e0395f 100644 --- a/test/run_tests.cpp +++ b/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) {