aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgingerBill <gingerBill@users.noreply.github.com>2026-01-15 17:28:28 +0000
committergingerBill <gingerBill@users.noreply.github.com>2026-01-15 17:28:28 +0000
commit5f07055ac1548e6254651f40a23e74093a9bebfe (patch)
tree62d3123463beb55f8be5c1a32f177be08888ee4f
parent0366cd3304b3910a397c4989e46bee4c575adeec (diff)
Add `#must_tail` and `"preserve/none"` calling convention
-rw-r--r--src/check_expr.cpp13
-rw-r--r--src/llvm_backend.hpp3
-rw-r--r--src/llvm_backend_proc.cpp6
-rw-r--r--src/parser.cpp3
-rw-r--r--src/parser.hpp2
-rw-r--r--src/types.cpp38
6 files changed, 21 insertions, 44 deletions
diff --git a/src/check_expr.cpp b/src/check_expr.cpp
index 3b470cb88..74ae02f94 100644
--- a/src/check_expr.cpp
+++ b/src/check_expr.cpp
@@ -8426,11 +8426,14 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
break;
case ProcTailing_must_tail:
is_call_tailed = true;
- if (proc != nullptr) {
- Entity *e = entity_from_expr(proc);
- if (e != nullptr && e->kind == Entity_Procedure) {
- // TODO(bill): `preserve_none`
- }
+ 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;
}
diff --git a/src/llvm_backend.hpp b/src/llvm_backend.hpp
index 9db7e94d9..884b87998 100644
--- a/src/llvm_backend.hpp
+++ b/src/llvm_backend.hpp
@@ -671,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,
@@ -724,6 +725,8 @@ lbCallingConventionKind const lb_calling_convention_map[ProcCC_MAX] = {
lbCallingConvention_Win64, // ProcCC_Win64,
lbCallingConvention_X86_64_SysV, // ProcCC_SysV,
+ lbCallingConvention_PreserveNone, // ProcCC_PreserveNone,
+
};
enum : LLVMDWARFTypeEncoding {
diff --git a/src/llvm_backend_proc.cpp b/src/llvm_backend_proc.cpp
index 0703941c1..9ac51bba3 100644
--- a/src/llvm_backend_proc.cpp
+++ b/src/llvm_backend_proc.cpp
@@ -179,12 +179,6 @@ gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool i
}
}
- switch (p->tailing) {
- case ProcTailing_must_tail:
- lb_add_attribute_to_proc(m, p->value, "preserve_none");
- break;
- }
-
switch (entity->Procedure.optimization_mode) {
case ProcedureOptimizationMode_None:
lb_add_attribute_to_proc(m, p->value, "optnone");
diff --git a/src/parser.cpp b/src/parser.cpp
index d8a9df473..8782b3a2b 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -2216,6 +2216,7 @@ gb_internal Ast *parse_inlining_or_tailing_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;
@@ -4020,6 +4021,8 @@ 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 == "system") {
if (build_context.metrics.os == TargetOs_windows) {
return ProcCC_StdCall;
diff --git a/src/parser.hpp b/src/parser.hpp
index 30b11c730..77d38b291 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -301,6 +301,7 @@ enum ProcCallingConvention : i32 {
ProcCC_Win64 = 9,
ProcCC_SysV = 10,
+ ProcCC_PreserveNone = 11,
ProcCC_MAX,
@@ -320,6 +321,7 @@ gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
"inlineasm",
"win64",
"sysv",
+ "preserve/none",
};
gb_internal ProcCallingConvention default_calling_convention(void) {
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);