diff --git a/src/all_types.hpp b/src/all_types.hpp index f15756ebf..ebeaa2ac7 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -998,6 +998,7 @@ enum BuiltinFnId { BuiltinFnIdCInclude, BuiltinFnIdCDefine, BuiltinFnIdCUndef, + BuiltinFnIdCompileVar, }; struct BuiltinFnEntry { @@ -1058,6 +1059,7 @@ struct CodeGen { LLVMTargetDataRef target_data_ref; unsigned pointer_size_bytes; + bool is_big_endian; bool is_static; bool strip_debug_symbols; bool have_exported_main; diff --git a/src/analyze.cpp b/src/analyze.cpp index 480f0c7b3..e51d72389 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -3896,7 +3896,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry uint64_t big_c = char_val->data.x_bignum.data.x_uint; assert(big_c <= UINT8_MAX); uint8_t c = big_c; - buf_appendf(context->c_import_buf, "%c", c); + buf_append_char(context->c_import_buf, c); } buf_appendf(context->c_import_buf, ">\n"); @@ -3907,6 +3907,50 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry case BuiltinFnIdCUndef: zig_panic("TODO"); + case BuiltinFnIdCompileVar: + { + AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field; + + TypeTableEntry *str_type = get_unknown_size_array_type(g, g->builtin_types.entry_u8, true); + TypeTableEntry *resolved_type = analyze_expression(g, import, context, str_type, *str_node); + + if (resolved_type->id == TypeTableEntryIdInvalid) { + return resolved_type; + } + + ConstExprValue *const_str_val = &get_resolved_expr(*str_node)->const_val; + + if (!const_str_val->ok) { + add_node_error(g, *str_node, buf_sprintf("@compile_var requires constant expression")); + return g->builtin_types.entry_void; + } + + ConstExprValue *ptr_field = const_str_val->data.x_struct.fields[0]; + uint64_t len = ptr_field->data.x_ptr.len; + Buf var_name = BUF_INIT; + buf_resize(&var_name, 0); + for (uint64_t i = 0; i < len; i += 1) { + ConstExprValue *char_val = ptr_field->data.x_ptr.ptr[i]; + uint64_t big_c = char_val->data.x_bignum.data.x_uint; + assert(big_c <= UINT8_MAX); + uint8_t c = big_c; + buf_append_char(&var_name, c); + } + + ConstExprValue *const_val = &get_resolved_expr(node)->const_val; + const_val->depends_on_compile_var = true; + + if (buf_eql_str(&var_name, "is_big_endian")) { + return resolve_expr_const_val_as_bool(g, node, g->is_big_endian); + } else { + add_node_error(g, *str_node, + buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(&var_name))); + return g->builtin_types.entry_invalid; + } + + break; + } + } zig_unreachable(); } diff --git a/src/codegen.cpp b/src/codegen.cpp index abcfbd096..335f0319f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -304,6 +304,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { case BuiltinFnIdMinValue: case BuiltinFnIdMaxValue: case BuiltinFnIdMemberCount: + case BuiltinFnIdCompileVar: // caught by constant expression eval codegen zig_unreachable(); } @@ -3221,6 +3222,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn_with_arg_count(g, BuiltinFnIdCInclude, "c_include", 1); 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); } @@ -3267,6 +3269,7 @@ static void init(CodeGen *g, Buf *source_path) { g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); + g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); g->builder = LLVMCreateBuilder(); g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); diff --git a/test/run_tests.cpp b/test/run_tests.cpp index dd5f08527..14856b7ab 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -2033,6 +2033,11 @@ fn func() -> bogus {} )SOURCE", 2, ".tmp_source.zig:3:1: error: redefinition of 'func'", ".tmp_source.zig:2:14: error: use of undeclared identifier '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'"); } //////////////////////////////////////////////////////////////////////////////