From c3b510c2d9adf1a9281285fc711a28187288af75 Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Tue, 13 Jun 2017 21:00:42 +0100 Subject: C-style `c_vararg`s (Not heavily tested) --- src/check_expr.cpp | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) (limited to 'src/check_expr.cpp') diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 2f43197c8..eff8035c1 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -1049,6 +1049,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari } bool is_variadic = false; + bool is_c_vararg = false; Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count); isize variable_index = 0; for_array(i, params) { @@ -1114,10 +1115,19 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari if (p->flags&FieldFlag_no_alias) { if (!is_type_pointer(type)) { - error_node(params[i], "`no_alias` can only be applied to fields of pointer type"); + error_node(params[i], "`#no_alias` can only be applied to fields of pointer type"); p->flags &= ~FieldFlag_no_alias; // Remove the flag } } + if (p->flags&FieldFlag_c_vararg) { + if (p->type == NULL || + p->type->kind != AstNode_Ellipsis) { + error_node(params[i], "`#c_vararg` can only be applied to variadic type fields"); + p->flags &= ~FieldFlag_c_vararg; // Remove the flag + } else { + is_c_vararg = true; + } + } for_array(j, p->names) { AstNode *name = p->names[j]; @@ -1145,6 +1155,9 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari Entity *end = variables[variable_count-1]; end->type = make_type_slice(c->allocator, end->type); end->flags |= EntityFlag_Ellipsis; + if (is_c_vararg) { + end->flags |= EntityFlag_CVarArg; + } } Type *tuple = make_type_tuple(c->allocator); @@ -1409,6 +1422,19 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) { type->Proc.variadic = variadic; type->Proc.calling_convention = pt->calling_convention; + if (param_count > 0) { + Entity *end = params->Tuple.variables[param_count-1]; + if (end->flags&EntityFlag_CVarArg) { + if (pt->calling_convention == ProcCC_Odin) { + error(end->token, "Odin calling convention does not support #c_vararg"); + } else if (pt->calling_convention == ProcCC_Fast) { + error(end->token, "Fast calling convention does not support #c_vararg"); + } else { + type->Proc.c_vararg = true; + } + } + } + type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count); for (isize i = 0; i < param_count; i++) { @@ -4865,6 +4891,15 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { if (score_) *score_ = score; return CallArgumentError_NonVariadicExpand; } + if (vari_expand && proc_type->Proc.c_vararg) { + if (show_error) { + error(ce->ellipsis, + "Cannot use `..` in call to a `#c_vararg` variadic procedure: `%.*s`", + LIT(ce->proc->Ident.string)); + } + if (score_) *score_ = score; + return CallArgumentError_NonVariadicExpand; + } if (operands.count == 0 && param_count_excluding_defaults == 0) { if (score_) *score_ = score; @@ -6566,6 +6601,9 @@ gbString write_expr_to_string(gbString str, AstNode *node) { if (f->flags&FieldFlag_no_alias) { str = gb_string_appendc(str, "#no_alias "); } + if (f->flags&FieldFlag_c_vararg) { + str = gb_string_appendc(str, "#c_vararg "); + } for_array(i, f->names) { AstNode *name = f->names[i]; -- cgit v1.2.3