C-style c_varargs (Not heavily tested)

This commit is contained in:
Ginger Bill
2017-06-13 21:00:42 +01:00
parent e7fc24e48c
commit c3b510c2d9
7 changed files with 202 additions and 55 deletions

View File

@@ -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];