aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2026-01-22 11:47:23 +0100
committerGitHub <noreply@github.com>2026-01-22 11:47:23 +0100
commit3f8a32aeb963e056ac7709c26f05a99fb884ef95 (patch)
tree4eed35fa23e9f4c5b7dedc6a355b16f5d3119661 /src
parentfb479b3aaec5a9a715bcff7d65498ba18020f4f0 (diff)
parent5c09550d383df49a1d29d8f66bc1c45ee3be1136 (diff)
Merge branch 'master' into xmlcomment
Diffstat (limited to 'src')
-rw-r--r--src/build_settings.cpp11
-rw-r--r--src/check_builtin.cpp10
-rw-r--r--src/check_decl.cpp1
-rw-r--r--src/check_expr.cpp50
-rw-r--r--src/checker.cpp6
-rw-r--r--src/checker.hpp1
-rw-r--r--src/entity.cpp1
-rw-r--r--src/linker.cpp16
-rw-r--r--src/llvm_backend.cpp12
-rw-r--r--src/llvm_backend.hpp8
-rw-r--r--src/llvm_backend_proc.cpp48
-rw-r--r--src/main.cpp12
-rw-r--r--src/parser.cpp28
-rw-r--r--src/parser.hpp19
-rw-r--r--src/types.cpp38
15 files changed, 200 insertions, 61 deletions
diff --git a/src/build_settings.cpp b/src/build_settings.cpp
index 7160f3721..7d43788cd 100644
--- a/src/build_settings.cpp
+++ b/src/build_settings.cpp
@@ -582,6 +582,7 @@ struct BuildContext {
RelocMode reloc_mode;
bool disable_red_zone;
+ bool disable_unwind;
isize max_error_count;
@@ -839,6 +840,15 @@ gb_global TargetMetrics target_freestanding_amd64_win64 = {
TargetABI_Win64,
};
+gb_global TargetMetrics target_freestanding_amd64_mingw = {
+ TargetOs_freestanding,
+ TargetArch_amd64,
+ 8, 8, AMD64_MAX_ALIGNMENT, 32,
+ str_lit("x86_64-pc-windows-gnu"),
+ TargetABI_Win64,
+};
+
+
gb_global TargetMetrics target_freestanding_arm64 = {
TargetOs_freestanding,
TargetArch_arm64,
@@ -901,6 +911,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
{ str_lit("freestanding_amd64_win64"), &target_freestanding_amd64_win64 },
+ { str_lit("freestanding_amd64_mingw"), &target_freestanding_amd64_mingw },
{ str_lit("freestanding_arm64"), &target_freestanding_arm64 },
{ str_lit("freestanding_arm32"), &target_freestanding_arm32 },
diff --git a/src/check_builtin.cpp b/src/check_builtin.cpp
index 1b3e6912c..929891826 100644
--- a/src/check_builtin.cpp
+++ b/src/check_builtin.cpp
@@ -2695,6 +2695,16 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
case BuiltinProc_size_of: {
// size_of :: proc(Type or expr) -> untyped int
+ if (ce->args[0]->kind == Ast_UnaryExpr) {
+ ast_node(arg, UnaryExpr, ce->args[0]);
+ if (arg->op.kind == Token_And) {
+ ERROR_BLOCK();
+
+ warning(ce->args[0], "'size_of(&x)' returns the size of a pointer, not the size of x");
+ error_line("\tSuggestion: Use 'size_of(rawptr)' if you want the size of the pointer");
+ }
+ }
+
Operand o = {};
check_expr_or_type(c, &o, ce->args[0]);
if (o.mode == Addressing_Invalid) {
diff --git a/src/check_decl.cpp b/src/check_decl.cpp
index 27babd255..8019d00c3 100644
--- a/src/check_decl.cpp
+++ b/src/check_decl.cpp
@@ -1473,6 +1473,7 @@ gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
e->Procedure.no_sanitize_address = ac.no_sanitize_address;
e->Procedure.no_sanitize_memory = ac.no_sanitize_memory;
+ e->Procedure.no_sanitize_thread = ac.no_sanitize_thread;
e->deprecated_message = ac.deprecated_message;
e->warning_message = ac.warning_message;
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 2b2ae09cc..99f803a08 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -1133,7 +1133,11 @@ gb_internal void check_assignment(CheckerContext *c, Operand *operand, Type *typ
x.mode = Addressing_Value;
x.type = t;
if (check_is_assignable_to(c, &x, type)) {
- add_entity_use(c, operand->expr, e);
+ if (operand->expr->kind == Ast_SelectorExpr) {
+ add_entity_use(c, operand->expr->SelectorExpr.selector, e);
+ } else {
+ add_entity_use(c, operand->expr, e);
+ }
good = true;
break;
}
@@ -3528,7 +3532,7 @@ gb_internal bool check_cast_internal(CheckerContext *c, Operand *x, Type *type)
if (core_type(bt)->kind == Type_Basic) {
return check_representable_as_constant(c, x->value, type, &x->value) ||
(is_type_pointer(type) && check_is_castable_to(c, x, type));
- } else if (!are_types_identical(elem, bt) && elem->kind == Type_Basic) {
+ } else if (!are_types_identical(elem, bt) && elem->kind == Type_Basic && x->type->kind == Type_Basic) {
return check_representable_as_constant(c, x->value, elem, &x->value) ||
(is_type_pointer(elem) && check_is_castable_to(c, x, elem));
} else if (check_is_castable_to(c, x, type)) {
@@ -8210,7 +8214,7 @@ gb_internal void check_objc_call_expr(CheckerContext *c, Operand *operand, Ast *
add_objc_proc_type(c, call, return_type, param_types);
}
-gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, Type *type_hint) {
+gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *proc, Slice<Ast *> const &args, ProcInlining inlining, ProcTailing tailing, Type *type_hint) {
if (proc != nullptr &&
proc->kind == Ast_BasicDirective) {
ast_node(bd, BasicDirective, proc);
@@ -8241,7 +8245,10 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
return Expr_Expr;
}
if (inlining != ProcInlining_none) {
- error(call, "Inlining operators are not allowed on built-in procedures");
+ error(call, "Inlining directives are not allowed on built-in procedures");
+ }
+ if (tailing != ProcTailing_none) {
+ error(call, "Tailing directives are not allowed on built-in procedures");
}
} else {
if (proc != nullptr) {
@@ -8383,6 +8390,7 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
}
bool is_call_inlined = false;
+ bool is_call_tailed = true;
switch (inlining) {
case ProcInlining_inline:
@@ -8417,6 +8425,23 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
}
}
+ switch (tailing) {
+ case ProcTailing_none:
+ break;
+ case ProcTailing_must_tail:
+ is_call_tailed = true;
+ if (c->curr_proc_sig == nullptr || !are_types_identical(c->curr_proc_sig, pt)) {
+ ERROR_BLOCK();
+ gbString a = type_to_string(pt);
+ gbString b = type_to_string(c->curr_proc_sig);
+ error(call, "Use of '#must_tail' of a procedure must have the same type as the procedure it was called within");
+ error_line("\tCall type: %s, parent type: %s", a, b);
+ gb_string_free(b);
+ gb_string_free(a);
+ }
+ break;
+ }
+
{
String invalid;
if (pt->kind == Type_Proc && pt->Proc.require_target_feature.len != 0) {
@@ -11554,6 +11579,15 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
return kind;
case_end;
+ case_ast_node(ht, HelperType, node);
+ Type *type = check_type(c, ht->type);
+ if (type != nullptr && type != t_invalid) {
+ o->mode = Addressing_Type;
+ o->type = type;
+ }
+ return kind;
+ case_end;
+
case_ast_node(i, Implicit, node);
switch (i->kind) {
case Token_context:
@@ -11816,7 +11850,7 @@ gb_internal ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast
case_end;
case_ast_node(ce, CallExpr, node);
- return check_call_expr(c, o, node, ce->proc, ce->args, ce->inlining, type_hint);
+ return check_call_expr(c, o, node, ce->proc, ce->args, ce->inlining, ce->tailing, type_hint);
case_end;
case_ast_node(de, DerefExpr, node);
@@ -12557,6 +12591,12 @@ gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthan
case_end;
case_ast_node(ce, CallExpr, node);
+ switch (ce->tailing) {
+ case ProcTailing_must_tail:
+ str = gb_string_appendc(str, "#must_tail ");
+ break;
+ }
+
switch (ce->inlining) {
case ProcInlining_inline:
str = gb_string_appendc(str, "#force_inline ");
diff --git a/src/checker.cpp b/src/checker.cpp
index ab3ba50dd..453f3e241 100644
--- a/src/checker.cpp
+++ b/src/checker.cpp
@@ -3990,6 +3990,12 @@ gb_internal DECL_ATTRIBUTE_PROC(proc_decl_attribute) {
}
ac->no_sanitize_memory = true;
return true;
+ } else if (name == "no_sanitize_thread") {
+ if (value != nullptr) {
+ error(value, "'%.*s' expects no parameter", LIT(name));
+ }
+ ac->no_sanitize_thread = true;
+ return true;
}
return false;
}
diff --git a/src/checker.hpp b/src/checker.hpp
index bda7b2746..f9c279a51 100644
--- a/src/checker.hpp
+++ b/src/checker.hpp
@@ -141,6 +141,7 @@ struct AttributeContext {
bool instrumentation_exit : 1;
bool no_sanitize_address : 1;
bool no_sanitize_memory : 1;
+ bool no_sanitize_thread : 1;
bool rodata : 1;
bool ignore_duplicates : 1;
u32 optimization_mode; // ProcedureOptimizationMode
diff --git a/src/entity.cpp b/src/entity.cpp
index 2b21fdcac..55aca8069 100644
--- a/src/entity.cpp
+++ b/src/entity.cpp
@@ -268,6 +268,7 @@ struct Entity {
bool is_anonymous : 1;
bool no_sanitize_address : 1;
bool no_sanitize_memory : 1;
+ bool no_sanitize_thread : 1;
bool is_objc_impl_or_import : 1;
bool is_objc_class_method : 1;
} Procedure;
diff --git a/src/linker.cpp b/src/linker.cpp
index c2a3ee928..c68417994 100644
--- a/src/linker.cpp
+++ b/src/linker.cpp
@@ -737,7 +737,21 @@ try_cross_linking:;
}
if (build_context.build_mode == BuildMode_StaticLibrary) {
- compiler_error("TODO(bill): -build-mode:static on non-windows targets");
+ TIME_SECTION("Static Library Creation");
+
+ gbString ar_command = gb_string_make(heap_allocator(), "");
+ defer (gb_string_free(ar_command));
+
+ ar_command = gb_string_appendc(ar_command, "ar rcs ");
+ ar_command = gb_string_append_fmt(ar_command, "\"%.*s\" ", LIT(output_filename));
+ ar_command = gb_string_appendc(ar_command, object_files);
+
+ result = system_exec_command_line_app("ar", ar_command);
+ if (result) {
+ return result;
+ }
+
+ return result;
}
// NOTE(dweiler): We use clang as a frontend for the linker as there are
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index 1cde65640..0bf3d1125 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -2111,7 +2111,7 @@ gb_internal void lb_create_startup_runtime_generate_body(lbModule *m, lbProcedur
for (Entity *e : info->init_procedures) {
lbValue value = lb_find_procedure_value_from_entity(m, e);
- lb_emit_call(p, value, {}, ProcInlining_none);
+ lb_emit_call(p, value, {}, ProcInlining_none, ProcTailing_none);
}
@@ -2157,7 +2157,7 @@ gb_internal lbProcedure *lb_create_cleanup_runtime(lbModule *main_module) { // C
for (Entity *e : info->fini_procedures) {
lbValue value = lb_find_procedure_value_from_entity(main_module, e);
- lb_emit_call(p, value, {}, ProcInlining_none);
+ lb_emit_call(p, value, {}, ProcInlining_none, ProcTailing_none);
}
lb_end_procedure_body(p);
@@ -2850,7 +2850,7 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
}
lbValue startup_runtime_value = {startup_runtime->value, startup_runtime->type};
- lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none);
+ lb_emit_call(p, startup_runtime_value, {}, ProcInlining_none, ProcTailing_none);
if (build_context.command_kind == Command_test) {
Type *t_Internal_Test = find_type_in_pkg(m->info, str_lit("testing"), str_lit("Internal_Test"));
@@ -2917,16 +2917,16 @@ gb_internal lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *star
auto exit_args = array_make<lbValue>(temporary_allocator(), 1);
exit_args[0] = lb_emit_select(p, result, lb_const_int(m, t_int, 0), lb_const_int(m, t_int, 1));
- lb_emit_call(p, exit_runner, exit_args, ProcInlining_none);
+ lb_emit_call(p, exit_runner, exit_args, ProcInlining_none, ProcTailing_none);
} else {
if (m->info->entry_point != nullptr) {
lbValue entry_point = lb_find_procedure_value_from_entity(m, m->info->entry_point);
- lb_emit_call(p, entry_point, {}, ProcInlining_no_inline);
+ lb_emit_call(p, entry_point, {}, ProcInlining_no_inline, ProcTailing_none);
}
if (call_cleanup) {
lbValue cleanup_runtime_value = {cleanup_runtime->value, cleanup_runtime->type};
- lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none);
+ lb_emit_call(p, cleanup_runtime_value, {}, ProcInlining_none, ProcTailing_none);
}
if (is_dll_main) {
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index da5d91f2e..e10471527 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -345,6 +345,7 @@ struct lbProcedure {
Ast * body;
u64 tags;
ProcInlining inlining;
+ ProcTailing tailing;
bool is_foreign;
bool is_export;
bool is_entry_point;
@@ -484,7 +485,7 @@ gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlo
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, Ast *node);
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
-gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
+gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none, ProcTailing tailing = ProcTailing_none);
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
@@ -670,6 +671,7 @@ enum lbCallingConventionKind : unsigned {
lbCallingConvention_PreserveAll = 15,
lbCallingConvention_Swift = 16,
lbCallingConvention_CXX_FAST_TLS = 17,
+ lbCallingConvention_PreserveNone = 21,
lbCallingConvention_FirstTargetCC = 64,
lbCallingConvention_X86_StdCall = 64,
lbCallingConvention_X86_FastCall = 65,
@@ -723,6 +725,10 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = {
lbCallingConvention_Win64, // ProcCC_Win64,
lbCallingConvention_X86_64_SysV, // ProcCC_SysV,
+ lbCallingConvention_PreserveNone, // ProcCC_PreserveNone,
+ lbCallingConvention_PreserveMost, // ProcCC_PreserveMost,
+ lbCallingConvention_PreserveAll, // ProcCC_PreserveAll,
+
};
enum : LLVMDWARFTypeEncoding {
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 216d600da..640a43111 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -117,6 +117,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
p->type_expr = decl->type_expr;
p->body = pl->body;
p->inlining = pl->inlining;
+ p->tailing = pl->tailing;
p->is_foreign = entity->Procedure.is_foreign;
p->is_export = entity->Procedure.is_export;
p->is_entry_point = false;
@@ -152,6 +153,10 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
lb_ensure_abi_function_type(m, p);
lb_add_function_type_attributes(p->value, p->abi_function_type, p->abi_function_type->calling_convention);
+ if (build_context.disable_unwind) {
+ lb_add_attribute_to_proc(m, p->value, "nounwind");
+ }
+
if (pt->Proc.diverging) {
lb_add_attribute_to_proc(m, p->value, "noreturn");
}
@@ -346,7 +351,7 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
if (build_context.sanitizer_flags & SanitizerFlag_Memory && !entity->Procedure.no_sanitize_memory) {
lb_add_attribute_to_proc(m, p->value, "sanitize_memory");
}
- if (build_context.sanitizer_flags & SanitizerFlag_Thread) {
+ if (build_context.sanitizer_flags & SanitizerFlag_Thread && !entity->Procedure.no_sanitize_thread) {
lb_add_attribute_to_proc(m, p->value, "sanitize_thread");
}
}
@@ -387,6 +392,7 @@ gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name
p->body = nullptr;
p->tags = 0;
p->inlining = ProcInlining_none;
+ p->tailing = ProcTailing_none;
p->is_foreign = false;
p->is_export = false;
p->is_entry_point = false;
@@ -855,7 +861,7 @@ gb_internal Array<lbValue> lb_value_to_array(lbProcedure *p, gbAllocator const &
-gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) {
+gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining, ProcTailing tailing) {
GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value)));
unsigned arg_count = cast(unsigned)processed_args.count;
@@ -972,6 +978,15 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue
break;
}
+ switch (tailing) {
+ case ProcTailing_none:
+ break;
+ case ProcTailing_must_tail:
+ LLVMSetTailCall(ret, true);
+ LLVMSetTailCallKind(ret, LLVMTailCallKindMustTail);
+ break;
+ }
+
lbValue res = {};
res.value = ret;
res.type = abi_rt;
@@ -1045,7 +1060,7 @@ gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
return lb_emit_load(p, res);
}
-gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining) {
+gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, ProcTailing tailing) {
lbModule *m = p->module;
Type *pt = base_type(value.type);
@@ -1168,10 +1183,10 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
if (return_by_pointer) {
lbValue return_ptr = lb_add_local_generated(p, rt, true).addr;
- lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
+ lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining, tailing);
result = lb_emit_load(p, return_ptr);
} else if (rt != nullptr) {
- result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining);
+ result = lb_emit_call_internal(p, value, {}, processed_args, rt, context_ptr, inlining, tailing);
if (ft->ret.cast_type) {
result.value = OdinLLVMBuildTransmute(p, result.value, ft->ret.cast_type);
}
@@ -1184,7 +1199,7 @@ gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> c
result = lb_emit_conv(p, result, rt);
}
} else {
- lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining);
+ lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining, tailing);
}
if (original_rt != rt) {
@@ -4402,6 +4417,25 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
return lb_handle_objc_auto_send(p, expr, slice(call_args, 0, call_args.count));
}
- return lb_emit_call(p, value, call_args, ce->inlining);
+
+ ProcInlining inlining = ce->inlining;
+ ProcTailing tailing = ce->tailing;
+
+ if (tailing == ProcTailing_none &&
+ proc_entity && proc_entity->kind == Entity_Procedure &&
+ proc_entity->decl_info &&
+ proc_entity->decl_info->proc_lit) {
+ ast_node(pl, ProcLit, proc_entity->decl_info->proc_lit);
+
+ if (pl->inlining != ProcInlining_none) {
+ inlining = pl->inlining;
+ }
+
+ if (pl->tailing != ProcTailing_none) {
+ tailing = pl->tailing;
+ }
+ }
+
+ return lb_emit_call(p, value, call_args, inlining, tailing);
}
diff --git a/src/main.cpp b/src/main.cpp
index 9a5df8aea..753f58986 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -363,6 +363,8 @@ enum BuildFlagKind {
BuildFlag_RelocMode,
BuildFlag_DisableRedZone,
+ BuildFlag_DisableUnwind,
+
BuildFlag_DisallowDo,
BuildFlag_DefaultToNilAllocator,
BuildFlag_DefaultToPanicAllocator,
@@ -592,6 +594,8 @@ gb_internal bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build);
+ add_flag(&build_flags, BuildFlag_DisableUnwind, str_lit("disable-unwind"), BuildFlagParam_None, Command__does_build);
+
add_flag(&build_flags, BuildFlag_DisallowDo, str_lit("disallow-do"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DefaultToNilAllocator, str_lit("default-to-nil-allocator"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_DefaultToPanicAllocator, str_lit("default-to-panic-allocator"),BuildFlagParam_None, Command__does_check);
@@ -1424,6 +1428,10 @@ gb_internal bool parse_build_flags(Array<String> args) {
case BuildFlag_DisableRedZone:
build_context.disable_red_zone = true;
break;
+ case BuildFlag_DisableUnwind:
+ build_context.disable_unwind = true;
+ break;
+
case BuildFlag_DisallowDo:
build_context.disallow_do = true;
break;
@@ -2971,6 +2979,10 @@ gb_internal int print_show_help(String const arg0, String command, String option
if (check) {
if (print_flag("-target:<string>")) {
print_usage_line(2, "Sets the target for the executable to be built in.");
+ print_usage_line(2, "Examples:");
+ print_usage_line(3, "-target:linux_amd64");
+ print_usage_line(3, "-target:windows_amd64");
+ print_usage_line(3, "-target:\"?\" for a list");
}
if (print_flag("-terse-errors")) {
diff --git a/src/parser.cpp b/src/parser.cpp
index 823021e04..fc55dae97 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -2176,7 +2176,7 @@ gb_internal bool ast_on_same_line(Token const &x, Ast *yp) {
return x.pos.line == y.pos.line;
}
-gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) {
+gb_internal Ast *parse_inlining_or_tailing_operand(AstFile *f, Token token) {
Ast *expr = parse_unary_expr(f, false);
Ast *e = strip_or_return_expr(expr);
if (e == nullptr) {
@@ -2187,11 +2187,14 @@ gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) {
return ast_bad_expr(f, token, f->curr_token);
}
ProcInlining pi = ProcInlining_none;
+ ProcTailing pt = ProcTailing_none;
if (token.kind == Token_Ident) {
if (token.string == "force_inline") {
pi = ProcInlining_inline;
} else if (token.string == "force_no_inline") {
pi = ProcInlining_no_inline;
+ } else if (token.string == "must_tail") {
+ pt = ProcTailing_must_tail;
}
}
@@ -2211,6 +2214,15 @@ gb_internal Ast *parse_force_inlining_operand(AstFile *f, Token token) {
}
}
+ if (pt != ProcTailing_none) {
+ if (e->kind == Ast_ProcLit) {
+ syntax_error(expr, "'#must_call' can only be applied to a procedure call, not the procedure literal");
+ e->ProcLit.tailing = pt;
+ } else if (e->kind == Ast_CallExpr) {
+ e->CallExpr.tailing = pt;
+ }
+ }
+
return expr;
}
@@ -2507,8 +2519,9 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
syntax_error(tag, "#relative types have now been removed in favour of \"core:relative\"");
return ast_relative_type(f, tag, type);
} else if (name.string == "force_inline" ||
- name.string == "force_no_inline") {
- return parse_force_inlining_operand(f, name);
+ name.string == "force_no_inline" ||
+ name.string == "must_tail") {
+ return parse_inlining_or_tailing_operand(f, name);
}
return ast_basic_directive(f, token, name);
}
@@ -4008,6 +4021,10 @@ gb_internal ProcCallingConvention string_to_calling_convention(String const &s)
if (s == "win64") return ProcCC_Win64;
if (s == "sysv") return ProcCC_SysV;
+ if (s == "preserve/none") return ProcCC_PreserveNone;
+ if (s == "preserve/most") return ProcCC_PreserveMost;
+ if (s == "preserve/all") return ProcCC_PreserveAll;
+
if (s == "system") {
if (build_context.metrics.os == TargetOs_windows) {
return ProcCC_StdCall;
@@ -5399,8 +5416,9 @@ gb_internal Ast *parse_stmt(AstFile *f) {
expect_semicolon(f);
return stmt;
} else if (name.string == "force_inline" ||
- name.string == "force_no_inline") {
- Ast *expr = parse_force_inlining_operand(f, name);
+ name.string == "force_no_inline" ||
+ name.string == "must_tail") {
+ Ast *expr = parse_inlining_or_tailing_operand(f, name);
Ast *stmt = ast_expr_stmt(f, expr);
expect_semicolon(f);
return stmt;
diff --git a/src/parser.hpp b/src/parser.hpp
index 71b61d95f..011330438 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -263,12 +263,17 @@ struct ForeignFileWorkerData {
-enum ProcInlining {
- ProcInlining_none = 0,
- ProcInlining_inline = 1,
+enum ProcInlining : u8 {
+ ProcInlining_none = 0,
+ ProcInlining_inline = 1,
ProcInlining_no_inline = 2,
};
+enum ProcTailing : u8 {
+ ProcTailing_none = 0,
+ ProcTailing_must_tail = 1,
+};
+
enum ProcTag {
ProcTag_bounds_check = 1<<0,
ProcTag_no_bounds_check = 1<<1,
@@ -296,6 +301,9 @@ enum ProcCallingConvention : i32 {
ProcCC_Win64 = 9,
ProcCC_SysV = 10,
+ ProcCC_PreserveNone = 11,
+ ProcCC_PreserveMost = 12,
+ ProcCC_PreserveAll = 13,
ProcCC_MAX,
@@ -315,6 +323,9 @@ gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
"inlineasm",
"win64",
"sysv",
+ "preserve/none",
+ "preserve/most",
+ "preserve/all",
};
gb_internal ProcCallingConvention default_calling_convention(void) {
@@ -441,6 +452,7 @@ struct AstSplitArgs {
Ast *body; \
u64 tags; \
ProcInlining inlining; \
+ ProcTailing tailing; \
Token where_token; \
Slice<Ast *> where_clauses; \
DeclInfo *decl; \
@@ -486,6 +498,7 @@ AST_KIND(_ExprBegin, "", bool) \
Token close; \
Token ellipsis; \
ProcInlining inlining; \
+ ProcTailing tailing; \
bool optional_ok_one; \
bool was_selector; \
AstSplitArgs *split_args; \
diff --git a/src/types.cpp b/src/types.cpp
index 18e3b56ac..911cd4448 100644
--- a/src/types.cpp
+++ b/src/types.cpp
@@ -5210,40 +5210,12 @@ gb_internal gbString write_type_to_string(gbString str, Type *type, bool shortha
case Type_Proc:
str = gb_string_appendc(str, "proc");
- switch (type->Proc.calling_convention) {
- case ProcCC_Odin:
- if (default_calling_convention() != ProcCC_Odin) {
- str = gb_string_appendc(str, " \"odin\" ");
- }
- break;
- case ProcCC_Contextless:
- if (default_calling_convention() != ProcCC_Contextless) {
- str = gb_string_appendc(str, " \"contextless\" ");
- }
- break;
- case ProcCC_CDecl:
- str = gb_string_appendc(str, " \"c\" ");
- break;
- case ProcCC_StdCall:
- str = gb_string_appendc(str, " \"std\" ");
- break;
- case ProcCC_FastCall:
- str = gb_string_appendc(str, " \"fastcall\" ");
- break;
- break;
- case ProcCC_None:
- str = gb_string_appendc(str, " \"none\" ");
- break;
- case ProcCC_Naked:
- str = gb_string_appendc(str, " \"naked\" ");
- break;
- // case ProcCC_VectorCall:
- // str = gb_string_appendc(str, " \"vectorcall\" ");
- // break;
- // case ProcCC_ClrCall:
- // str = gb_string_appendc(str, " \"clrcall\" ");
- // break;
+ if (type->Proc.calling_convention != default_calling_convention()) {
+ str = gb_string_appendc(str, " \"");
+ str = gb_string_appendc(str, proc_calling_convention_strings[type->Proc.calling_convention]);
+ str = gb_string_appendc(str, "\" ");
}
+
str = gb_string_appendc(str, "(");
if (type->Proc.params) {
str = write_type_to_string(str, type->Proc.params, shorthand, allow_polymorphic);