constant initializers allow simple expressions

This commit is contained in:
Andrew Kelley 2015-12-14 23:49:56 -07:00
parent 83b68c9f13
commit 4dc2b82506
4 changed files with 56 additions and 19 deletions

View file

@ -1027,8 +1027,8 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
{ {
AstNode *op1 = node->data.bin_op_expr.op1; AstNode *op1 = node->data.bin_op_expr.op1;
AstNode *op2 = node->data.bin_op_expr.op2; AstNode *op2 = node->data.bin_op_expr.op2;
TypeTableEntry *lhs_type = analyze_expression(g, import, context, nullptr, op1); TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);
TypeTableEntry *rhs_type = analyze_expression(g, import, context, nullptr, op2); TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);
TypeTableEntry *return_type = nullptr; TypeTableEntry *return_type = nullptr;
@ -1191,21 +1191,25 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
{ {
TypeTableEntry *expected_return_type = get_return_type(context); if (context->fn_entry) {
TypeTableEntry *actual_return_type; TypeTableEntry *expected_return_type = get_return_type(context);
if (node->data.return_expr.expr) { TypeTableEntry *actual_return_type;
actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr); 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 { } 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; return_type = g->builtin_types.entry_unreachable;
break; break;
} }

View file

@ -270,6 +270,10 @@ struct NumberLiteralNode {
TypeTableEntry *resolved_type; TypeTableEntry *resolved_type;
}; };
struct VarDeclNode {
TypeTableEntry *type;
};
struct CodeGenNode { struct CodeGenNode {
union { union {
TypeNode type_node; // for NodeTypeType TypeNode type_node; // for NodeTypeType
@ -282,6 +286,7 @@ struct CodeGenNode {
FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr FieldAccessNode field_access_node; // for NodeTypeFieldAccessExpr
CastNode cast_node; // for NodeTypeCastExpr CastNode cast_node; // for NodeTypeCastExpr
NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
} data; } data;
ExprNode expr_node; // for all the expression nodes ExprNode expr_node; // for all the expression nodes
}; };

View file

@ -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) { 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, LLVMZigSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1,
g->cur_block_context->di_scope); 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) { for (int i = 0; i < g->global_vars.length; i += 1) {
VariableTableEntry *var = g->global_vars.at(i); 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 // 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); 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); LLVMSetGlobalConstant(global_value, var->is_const);
LLVMSetUnnamedAddr(global_value, true); LLVMSetUnnamedAddr(global_value, true);

View file

@ -496,6 +496,21 @@ fn test_foo(foo : Foo) {
if foo.b { if foo.b {
print_str("OK\n" as string); 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"); )SOURCE", "OK\n");
} }
@ -682,6 +697,13 @@ fn f() {
add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE( add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
fn f(...) {} fn f(...) {}
)SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions"); )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) { static void print_compiler_invocation(TestCase *test_case) {