mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
More support for test. Panic function update.
This commit is contained in:
committed by
Christoffer Lerno
parent
450113d161
commit
49eacb8824
@@ -62,6 +62,11 @@ extern fn LongDivResult ldiv(long number, long denom);
|
||||
extern fn int rand();
|
||||
extern fn void srand(uint seed);
|
||||
|
||||
define JmpBuf = CInt[$$JMP_BUF_SIZE];
|
||||
|
||||
extern fn CInt setjmp(JmpBuf* buffer);
|
||||
extern fn void longjmp(JmpBuf* buffer, CInt value);
|
||||
|
||||
// MB functions omitted
|
||||
|
||||
// string
|
||||
@@ -131,6 +136,7 @@ $default:
|
||||
macro CFile stderr() { return (CFile*)(uptr)2; }
|
||||
$endswitch;
|
||||
|
||||
|
||||
const HAS_MALLOC_SIZE =
|
||||
env::OS_TYPE == OsType.LINUX
|
||||
|| env::OS_TYPE == OsType.WIN32
|
||||
@@ -233,6 +239,7 @@ define SignalFunction = fn void(int);
|
||||
extern fn SignalFunction signal(int sig, SignalFunction function);
|
||||
// Incomplete
|
||||
|
||||
|
||||
module libc::errno;
|
||||
|
||||
const Errno EPERM = 1; /* Operation not permitted */
|
||||
@@ -368,3 +375,5 @@ const Errno EKEYREJECTED = 129; /* Key was rejected by service */
|
||||
|
||||
const Errno EOWNERDEAD = 130; /* Owner died */
|
||||
const Errno ENOTRECOVERABLE = 131; /* State not recoverable */
|
||||
|
||||
|
||||
|
||||
@@ -28,33 +28,72 @@ struct VarArrayHeader
|
||||
void *allocator;
|
||||
}
|
||||
|
||||
define TestFn = fn void!();
|
||||
|
||||
struct TestRunner
|
||||
{
|
||||
char** test_names;
|
||||
void** test_fns;
|
||||
uint count;
|
||||
char[][] test_names;
|
||||
TestFn[] test_fns;
|
||||
JmpBuf buf;
|
||||
}
|
||||
|
||||
fn TestRunner test_runner_create()
|
||||
{
|
||||
return TestRunner {
|
||||
.test_names = $$TEST_NAMES,
|
||||
.test_fns = $$TEST_FNS,
|
||||
.count = $$TEST_COUNT,
|
||||
.test_names = $$TEST_NAMES,
|
||||
};
|
||||
}
|
||||
|
||||
extern fn void puts(char* c);
|
||||
import libc;
|
||||
|
||||
fn void TestRunner.run(TestRunner* runner)
|
||||
private TestRunner* current_runner;
|
||||
fn void test_panic(char[] message, char[] file, char[] function, uint line)
|
||||
{
|
||||
for (uint i = 0; i < runner.count; i++)
|
||||
{
|
||||
puts(runner.test_names[i]);
|
||||
}
|
||||
io::println("[error]");
|
||||
io::printfln("\n Error: %s", message);
|
||||
io::printfln(" - in %s %s:%s.\n", function, file, line);
|
||||
libc::longjmp(¤t_runner.buf, 1);
|
||||
}
|
||||
|
||||
fn void run_test_runner()
|
||||
fn bool TestRunner.run(TestRunner* runner)
|
||||
{
|
||||
test_runner_create().run();
|
||||
current_runner = runner;
|
||||
PanicFn old_panic = builtin::panic;
|
||||
defer builtin::panic = old_panic;
|
||||
builtin::panic = &test_panic;
|
||||
int tests_passed = 0;
|
||||
int tests = runner.test_names.len;
|
||||
io::println("----- TESTS -----");
|
||||
foreach(i, char[] name : runner.test_names)
|
||||
{
|
||||
io::printf("Testing %s ... ", name);
|
||||
if (libc::setjmp(&runner.buf) == 0)
|
||||
{
|
||||
if (catch err = runner.test_fns[i]())
|
||||
{
|
||||
io::println("[failed]");
|
||||
continue;
|
||||
}
|
||||
io::println("[ok]");
|
||||
tests_passed++;
|
||||
}
|
||||
}
|
||||
io::printfln("\n%d test(s) run.\n", tests);
|
||||
io::print("Test Result: ");
|
||||
if (tests_passed < tests)
|
||||
{
|
||||
io::print("FAILED");
|
||||
}
|
||||
else
|
||||
{
|
||||
io::print("ok");
|
||||
}
|
||||
io::printfln(". %d passed, %d failed.", tests_passed, tests - tests_passed);
|
||||
return tests == tests_passed;
|
||||
}
|
||||
|
||||
fn bool __run_default_test_runner()
|
||||
{
|
||||
return test_runner_create().run();
|
||||
}
|
||||
@@ -63,6 +63,7 @@ static void usage(void)
|
||||
OUTPUT(" compile <file1> [<file2> ...] Compile files without a project into an executable.");
|
||||
OUTPUT(" init <project name> Initialize a new project structure.");
|
||||
OUTPUT(" build [<target>] Build the target in the current project.");
|
||||
OUTPUT(" test Run the unit tests in the current project.");
|
||||
OUTPUT(" clean Clean all build files.");
|
||||
OUTPUT(" run [<target>] Run (and build if needed) the target in the current project.");
|
||||
OUTPUT(" dist [<target>] Clean and build a target for distribution.");
|
||||
@@ -244,6 +245,12 @@ static void parse_command(BuildOptions *options)
|
||||
options->command = COMMAND_UNIT_TEST;
|
||||
return;
|
||||
}
|
||||
if (arg_match("compile-test"))
|
||||
{
|
||||
options->command = COMMAND_COMPILE_TEST;
|
||||
options->testing = true;
|
||||
return;
|
||||
}
|
||||
if (arg_match("compile"))
|
||||
{
|
||||
options->command = COMMAND_COMPILE;
|
||||
@@ -275,6 +282,12 @@ static void parse_command(BuildOptions *options)
|
||||
parse_optional_target(options);
|
||||
return;
|
||||
}
|
||||
if (arg_match("test"))
|
||||
{
|
||||
options->command = COMMAND_TEST;
|
||||
options->testing = true;
|
||||
return;
|
||||
}
|
||||
if (arg_match("run"))
|
||||
{
|
||||
options->command = COMMAND_RUN;
|
||||
|
||||
@@ -23,6 +23,7 @@ typedef enum
|
||||
COMMAND_MISSING = 0,
|
||||
COMMAND_COMPILE,
|
||||
COMMAND_COMPILE_ONLY,
|
||||
COMMAND_COMPILE_TEST,
|
||||
COMMAND_GENERATE_HEADERS,
|
||||
COMMAND_INIT,
|
||||
COMMAND_BUILD,
|
||||
@@ -35,6 +36,7 @@ typedef enum
|
||||
COMMAND_DIST,
|
||||
COMMAND_DOCS,
|
||||
COMMAND_BENCH,
|
||||
COMMAND_TEST,
|
||||
COMMAND_UNIT_TEST,
|
||||
COMMAND_PRINT_SYNTAX,
|
||||
} CompilerCommand;
|
||||
@@ -335,6 +337,7 @@ typedef struct
|
||||
const char *llvm_file_dir;
|
||||
const char *asm_file_dir;
|
||||
bool run_after_compile;
|
||||
bool generate_test_runner;
|
||||
bool test_output;
|
||||
bool output_headers;
|
||||
bool output_ast;
|
||||
|
||||
@@ -69,6 +69,8 @@ bool command_is_projectless(CompilerCommand command)
|
||||
case COMMAND_COMPILE_RUN:
|
||||
case COMMAND_DYNAMIC_LIB:
|
||||
case COMMAND_STATIC_LIB:
|
||||
case COMMAND_COMPILE_TEST:
|
||||
case COMMAND_UNIT_TEST:
|
||||
return true;
|
||||
case COMMAND_MISSING:
|
||||
case COMMAND_GENERATE_HEADERS:
|
||||
@@ -80,8 +82,8 @@ bool command_is_projectless(CompilerCommand command)
|
||||
case COMMAND_DIST:
|
||||
case COMMAND_DOCS:
|
||||
case COMMAND_BENCH:
|
||||
case COMMAND_UNIT_TEST:
|
||||
case COMMAND_PRINT_SYNTAX:
|
||||
case COMMAND_TEST:
|
||||
return false;
|
||||
}
|
||||
UNREACHABLE
|
||||
@@ -90,6 +92,11 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
{
|
||||
switch (options->command)
|
||||
{
|
||||
case COMMAND_COMPILE_TEST:
|
||||
case COMMAND_TEST:
|
||||
target->run_after_compile = true;
|
||||
target->type = TARGET_TYPE_TEST;
|
||||
break;
|
||||
case COMMAND_RUN:
|
||||
case COMMAND_COMPILE_RUN:
|
||||
case COMMAND_CLEAN_RUN:
|
||||
|
||||
@@ -334,8 +334,11 @@ void compiler_compile(void)
|
||||
{
|
||||
switch (active_target.type)
|
||||
{
|
||||
case TARGET_TYPE_EXECUTABLE:
|
||||
case TARGET_TYPE_TEST:
|
||||
active_target.name = "testrun";
|
||||
output_exe = exe_name();
|
||||
break;
|
||||
case TARGET_TYPE_EXECUTABLE:
|
||||
if (!global_context.main)
|
||||
{
|
||||
puts("No main function was found, compilation only object files are generated.");
|
||||
@@ -648,6 +651,48 @@ void print_syntax(BuildOptions *options)
|
||||
|
||||
void resolve_libraries(void);
|
||||
|
||||
static int jump_buffer_size()
|
||||
{
|
||||
switch (active_target.arch_os_target)
|
||||
{
|
||||
case ARCH_OS_TARGET_DEFAULT:
|
||||
return 512;
|
||||
case ELF_RISCV32:
|
||||
case ELF_RISCV64:
|
||||
case LINUX_RISCV32:
|
||||
case LINUX_RISCV64:
|
||||
REMINDER("RISCV jmpbuf size is unknown");
|
||||
return 512;
|
||||
case ELF_X64:
|
||||
case FREEBSD_X64:
|
||||
case LINUX_X64:
|
||||
case MACOS_X64:
|
||||
case WINDOWS_X64:
|
||||
case MINGW_X64:
|
||||
case NETBSD_X64:
|
||||
case OPENBSD_X64:
|
||||
// Based on MacOS headers
|
||||
return ((9 * 2) + 3 + 16);
|
||||
case LINUX_AARCH64:
|
||||
case ELF_AARCH64:
|
||||
case MACOS_AARCH64:
|
||||
// Based on MacOS headers
|
||||
return ((14 + 8 + 2) * 2);
|
||||
case LINUX_X86:
|
||||
case MCU_X86:
|
||||
case NETBSD_X86:
|
||||
case OPENBSD_X86:
|
||||
case WINDOWS_X86:
|
||||
case ELF_X86:
|
||||
case FREEBSD_X86:
|
||||
return 18;
|
||||
case WASM32:
|
||||
case WASM64:
|
||||
REMINDER("WASM setjmp size is unknown");
|
||||
return 512;
|
||||
}
|
||||
UNREACHABLE
|
||||
}
|
||||
void compile()
|
||||
{
|
||||
symtab_init(active_target.symtab_size);
|
||||
@@ -679,6 +724,7 @@ void compile()
|
||||
setup_bool_define("COMPILER_SAFE_MODE", active_target.feature.safe_mode);
|
||||
setup_int_define("LLVM_VERSION", llvm_version_major, type_int);
|
||||
setup_bool_define("BENCHMARKING", active_target.benchmarking);
|
||||
setup_int_define("JMP_BUF_SIZE", jump_buffer_size(), type_int);
|
||||
setup_bool_define("TESTING", active_target.testing);
|
||||
|
||||
type_init_cint();
|
||||
|
||||
@@ -1660,6 +1660,7 @@ typedef struct
|
||||
Path std_module_path;
|
||||
Decl *panic_var;
|
||||
Decl *main;
|
||||
Decl *test_func;
|
||||
Decl *decl_stack[MAX_GLOBAL_DECL_STACK];
|
||||
Decl** decl_stack_bottom;
|
||||
Decl** decl_stack_top;
|
||||
@@ -1826,6 +1827,7 @@ extern const char *builtin_defines[NUMBER_OF_BUILTIN_DEFINES];
|
||||
extern const char *type_property_list[NUMBER_OF_TYPE_PROPERTIES];
|
||||
extern const char *kw_std__core;
|
||||
extern const char *kw_std__core__types;
|
||||
extern const char *kw___run_default_test_runner;
|
||||
extern const char *kw_typekind;
|
||||
|
||||
extern const char *kw_argc;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include "compiler_internal.h"
|
||||
|
||||
|
||||
CompilationUnit * unit_create(File *file)
|
||||
CompilationUnit *unit_create(File *file)
|
||||
{
|
||||
CompilationUnit *unit = CALLOCS(CompilationUnit);
|
||||
unit->file = file;
|
||||
|
||||
@@ -111,6 +111,7 @@ typedef enum
|
||||
CAST_ENUMLOW,
|
||||
CAST_APTSA,
|
||||
CAST_SAPTR,
|
||||
CAST_SASA,
|
||||
CAST_SABOOL,
|
||||
CAST_STST,
|
||||
CAST_PTRANY,
|
||||
@@ -900,7 +901,6 @@ typedef enum
|
||||
BUILTIN_DEF_LINE,
|
||||
BUILTIN_DEF_LINE_RAW,
|
||||
BUILTIN_DEF_MODULE,
|
||||
BUILTIN_DEF_TEST_COUNT,
|
||||
BUILTIN_DEF_TEST_NAMES,
|
||||
BUILTIN_DEF_TEST_FNS,
|
||||
BUILTIN_DEF_TIME,
|
||||
|
||||
@@ -375,6 +375,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_
|
||||
case CAST_PTRPTR:
|
||||
case CAST_APTSA:
|
||||
case CAST_SAPTR:
|
||||
case CAST_SASA:
|
||||
case CAST_ENUMLOW:
|
||||
return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind);
|
||||
case CAST_PTRANY:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <llvm-c/Error.h>
|
||||
#include <llvm-c/Comdat.h>
|
||||
#include <llvm-c/Linker.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
typedef struct LLVMOpaquePassBuilderOptions *LLVMPassBuilderOptionsRef;
|
||||
LLVMErrorRef LLVMRunPasses(LLVMModuleRef M, const char *Passes,
|
||||
LLVMTargetMachineRef TM,
|
||||
@@ -1004,76 +1004,104 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
INLINE void llvm_gen_tests(GenContext *test_owner, Module** modules, unsigned module_count)
|
||||
static void llvm_gen_test_main(GenContext *c)
|
||||
{
|
||||
Decl *test_runner = global_context.test_func;
|
||||
if (!test_runner)
|
||||
{
|
||||
error_exit("No test runner found.");
|
||||
}
|
||||
assert(!global_context.main && "Main should not be set if a test main is generated.");
|
||||
global_context.main = test_runner;
|
||||
LLVMTypeRef cint = llvm_get_type(c, type_cint);
|
||||
LLVMTypeRef main_type = LLVMFunctionType(cint, NULL, 0, true);
|
||||
LLVMTypeRef runner_type = LLVMFunctionType(c->byte_type, NULL, 0, true);
|
||||
LLVMValueRef func = LLVMAddFunction(c->module, kw_main, main_type);
|
||||
LLVMValueRef other_func = LLVMAddFunction(c->module, test_runner->extname, runner_type);
|
||||
LLVMBasicBlockRef entry = LLVMAppendBasicBlockInContext(c->context, func, "entry");
|
||||
LLVMBuilderRef builder = LLVMCreateBuilderInContext(c->context);
|
||||
LLVMPositionBuilderAtEnd(builder, entry);
|
||||
LLVMValueRef val = LLVMBuildCall2(builder, runner_type, other_func, NULL, 0, "");
|
||||
val = LLVMBuildSelect(builder, LLVMBuildTrunc(builder, val, c->bool_type, ""),
|
||||
LLVMConstNull(cint), LLVMConstInt(cint, 1, false), "");
|
||||
LLVMBuildRet(builder, val);
|
||||
LLVMDisposeBuilder(builder);
|
||||
gencontext_print_llvm_ir(c);
|
||||
}
|
||||
INLINE GenContext *llvm_gen_tests(Module** modules, unsigned module_count, LLVMContextRef shared_context)
|
||||
{
|
||||
Path *test_path = path_create_from_string("$test", 5, INVALID_SPAN);
|
||||
Module *test_module = compiler_find_or_create_module(test_path, NULL, false);
|
||||
|
||||
GenContext *c = cmalloc(sizeof(GenContext));
|
||||
active_target.debug_info = DEBUG_INFO_NONE;
|
||||
gencontext_init(c, test_module, shared_context);
|
||||
gencontext_begin_module(c);
|
||||
|
||||
LLVMValueRef *names = NULL;
|
||||
LLVMValueRef *decls = NULL;
|
||||
|
||||
LLVMTypeRef void_test = LLVMFunctionType(LLVMVoidTypeInContext(test_owner->context), NULL, 0, false);
|
||||
LLVMTypeRef opt_test = LLVMFunctionType(test_owner->fault_type, NULL, 0, false);
|
||||
LLVMTypeRef opt_test = LLVMFunctionType(llvm_get_type(c, type_anyerr), NULL, 0, false);
|
||||
for (unsigned i = 0; i < module_count; i++)
|
||||
{
|
||||
Module *module = modules[i];
|
||||
bool gen_proto = test_owner->code_module != module;
|
||||
FOREACH_BEGIN(Decl *test, module->tests)
|
||||
LLVMValueRef ref;
|
||||
if (gen_proto)
|
||||
{
|
||||
LLVMTypeRef type = test->type->function.prototype->rtype == type_void ? void_test : opt_test;
|
||||
ref = LLVMAddFunction(test_owner->module, test->extname, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
ref = test->backend_ref;
|
||||
}
|
||||
LLVMTypeRef type = opt_test;
|
||||
ref = LLVMAddFunction(c->module, test->extname, type);
|
||||
scratch_buffer_clear();
|
||||
scratch_buffer_printf("%s::%s", module->name->module, test->name);
|
||||
LLVMTypeRef char_array_type = LLVMArrayType(test_owner->byte_type, scratch_buffer.len + 1);
|
||||
LLVMValueRef global_string = llvm_add_global_raw(test_owner, ".test", char_array_type, 0);
|
||||
llvm_set_internal_linkage(global_string);
|
||||
LLVMSetGlobalConstant(global_string, 1);
|
||||
LLVMSetInitializer(global_string, llvm_get_zstring(test_owner, scratch_buffer_to_string(), scratch_buffer.len));
|
||||
LLVMValueRef str = LLVMBuildBitCast(test_owner->builder, global_string, test_owner->char_ptr_type, "");
|
||||
vec_add(names, str);
|
||||
ref = LLVMBuildBitCast(test_owner->builder, ref, test_owner->char_ptr_type, "");
|
||||
LLVMValueRef name = llvm_emit_string_const(c, scratch_buffer_to_string(), ".test.name");
|
||||
vec_add(names, name);
|
||||
vec_add(decls, ref);
|
||||
FOREACH_END();
|
||||
}
|
||||
unsigned test_count = vec_size(decls);
|
||||
LLVMTypeRef ptr_of_chars_ptrs = LLVMPointerType(test_owner->char_ptr_type, 0);
|
||||
LLVMValueRef name_ref;
|
||||
LLVMValueRef decl_ref;
|
||||
LLVMTypeRef chars_type = llvm_get_type(c, type_chars);
|
||||
if (test_count)
|
||||
{
|
||||
LLVMValueRef array_of_names = LLVMConstArray(test_owner->char_ptr_type, names, test_count);
|
||||
LLVMValueRef array_of_decls = LLVMConstArray(test_owner->char_ptr_type, decls, test_count);
|
||||
LLVMValueRef array_of_names = LLVMConstArray(chars_type, names, test_count);
|
||||
LLVMValueRef array_of_decls = LLVMConstArray(LLVMPointerType(opt_test, 0), decls, test_count);
|
||||
LLVMTypeRef arr_type = LLVMTypeOf(array_of_names);
|
||||
name_ref = llvm_add_global_raw(test_owner, ".test_names", arr_type, llvm_alloc_size(test_owner, arr_type));
|
||||
decl_ref = llvm_add_global_raw(test_owner, ".test_decls", arr_type, llvm_alloc_size(test_owner, arr_type));
|
||||
name_ref = llvm_add_global_raw(c, ".test_names", arr_type, llvm_alloc_size(c, arr_type));
|
||||
decl_ref = llvm_add_global_raw(c, ".test_decls", LLVMTypeOf(array_of_decls), llvm_alloc_size(c, arr_type));
|
||||
llvm_set_internal_linkage(name_ref);
|
||||
llvm_set_internal_linkage(decl_ref);
|
||||
LLVMSetGlobalConstant(name_ref, 1);
|
||||
LLVMSetGlobalConstant(decl_ref, 1);
|
||||
LLVMSetInitializer(name_ref, array_of_names);
|
||||
LLVMSetInitializer(decl_ref, array_of_decls);
|
||||
name_ref = LLVMBuildBitCast(test_owner->builder, name_ref, ptr_of_chars_ptrs, "");
|
||||
decl_ref = LLVMBuildBitCast(test_owner->builder, decl_ref, ptr_of_chars_ptrs, "");
|
||||
name_ref = LLVMBuildBitCast(c->builder, name_ref, llvm_get_ptr_type(c, type_chars), "");
|
||||
decl_ref = LLVMBuildBitCast(c->builder, decl_ref, llvm_get_ptr_type(c, type_voidptr), "");
|
||||
}
|
||||
else
|
||||
{
|
||||
name_ref = LLVMConstNull(ptr_of_chars_ptrs);
|
||||
decl_ref = LLVMConstNull(ptr_of_chars_ptrs);
|
||||
name_ref = LLVMConstNull(llvm_get_ptr_type(c, type_chars));
|
||||
decl_ref = LLVMConstNull(llvm_get_ptr_type(c, type_voidptr));
|
||||
}
|
||||
LLVMValueRef name_list = llvm_add_global_raw(test_owner, "C3_TEST_NAME_LIST", ptr_of_chars_ptrs, llvm_alloc_size(test_owner, ptr_of_chars_ptrs));
|
||||
LLVMValueRef count = llvm_const_int(c, type_usize, test_count);
|
||||
Type *chars_array = type_get_subarray(type_chars);
|
||||
LLVMValueRef name_list = llvm_add_global(c, test_names_var_name, chars_array, type_alloca_alignment(chars_array));
|
||||
LLVMSetGlobalConstant(name_list, 1);
|
||||
LLVMSetInitializer(name_list, name_ref);
|
||||
LLVMValueRef decl_list = llvm_add_global_raw(test_owner, "C3_TEST_DECL_LIST", ptr_of_chars_ptrs, llvm_alloc_size(test_owner, ptr_of_chars_ptrs));
|
||||
LLVMSetInitializer(name_list, llvm_emit_aggregate_two(c, chars_array, name_ref, count));
|
||||
Type *decls_array_type = type_get_subarray(type_voidptr);
|
||||
LLVMValueRef decl_list = llvm_add_global(c, test_fns_var_name, decls_array_type, type_alloca_alignment(decls_array_type));
|
||||
LLVMSetGlobalConstant(decl_list, 1);
|
||||
LLVMSetInitializer(decl_list, decl_ref);
|
||||
LLVMTypeRef int_len_type = LLVMInt32TypeInContext(test_owner->context);
|
||||
LLVMValueRef name_count = llvm_add_global_raw(test_owner, "C3_TEST_COUNT", int_len_type, llvm_alloc_size(test_owner, int_len_type));
|
||||
LLVMSetGlobalConstant(name_count, 1);
|
||||
LLVMSetInitializer(name_count, LLVMConstInt(int_len_type, test_count, false));
|
||||
LLVMSetInitializer(decl_list, llvm_emit_aggregate_two(c, decls_array_type, decl_ref, count));
|
||||
|
||||
if (active_target.type == TARGET_TYPE_TEST)
|
||||
{
|
||||
llvm_gen_test_main(c);
|
||||
}
|
||||
|
||||
if (llvm_use_debug(c))
|
||||
{
|
||||
LLVMDIBuilderFinalize(c->debug.builder);
|
||||
LLVMDisposeDIBuilder(c->debug.builder);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
void **llvm_gen(Module** modules, unsigned module_count)
|
||||
{
|
||||
@@ -1093,7 +1121,7 @@ void **llvm_gen(Module** modules, unsigned module_count)
|
||||
}
|
||||
if (!gen_contexts) return NULL;
|
||||
GenContext *first = gen_contexts[0];
|
||||
llvm_gen_tests(first, modules, module_count);
|
||||
vec_add(gen_contexts, llvm_gen_tests(modules, module_count, context));
|
||||
unsigned count = vec_size(gen_contexts);
|
||||
for (unsigned i = 1; i < count; i++)
|
||||
{
|
||||
@@ -1110,7 +1138,7 @@ void **llvm_gen(Module** modules, unsigned module_count)
|
||||
if (!result) continue;
|
||||
vec_add(gen_contexts, result);
|
||||
}
|
||||
llvm_gen_tests(gen_contexts[0], modules, module_count);
|
||||
vec_add(gen_contexts, llvm_gen_tests(modules, module_count, NULL));
|
||||
return (void**)gen_contexts;
|
||||
}
|
||||
|
||||
@@ -1153,7 +1181,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
llvm_emit_function_decl(gen_context, func);
|
||||
FOREACH_END();
|
||||
|
||||
if (!active_target.testing && unit->main_function && unit->main_function->is_synthetic)
|
||||
if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic)
|
||||
{
|
||||
llvm_emit_function_decl(gen_context, unit->main_function);
|
||||
}
|
||||
@@ -1178,7 +1206,7 @@ static GenContext *llvm_gen_module(Module *module, LLVMContextRef shared_context
|
||||
if (decl->func_decl.body) llvm_emit_function_body(gen_context, decl);
|
||||
FOREACH_END();
|
||||
|
||||
if (!active_target.testing && unit->main_function && unit->main_function->is_synthetic)
|
||||
if (active_target.type != TARGET_TYPE_TEST && unit->main_function && unit->main_function->is_synthetic)
|
||||
{
|
||||
llvm_emit_function_body(gen_context, unit->main_function);
|
||||
}
|
||||
|
||||
@@ -1237,6 +1237,11 @@ void llvm_emit_cast(GenContext *c, CastKind cast_kind, Expr *expr, BEValue *valu
|
||||
case CAST_APTSA:
|
||||
llvm_emit_arr_to_subarray_cast(c, value, to_type);
|
||||
break;
|
||||
case CAST_SASA:
|
||||
assert(type_is_pointer(value->type->array.base));
|
||||
llvm_value_addr(c, value);
|
||||
llvm_value_bitcast(c, value, to_type);
|
||||
break;
|
||||
case CAST_SAPTR:
|
||||
llvm_emit_subarray_pointer(c, value, value);
|
||||
if (value->type != to_type)
|
||||
@@ -6023,13 +6028,10 @@ static LLVMValueRef llvm_get_test_hook_global(GenContext *c, Expr *expr)
|
||||
switch (expr->test_hook_expr)
|
||||
{
|
||||
case BUILTIN_DEF_TEST_FNS:
|
||||
name = "C3_TEST_DECL_LIST";
|
||||
break;
|
||||
case BUILTIN_DEF_TEST_COUNT:
|
||||
name = "C3_TEST_COUNT";
|
||||
name = test_fns_var_name;
|
||||
break;
|
||||
case BUILTIN_DEF_TEST_NAMES:
|
||||
name = "C3_TEST_NAME_LIST";
|
||||
name = test_names_var_name;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
|
||||
@@ -497,8 +497,17 @@ void llvm_emit_body(GenContext *c, LLVMValueRef function, const char *module_nam
|
||||
LLVMValueRef file_name = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 2, alignment, &align_to_use);
|
||||
llvm_store_to_ptr_raw_aligned(c, file_name, c->debug.file_name, align_to_use);
|
||||
c->debug.stack_slot_row = llvm_emit_struct_gep_raw(c, c->debug.stack_slot, slot_type, 3, alignment, &align_to_use);
|
||||
LLVMValueRef last_ptr = NULL;
|
||||
if (function_name != kw_main && function_name != kw_mainstub)
|
||||
{
|
||||
last_ptr = c->debug.last_ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
last_ptr = prev_ptr;
|
||||
}
|
||||
llvm_store_to_ptr_raw_aligned(c,
|
||||
c->debug.last_ptr,
|
||||
last_ptr,
|
||||
c->debug.stack_slot,
|
||||
type_alloca_alignment(type_voidptr));
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ typedef struct GenContext_
|
||||
LLVMTypeRef fault_type;
|
||||
LLVMTypeRef size_type;
|
||||
LLVMTypeRef char_ptr_type;
|
||||
LLVMTypeRef chars_type;
|
||||
Decl *panic_var;
|
||||
struct
|
||||
{
|
||||
|
||||
@@ -127,6 +127,7 @@ void gencontext_begin_module(GenContext *c)
|
||||
c->fault_type = create_fault_type(c);
|
||||
c->size_type = llvm_get_type(c, type_usize);
|
||||
c->char_ptr_type = LLVMPointerType(c->byte_type, 0);
|
||||
c->chars_type = llvm_get_type(c, type_chars);
|
||||
if (c->panic_var) c->panic_var->backend_ref = NULL;
|
||||
|
||||
if (active_target.debug_info != DEBUG_INFO_NONE)
|
||||
@@ -142,8 +143,8 @@ void gencontext_begin_module(GenContext *c)
|
||||
{
|
||||
c->debug.stack_type = LLVMStructCreateNamed(c->context, ".$callstack");
|
||||
LLVMTypeRef types[4] = { LLVMPointerType(c->debug.stack_type, 0),
|
||||
LLVMPointerType(c->byte_type, 0),
|
||||
LLVMPointerType(c->byte_type, 0),
|
||||
c->chars_type,
|
||||
c->chars_type,
|
||||
llvm_get_type(c, type_uint) };
|
||||
LLVMStructSetBody(c->debug.stack_type, types, 4, false);
|
||||
c->debug.last_ptr = NULL;
|
||||
|
||||
@@ -549,6 +549,8 @@ bool cast_may_explicit(Type *from_type, Type *to_type, bool ignore_failability,
|
||||
case TYPE_UNION:
|
||||
return type_is_structurally_equivalent(from_type, to_type);
|
||||
case TYPE_SUBARRAY:
|
||||
if (to_kind == TYPE_SUBARRAY && type_is_pointer(to_type->array.base)
|
||||
&& type_is_pointer(from_type->array.base)) return true;
|
||||
return to_kind == TYPE_POINTER;
|
||||
case TYPE_VECTOR:
|
||||
return type_is_structurally_equivalent(type_get_array(from_type->array.base, (uint32_t)from_type->array.len), to_type);
|
||||
@@ -821,6 +823,17 @@ bool cast_may_implicit(Type *from_type, Type *to_type, CastOption option)
|
||||
{
|
||||
return from->pointer->type_kind == TYPE_ARRAY && from->pointer->array.base == base;
|
||||
}
|
||||
|
||||
// Allow casting void*[] to int*[]
|
||||
if (from->type_kind == TYPE_SUBARRAY && from->array.base == type_voidptr && type_is_pointer(to->array.base))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Allow casting int*[] -> void*[]
|
||||
if (from->type_kind == TYPE_SUBARRAY && to->array.base == type_voidptr && type_is_pointer(from->array.base))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1450,6 +1463,14 @@ static bool err_to_bool(Expr *expr, Type *to_type)
|
||||
return insert_cast(expr, CAST_ERBOOL, to_type);
|
||||
}
|
||||
|
||||
static inline bool subarray_to_subarray(Expr *expr, Type *to_type)
|
||||
{
|
||||
if (expr_is_const(expr))
|
||||
{
|
||||
expr->type = to_type;
|
||||
}
|
||||
return insert_cast(expr, CAST_SASA, to_type);
|
||||
}
|
||||
static inline bool subarray_to_bool(Expr *expr)
|
||||
{
|
||||
if (expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_INITIALIZER)
|
||||
@@ -1562,6 +1583,7 @@ static bool cast_inner(Expr *expr, Type *from_type, Type *to, Type *to_type)
|
||||
case TYPE_SUBARRAY:
|
||||
if (to->type_kind == TYPE_POINTER) return insert_cast(expr, CAST_SAPTR, to);
|
||||
if (to->type_kind == TYPE_BOOL) return subarray_to_bool(expr);
|
||||
if (to->type_kind == TYPE_SUBARRAY) return subarray_to_subarray(expr, to);
|
||||
break;
|
||||
case TYPE_VECTOR:
|
||||
if (to->type_kind == TYPE_ARRAY) return vec_to_arr(expr, to_type);
|
||||
|
||||
@@ -1930,6 +1930,8 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl)
|
||||
SEMA_ERROR(params[0], "Expected zero, 1 or 2 parameters for main.");
|
||||
return false;
|
||||
}
|
||||
if (active_target.type == TARGET_TYPE_TEST) return true;
|
||||
|
||||
Decl *function;
|
||||
if (!subarray_param && is_int_return)
|
||||
{
|
||||
@@ -2068,6 +2070,15 @@ static inline bool sema_analyse_func(SemaContext *context, Decl *decl)
|
||||
|
||||
if (!sema_analyse_func_macro(context, decl, true)) return false;
|
||||
|
||||
if (decl->name == kw___run_default_test_runner)
|
||||
{
|
||||
if (global_context.test_func)
|
||||
{
|
||||
SEMA_ERROR(decl, "Multiple test runners defined.");
|
||||
return false;
|
||||
}
|
||||
global_context.test_func = decl;
|
||||
}
|
||||
Signature *sig = &decl->func_decl.signature;
|
||||
Type *func_type = sema_analyse_function_signature(context, decl, sig->abi, sig, true);
|
||||
decl->type = func_type;
|
||||
|
||||
@@ -5947,18 +5947,13 @@ static inline bool sema_expr_analyse_compiler_const(SemaContext *context, Expr *
|
||||
expr_replace(expr, value);
|
||||
return true;
|
||||
}
|
||||
case BUILTIN_DEF_TEST_COUNT:
|
||||
expr->type = type_uint;
|
||||
expr->test_hook_expr = BUILTIN_DEF_TEST_COUNT;
|
||||
expr->expr_kind = EXPR_TEST_HOOK;
|
||||
return true;
|
||||
case BUILTIN_DEF_TEST_NAMES:
|
||||
expr->type = type_get_ptr(type_get_ptr(type_char));
|
||||
expr->type = type_get_subarray(type_chars);
|
||||
expr->test_hook_expr = BUILTIN_DEF_TEST_NAMES;
|
||||
expr->expr_kind = EXPR_TEST_HOOK;
|
||||
return true;
|
||||
case BUILTIN_DEF_TEST_FNS:
|
||||
expr->type = type_get_ptr(type_voidptr);
|
||||
expr->type = type_get_subarray(type_voidptr);
|
||||
expr->test_hook_expr = BUILTIN_DEF_TEST_FNS;
|
||||
expr->expr_kind = EXPR_TEST_HOOK;
|
||||
return true;
|
||||
|
||||
@@ -79,6 +79,7 @@ const char *kw_return;
|
||||
const char *kw_std;
|
||||
const char *kw_std__core;
|
||||
const char *kw_std__core__types;
|
||||
const char *kw___run_default_test_runner;
|
||||
const char *kw_type;
|
||||
const char *kw_typekind;
|
||||
|
||||
@@ -131,7 +132,6 @@ void symtab_init(uint32_t capacity)
|
||||
builtin_defines[BUILTIN_DEF_TIME] = KW_DEF("TIME");
|
||||
builtin_defines[BUILTIN_DEF_TEST_NAMES] = KW_DEF("TEST_NAMES");
|
||||
builtin_defines[BUILTIN_DEF_TEST_FNS] = KW_DEF("TEST_FNS");
|
||||
builtin_defines[BUILTIN_DEF_TEST_COUNT] = KW_DEF("TEST_COUNT");
|
||||
|
||||
type = TOKEN_TYPE_IDENT;
|
||||
kw_typekind = KW_DEF("TypeKind");
|
||||
@@ -148,7 +148,7 @@ void symtab_init(uint32_t capacity)
|
||||
kw_incr = KW_DEF("incr");
|
||||
kw_inline = KW_DEF("inline");
|
||||
kw_inout = KW_DEF("inout");
|
||||
kw_mainstub = KW_DEF("_$mainstub");
|
||||
kw_mainstub = KW_DEF("_$start");
|
||||
kw_main = KW_DEF("main");
|
||||
kw_nameof = KW_DEF("nameof");
|
||||
kw_noinline = KW_DEF("noinline");
|
||||
@@ -160,6 +160,7 @@ void symtab_init(uint32_t capacity)
|
||||
kw_std = KW_DEF("std");
|
||||
kw_std__core = KW_DEF("std::core");
|
||||
kw_std__core__types = KW_DEF("std::core::types");
|
||||
kw___run_default_test_runner = KW_DEF("__run_default_test_runner");
|
||||
kw_type = KW_DEF("type");
|
||||
|
||||
type_property_list[TYPE_PROPERTY_MAX] = builtin_list[BUILTIN_MAX] = KW_DEF("max");
|
||||
|
||||
@@ -1472,7 +1472,6 @@ void type_setup(PlatformTarget *target)
|
||||
size_subarray = (unsigned)(alignment_subarray * 2);
|
||||
type_init("anyerr", &t.anyerr, TYPE_ANYERR, target->width_pointer, target->align_pointer);
|
||||
type_chars = type_get_subarray(type_char);
|
||||
|
||||
}
|
||||
|
||||
int type_kind_bitsize(TypeKind kind)
|
||||
|
||||
@@ -63,6 +63,7 @@ int main_real(int argc, const char *argv[])
|
||||
case COMMAND_COMPILE_RUN:
|
||||
case COMMAND_DYNAMIC_LIB:
|
||||
case COMMAND_STATIC_LIB:
|
||||
case COMMAND_COMPILE_TEST:
|
||||
compile_target(&build_options);
|
||||
break;
|
||||
case COMMAND_CLEAN:
|
||||
@@ -74,6 +75,7 @@ int main_real(int argc, const char *argv[])
|
||||
case COMMAND_DIST:
|
||||
case COMMAND_DOCS:
|
||||
case COMMAND_BENCH:
|
||||
case COMMAND_TEST:
|
||||
compile_file_list(&build_options);
|
||||
break;
|
||||
case COMMAND_MISSING:
|
||||
|
||||
Reference in New Issue
Block a user