| author | |
| committer | |
| log | 4dc2b8250638efda3a9990182f46ad57c403b28b |
| tree | 25ced26eb3a257753ac0b877326eea82697960d1 |
| parent | 83b68c9f13c90dfbbd2735cde4ef570ac50476c0 |
4 files changed, 56 insertions(+), 19 deletions(-)
src/analyze.cpp+19-15| ... | ... | @@ -1027,8 +1027,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import, |
| 1027 | 1027 | { |
| 1028 | 1028 | AstNode *op1 = node->data.bin_op_expr.op1; |
| 1029 | 1029 | AstNode *op2 = node->data.bin_op_expr.op2; |
| 1030 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); | |
| 1031 | TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2); | |
| 1030 | TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1); | |
| 1031 | TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2); | |
| 1032 | 1032 | |
| 1033 | 1033 | TypeTableEntry *return_type = nullptr; |
| 1034 | 1034 | |
| ... | ... | @@ -1191,21 +1191,25 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 1191 | 1191 | |
| 1192 | 1192 | case NodeTypeReturnExpr: |
| 1193 | 1193 | { |
| 1194 | TypeTableEntry *expected_return_type = get_return_type(context); | |
| 1195 | TypeTableEntry *actual_return_type; | |
| 1196 | if (node->data.return_expr.expr) { | |
| 1197 | actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr); | |
| 1198 | } else { | |
| 1199 | actual_return_type = g->builtin_types.entry_void; | |
| 1200 | } | |
| 1194 | if (context->fn_entry) { | |
| 1195 | TypeTableEntry *expected_return_type = get_return_type(context); | |
| 1196 | TypeTableEntry *actual_return_type; | |
| 1197 | if (node->data.return_expr.expr) { | |
| 1198 | actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr); | |
| 1199 | } else { | |
| 1200 | actual_return_type = g->builtin_types.entry_void; | |
| 1201 | } | |
| 1201 | 1202 | |
| 1202 | if (actual_return_type->id == TypeTableEntryIdUnreachable) { | |
| 1203 | // "return exit(0)" should just be "exit(0)". | |
| 1204 | add_node_error(g, node, buf_sprintf("returning is unreachable")); | |
| 1205 | actual_return_type = g->builtin_types.entry_invalid; | |
| 1206 | } | |
| 1203 | if (actual_return_type->id == TypeTableEntryIdUnreachable) { | |
| 1204 | // "return exit(0)" should just be "exit(0)". | |
| 1205 | add_node_error(g, node, buf_sprintf("returning is unreachable")); | |
| 1206 | actual_return_type = g->builtin_types.entry_invalid; | |
| 1207 | } | |
| 1207 | 1208 | |
| 1208 | check_type_compatibility(g, node, expected_return_type, actual_return_type); | |
| 1209 | check_type_compatibility(g, node, expected_return_type, actual_return_type); | |
| 1210 | } else { | |
| 1211 | add_node_error(g, node, buf_sprintf("return expression outside function definition")); | |
| 1212 | } | |
| 1209 | 1213 | return_type = g->builtin_types.entry_unreachable; |
| 1210 | 1214 | break; |
| 1211 | 1215 | } |
src/analyze.hpp+5| ... | ... | @@ -270,6 +270,10 @@ struct NumberLiteralNode { |
| 270 | 270 | TypeTableEntry *resolved_type; |
| 271 | 271 | }; |
| 272 | 272 | |
| 273 | struct VarDeclNode { | |
| 274 | TypeTableEntry *type; | |
| 275 | }; | |
| 276 | ||
| 273 | 277 | struct CodeGenNode { |
| 274 | 278 | union { |
| 275 | 279 | TypeNode type_node; // for NodeTypeType |
| ... | ... | @@ -282,6 +286,7 @@ struct CodeGenNode { |
| 282 | 286 | FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr |
| 283 | 287 | CastNode cast_node; // for NodeTypeCastExpr |
| 284 | 288 | NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral |
| 289 | VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration | |
| 285 | 290 | } data; |
| 286 | 291 | ExprNode expr_node; // for all the expression nodes |
| 287 | 292 | }; |
src/codegen.cpp+10-4| ... | ... | @@ -103,6 +103,8 @@ static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) { |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | 105 | static void add_debug_source_node(CodeGen *g, AstNode *node) { |
| 106 | if (!g->cur_block_context) | |
| 107 | return; | |
| 106 | 108 | LLVMZigSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, |
| 107 | 109 | g->cur_block_context->di_scope); |
| 108 | 110 | } |
| ... | ... | @@ -1040,12 +1042,16 @@ static void do_code_gen(CodeGen *g) { |
| 1040 | 1042 | for (int i = 0; i < g->global_vars.length; i += 1) { |
| 1041 | 1043 | VariableTableEntry *var = g->global_vars.at(i); |
| 1042 | 1044 | |
| 1043 | LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr); | |
| 1044 | ||
| 1045 | 1045 | // TODO if the global is exported, set external linkage |
| 1046 | LLVMValueRef global_value = LLVMAddGlobal(g->module, LLVMTypeOf(init_val), ""); | |
| 1046 | LLVMValueRef global_value = LLVMAddGlobal(g->module, var->type->type_ref, ""); | |
| 1047 | 1047 | LLVMSetLinkage(global_value, LLVMPrivateLinkage); |
| 1048 | LLVMSetInitializer(global_value, init_val); | |
| 1048 | ||
| 1049 | if (var->is_const) { | |
| 1050 | LLVMValueRef init_val = gen_expr(g, var->decl_node->data.variable_declaration.expr); | |
| 1051 | LLVMSetInitializer(global_value, init_val); | |
| 1052 | } else { | |
| 1053 | LLVMSetInitializer(global_value, LLVMConstNull(var->type->type_ref)); | |
| 1054 | } | |
| 1049 | 1055 | LLVMSetGlobalConstant(global_value, var->is_const); |
| 1050 | 1056 | LLVMSetUnnamedAddr(global_value, true); |
| 1051 | 1057 |
test/run_tests.cpp+22| ... | ... | @@ -496,6 +496,21 @@ fn test_foo(foo : Foo) { |
| 496 | 496 | if foo.b { |
| 497 | 497 | print_str("OK\n" as string); |
| 498 | 498 | } |
| 499 | } | |
| 500 | )SOURCE", "OK\n"); | |
| 501 | ||
| 502 | add_simple_case("global variables", R"SOURCE( | |
| 503 | use "std.zig"; | |
| 504 | ||
| 505 | const g1 : i32 = 1233 + 1; | |
| 506 | var g2 : i32; | |
| 507 | ||
| 508 | export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { | |
| 509 | if g2 != 0 { print_str("BAD\n" as string); } | |
| 510 | g2 = g1; | |
| 511 | if g2 != 1234 { print_str("BAD\n" as string); } | |
| 512 | print_str("OK\n" as string); | |
| 513 | return 0; | |
| 499 | 514 | } |
| 500 | 515 | )SOURCE", "OK\n"); |
| 501 | 516 | } |
| ... | ... | @@ -682,6 +697,13 @@ fn f() { |
| 682 | 697 | add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( |
| 683 | 698 | fn f(...) {} |
| 684 | 699 | )SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions"); |
| 700 | ||
| 701 | add_compile_fail_case("write to const global variable", R"SOURCE( | |
| 702 | const x : i32 = 99; | |
| 703 | fn f() { | |
| 704 | x = 1; | |
| 705 | } | |
| 706 | )SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant variable"); | |
| 685 | 707 | } |
| 686 | 708 | |
| 687 | 709 | static void print_compiler_invocation(TestCase *test_case) { |