- Output into /.build/obj/<platform> by default.

- Output llvm/asm into llvm/<platform> and asm/<platform> by default.
- Don't delete .o files not produced by the compiler.
- Correctly handle in/out when interacting with inout.
This commit is contained in:
Christoffer Lerno
2025-02-22 22:34:26 +01:00
parent 855be92881
commit 3da9f73338
11 changed files with 107 additions and 55 deletions

View File

@@ -175,6 +175,8 @@ fn char[]! load_buffer(String filename, char[] buffer)
}
fn char[]! load(Allocator allocator, String filename) => load_new(filename, allocator);
fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
{
File file = open(filename, "rb")!;

View File

@@ -7,6 +7,8 @@
- Add `--enable-new-generics` to enable `Foo{int}` generic syntax.
- `{| |}` expression blocks deprecated.
- c3c `--test-leak-report` flag for displaying full memory lead report if any
- Output into /.build/obj/<platform> by default.
- Output llvm/asm into llvm/<platform> and asm/<platform> by default.
### Fixes
- Bug appearing when `??` was combined with boolean in some cases.
@@ -18,6 +20,8 @@
- Crash when trying to define a method macro that isn't `@construct` but has no arguments.
- Regression, `.gitkeep` files were generated incorrectly.
- Aliases are now correctly handled as if they were variables/functions in regards to namespacing and accept `@builtin`.
- Correctly handle in/out when interacting with inout.
- Don't delete .o files not produced by the compiler.
### Stdlib changes

View File

@@ -461,23 +461,54 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
default: UNREACHABLE;
}
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT) target->arch_os_target = default_target;
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT)
{
error_exit("Unable to detect the default target, please set an explicit --target value.");
}
const char *target_name = arch_os_target[target->arch_os_target];
if (command_accepts_files(options->command))
{
target->build_dir = options->build_dir ? options->build_dir : NULL;
target->object_file_dir = options->obj_out ? options->obj_out : target->build_dir;
target->ir_file_dir = options->llvm_out ? options->llvm_out : target->build_dir;
target->asm_file_dir = options->asm_out ? options->asm_out : target->build_dir;
target->script_dir = options->script_dir ? options->script_dir : target->script_dir;
target->build_dir = options->build_dir ? options->build_dir : ".build";
if (!target->script_dir) target->script_dir = target->build_dir;
}
else
{
target->build_dir = options->build_dir ? options->build_dir : "build";
target->object_file_dir = options->obj_out ? options->obj_out : file_append_path(target->build_dir, "tmp");
target->ir_file_dir = options->llvm_out ? options->llvm_out : file_append_path(target->build_dir, "llvm_ir");
target->asm_file_dir = options->asm_out ? options->asm_out : file_append_path(target->build_dir, "asm");
target->script_dir = options->script_dir ? options->script_dir : target->script_dir;
if (!target->build_dir) target->build_dir = "build";
if (options->build_dir)
{
target->build_dir = options->build_dir;
}
else
{
options->build_dir = target->build_dir;
}
if (!target->script_dir) target->script_dir = "scripts";
}
target->ir_file_dir = options->llvm_out;
target->asm_file_dir = options->asm_out;
target->object_file_dir = options->obj_out;
if (!target->ir_file_dir)
{
target->ir_file_dir = options->build_dir
? file_append_path(file_append_path(options->build_dir, "llvm"), target_name)
: file_append_path("llvm", target_name);
}
if (!target->asm_file_dir)
{
target->asm_file_dir = options->build_dir
? file_append_path(file_append_path(options->build_dir, "asm"), target_name)
: file_append_path("asm", target_name);
}
if (!target->object_file_dir)
{
target->object_file_dir = options->build_dir
? file_append_path(file_append_path(options->build_dir, "obj"), target_name)
: file_append_path("obj", target_name);
}
switch (options->compile_option)
{
case COMPILE_NORMAL:

View File

@@ -391,13 +391,21 @@ void compiler_parse(void)
static void create_output_dir(const char *dir)
{
if (!file_exists(dir))
if (!dir) return;
if (file_exists(dir))
{
if (!dir_make(dir)) error_exit("Failed to create output directory %s.", dir);
if (!file_is_dir(dir)) error_exit("Output directory is not a directory %s.", dir);
return;
}
scratch_buffer_clear();
scratch_buffer_append(dir);
if (!dir_make_recursive(scratch_buffer_to_string()))
{
error_exit("Failed to create directory '%s'.", dir);
}
if (!file_is_dir(dir)) error_exit("Output directory is not a directory %s.", dir);
}
void compiler_compile(void)
{
if (compiler.build.lsp_output)
@@ -439,31 +447,19 @@ void compiler_compile(void)
if (compiler.build.asm_file_dir || compiler.build.ir_file_dir || compiler.build.emit_object_files)
{
if (compiler.build.build_dir && !file_exists(compiler.build.build_dir) && !dir_make(compiler.build.build_dir))
{
error_exit("Failed to create build directory '%s'.", compiler.build.build_dir);
}
create_output_dir(compiler.build.build_dir);
}
if (compiler.build.ir_file_dir && (compiler.build.emit_llvm || compiler.build.test_output || compiler.build.lsp_output))
{
if (!file_exists(compiler.build.ir_file_dir) && !dir_make(compiler.build.ir_file_dir))
{
error_exit("Failed to create output directory '%s'.", compiler.build.ir_file_dir);
}
create_output_dir(compiler.build.ir_file_dir);
}
if (compiler.build.asm_file_dir && compiler.build.emit_asm)
{
if (!file_exists(compiler.build.asm_file_dir) && !dir_make(compiler.build.asm_file_dir))
{
error_exit("Failed to create output directory '%s'.", compiler.build.asm_file_dir);
}
create_output_dir(compiler.build.asm_file_dir);
}
if (compiler.build.object_file_dir && compiler.build.emit_object_files)
{
if (!file_exists(compiler.build.object_file_dir) && !dir_make(compiler.build.object_file_dir))
{
error_exit("Failed to create output directory '%s'.", compiler.build.object_file_dir);
}
create_output_dir(compiler.build.object_file_dir);
}
if (compiler.build.type == TARGET_TYPE_EXECUTABLE && !compiler.context.main && !compiler.build.no_entry)
{
@@ -533,14 +529,14 @@ void compiler_compile(void)
free_arenas();
uint32_t output_file_count = vec_size(gen_contexts);
unsigned objfiles = vec_size(compiler.build.object_files);
unsigned external_objfile_count = vec_size(compiler.build.object_files);
unsigned cfiles = vec_size(compiler.build.csources);
unsigned cfiles_library = 0;
FOREACH(LibraryTarget *, lib, compiler.build.ccompiling_libraries)
{
cfiles_library += vec_size(lib->csources);
}
unsigned total_output = output_file_count + cfiles + cfiles_library + objfiles;
unsigned total_output = output_file_count + cfiles + cfiles_library + external_objfile_count;
if (total_output > MAX_OUTPUT_FILES)
{
error_exit("Too many output files.");
@@ -575,7 +571,7 @@ void compiler_compile(void)
obj_file_next += compile_cfiles(lib->cc ? lib->cc : compiler.build.cc, lib->csources,
lib->cflags, lib->cinclude_dirs, obj_file_next, lib->parent->provides);
}
for (unsigned i = 0; i < objfiles; i++)
for (unsigned i = 0; i < external_objfile_count; i++)
{
obj_file_next[0] = compiler.build.object_files[i];
obj_file_next++;
@@ -624,7 +620,8 @@ void compiler_compile(void)
puts("# output-files-end");
}
output_file_count += cfiles + cfiles_library + objfiles;
output_file_count += cfiles + cfiles_library + external_objfile_count;
unsigned objfile_delete_count = output_file_count - external_objfile_count;
free(compile_data);
compiler_codegen_time = bench_mark();
@@ -671,7 +668,7 @@ void compiler_compile(void)
platform_linker(output_exe, obj_files, output_file_count);
compiler_link_time = bench_mark();
compiler_print_bench();
delete_object_files(obj_files, output_file_count);
delete_object_files(obj_files, objfile_delete_count);
}
else
{
@@ -684,7 +681,7 @@ void compiler_compile(void)
}
else
{
delete_object_files(obj_files, output_file_count);
delete_object_files(obj_files, objfile_delete_count);
}
}
@@ -750,7 +747,7 @@ void compiler_compile(void)
{
error_exit("Failed to produce static library '%s'.", output_static);
}
delete_object_files(obj_files, output_file_count);
delete_object_files(obj_files, objfile_delete_count);
compiler_link_time = bench_mark();
compiler_print_bench();
OUTF("Static library '%s' created.\n", output_static);
@@ -770,7 +767,7 @@ void compiler_compile(void)
{
error_exit("Failed to produce dynamic library '%s'.", output_dynamic);
}
delete_object_files(obj_files, output_file_count);
delete_object_files(obj_files, objfile_delete_count);
OUTF("Dynamic library '%s' created.\n", output_dynamic);
compiler_link_time = bench_mark();
compiler_print_bench();

View File

@@ -459,7 +459,7 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
if (is_read)
{
decl->var.is_read = true;
if (decl->var.out_param)
if (decl->var.out_param && !decl->var.in_param)
{
RETURN_SEMA_ERROR(expr, "An 'out' variable may not be read from.");
}
@@ -468,7 +468,7 @@ static inline bool sema_check_asm_memvar(SemaContext *context, AsmInlineBlock *b
if (is_write)
{
decl->var.is_written = true;
if (decl->var.in_param)
if (decl->var.in_param && !decl->var.out_param)
{
RETURN_SEMA_ERROR(expr, "An 'in' variable may not be written to.");
}

View File

@@ -3205,6 +3205,8 @@ static inline bool sema_analyse_doc_header(SemaContext *context, AstId doc,
param->var.out_param = true;
break;
case INOUT_INOUT:
param->var.out_param = true;
param->var.in_param = true;
break;
}
if (!may_be_pointer && type->type_kind != TYPE_SLICE)

View File

@@ -792,7 +792,7 @@ CHECK_INNER:
if (inner->expr_kind != EXPR_IDENTIFIER) return true;
Decl *decl = inner->ident_expr;
if (decl->decl_kind != DECL_VAR) return true;
if (!decl->var.in_param) return true;
if (!decl->var.in_param || decl->var.out_param) return true;
RETURN_SEMA_ERROR(inner, "'in' parameters may not be assigned to.");
}
@@ -1902,21 +1902,21 @@ static inline bool sema_call_check_contract_param_match(SemaContext *context, De
{
if (expr->unary_expr.expr->ident_expr->var.kind == VARDECL_CONST && param->var.out_param)
{
SEMA_ERROR(expr, "A const parameter may not be passed into a function or macro as an 'out' argument.");
SEMA_ERROR(expr, "A const parameter may not be passed into a function or macro as an 'out' or 'inout' argument.");
return false;
}
}
if (expr->expr_kind != EXPR_IDENTIFIER) return true;
Decl *ident = expr->ident_expr;
if (ident->decl_kind != DECL_VAR) return true;
if (ident->var.out_param && param->var.in_param)
if (ident->var.out_param && !ident->var.in_param && param->var.in_param)
{
SEMA_ERROR(expr, "An 'out' parameter may not be passed into a function or macro as an 'in' argument.");
SEMA_ERROR(expr, "An 'out' parameter may not be passed into a function or macro as an 'in' or 'inout' argument.");
return false;
}
if (ident->var.in_param && param->var.out_param)
if (ident->var.in_param && !ident->var.out_param && param->var.out_param)
{
SEMA_ERROR(expr, "An 'in' parameter may not be passed into a function or macro as an 'out' argument.");
SEMA_ERROR(expr, "An 'in' parameter may not be passed into a function or macro as an 'out' or 'inout' argument.");
return false;
}
return true;
@@ -10170,7 +10170,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr, bool mutat
if (inner->expr_kind != EXPR_IDENTIFIER) break;
Decl *decl = inner->ident_expr;
if (decl->decl_kind != DECL_VAR) break;
if (!decl->var.out_param) break;
if (!decl->var.out_param || decl->var.in_param) break;
RETURN_SEMA_ERROR(expr, "'out' parameters may not be read.");
}
case EXPR_UNARY:
@@ -10180,7 +10180,7 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr, bool mutat
if (inner->expr_kind != EXPR_IDENTIFIER) break;
Decl *decl = inner->ident_expr;
if (decl->decl_kind != DECL_VAR) break;
if (!decl->var.out_param) break;
if (!decl->var.out_param || decl->var.in_param) break;
RETURN_SEMA_ERROR(expr, "'out' parameters may not be read.");
}
default:

View File

@@ -1887,13 +1887,6 @@ void target_setup(BuildTarget *target)
error_exit("Failed to find Windows def file: '%s' in path.", target->win.def);
}
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT) target->arch_os_target = default_target;
if (target->arch_os_target == ARCH_OS_TARGET_DEFAULT)
{
error_exit("Unable to detect the default target, please set an explicit --target value.");
}
if (target->arch_os_target == ELF_XTENSA && !XTENSA_AVAILABLE)
{
error_exit("Xtensa support is not available with this LLVM version.");

View File

@@ -393,6 +393,8 @@ fn void test_file(Path file_path)
cmdline.push(compiler_path.str_view());
cmdline.push("compile-only");
cmdline.push("--test");
cmdline.push("--llvm-out");
cmdline.push(".");
foreach (file : settings.input_files)
{
cmdline.push(file.name);

View File

@@ -8,7 +8,7 @@ fn void bar(Foo* f)
<* @param [in] f *>
fn void foo(Foo* f)
{
bar(f); // #error: macro as an 'out' argument
bar(f); // #error: An 'in' parameter may not be passed i
}
<* @param [in] f *>

View File

@@ -0,0 +1,21 @@
<*
@param [in] foo
*>
fn void test(int* foo)
{
test2(foo); // #error: An 'in' parameter may not be passed into
}
<*
@param [out] foo
*>
fn void test3(int* foo)
{
test2(foo); // #error: An 'out' parameter may not be passed into
}
<*
@param [inout] foo
*>
fn void test2(int* foo)
{
}