From 26ea20d88fb1b201546e29058ac4aa5d4760a577 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 Feb 2016 15:11:20 -0700 Subject: [PATCH] implement @const_eval closes #73 --- src/all_types.hpp | 1 + src/analyze.cpp | 20 +++++++++++++++++++- src/codegen.cpp | 2 ++ test/run_tests.cpp | 7 +++++++ test/self_hosted.zig | 7 +++++++ 5 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 7378e4d6e4..e7e925f42f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1033,6 +1033,7 @@ enum BuiltinFnId { BuiltinFnIdCDefine, BuiltinFnIdCUndef, BuiltinFnIdCompileVar, + BuiltinFnIdConstEval, }; struct BuiltinFnEntry { diff --git a/src/analyze.cpp b/src/analyze.cpp index d6485d0312..2b8119ed48 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4127,8 +4127,26 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name))); return g->builtin_types.entry_invalid; } + } + case BuiltinFnIdConstEval: + { + AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field; + TypeTableEntry *resolved_type = analyze_expression(g, import, context, expected_type, *expr_node); + if (resolved_type->id == TypeTableEntryIdInvalid) { + return resolved_type; + } - break; + ConstExprValue *const_expr_val = &get_resolved_expr(*expr_node)->const_val; + + if (!const_expr_val->ok) { + add_node_error(g, *expr_node, buf_sprintf("unable to evaluate constant expression")); + return resolved_type; + } + + ConstExprValue *const_val = &get_resolved_expr(node)->const_val; + *const_val = *const_expr_val; + + return resolved_type; } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 6ef2a92158..43e78ce194 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -310,6 +310,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { case BuiltinFnIdMaxValue: case BuiltinFnIdMemberCount: case BuiltinFnIdCompileVar: + case BuiltinFnIdConstEval: // caught by constant expression eval codegen zig_unreachable(); } @@ -3513,6 +3514,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn_with_arg_count(g, BuiltinFnIdCDefine, "c_define", 2); create_builtin_fn_with_arg_count(g, BuiltinFnIdCUndef, "c_undef", 1); create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileVar, "compile_var", 1); + create_builtin_fn_with_arg_count(g, BuiltinFnIdConstEval, "const_eval", 1); } diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 4d9de75bfa..318ba36f94 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -2020,6 +2020,13 @@ fn func() -> bogus {} add_compile_fail_case("bogus compile var", R"SOURCE( const x = @compile_var("bogus"); )SOURCE", 1, ".tmp_source.zig:2:24: error: unrecognized compile variable: 'bogus'"); + + + add_compile_fail_case("@const_eval", R"SOURCE( +fn a(x: i32) { + const y = @const_eval(x); +} + )SOURCE", 1, ".tmp_source.zig:3:27: error: unable to evaluate constant expression"); } ////////////////////////////////////////////////////////////////////////////// diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 86beb173b0..2ea44adaaa 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -233,3 +233,10 @@ fn const_expr_eval_on_single_expr_blocks_fn(x: i32, b: bool) -> i32 { return result; } + + +#attribute("test") +fn builtin_const_eval() { + const x : i32 = @const_eval(1 + 2 + 3); + if (x != @const_eval(6)) unreachable{}; +}