mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 08:08:50 +00:00
C-style c_varargs (Not heavily tested)
This commit is contained in:
+6
-3
@@ -293,13 +293,16 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_foreign && is_export) {
|
if (is_foreign && is_export) {
|
||||||
error_node(pd->type, "You cannot apply both `foreign` and `export` to a procedure");
|
error_node(pd->type, "A foreign procedure cannot have an `export` tag");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pd->body != NULL) {
|
if (pd->body != NULL) {
|
||||||
if (is_foreign) {
|
if (is_foreign) {
|
||||||
error_node(pd->body, "A procedure tagged as `foreign` cannot have a body");
|
error_node(pd->body, "A foreign procedure cannot have a body");
|
||||||
|
}
|
||||||
|
if (proc_type->Proc.c_vararg) {
|
||||||
|
error_node(pd->body, "A procedure with a `#c_vararg` field cannot have a body");
|
||||||
}
|
}
|
||||||
|
|
||||||
d->scope = c->context.scope;
|
d->scope = c->context.scope;
|
||||||
@@ -360,7 +363,7 @@ void check_proc_decl(Checker *c, Entity *e, DeclInfo *d) {
|
|||||||
Type *other_type = base_type(f->type);
|
Type *other_type = base_type(f->type);
|
||||||
if (!are_signatures_similar_enough(this_type, other_type)) {
|
if (!are_signatures_similar_enough(this_type, other_type)) {
|
||||||
error_node(d->proc_decl,
|
error_node(d->proc_decl,
|
||||||
"Redeclaration of #foreign procedure `%.*s` with different type signatures\n"
|
"Redeclaration of foreign procedure `%.*s` with different type signatures\n"
|
||||||
"\tat %.*s(%td:%td)",
|
"\tat %.*s(%td:%td)",
|
||||||
LIT(name), LIT(pos.file), pos.line, pos.column);
|
LIT(name), LIT(pos.file), pos.line, pos.column);
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-1
@@ -1049,6 +1049,7 @@ Type *check_get_params(Checker *c, Scope *scope, AstNode *_params, bool *is_vari
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_variadic = false;
|
bool is_variadic = false;
|
||||||
|
bool is_c_vararg = false;
|
||||||
Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
|
Entity **variables = gb_alloc_array(c->allocator, Entity *, variable_count);
|
||||||
isize variable_index = 0;
|
isize variable_index = 0;
|
||||||
for_array(i, params) {
|
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 (p->flags&FieldFlag_no_alias) {
|
||||||
if (!is_type_pointer(type)) {
|
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
|
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) {
|
for_array(j, p->names) {
|
||||||
AstNode *name = p->names[j];
|
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];
|
Entity *end = variables[variable_count-1];
|
||||||
end->type = make_type_slice(c->allocator, end->type);
|
end->type = make_type_slice(c->allocator, end->type);
|
||||||
end->flags |= EntityFlag_Ellipsis;
|
end->flags |= EntityFlag_Ellipsis;
|
||||||
|
if (is_c_vararg) {
|
||||||
|
end->flags |= EntityFlag_CVarArg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *tuple = make_type_tuple(c->allocator);
|
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.variadic = variadic;
|
||||||
type->Proc.calling_convention = pt->calling_convention;
|
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);
|
type->Proc.abi_compat_params = gb_alloc_array(c->allocator, Type *, param_count);
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
@@ -4865,6 +4891,15 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) {
|
|||||||
if (score_) *score_ = score;
|
if (score_) *score_ = score;
|
||||||
return CallArgumentError_NonVariadicExpand;
|
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 (operands.count == 0 && param_count_excluding_defaults == 0) {
|
||||||
if (score_) *score_ = score;
|
if (score_) *score_ = score;
|
||||||
@@ -6566,6 +6601,9 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
|
|||||||
if (f->flags&FieldFlag_no_alias) {
|
if (f->flags&FieldFlag_no_alias) {
|
||||||
str = gb_string_appendc(str, "#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) {
|
for_array(i, f->names) {
|
||||||
AstNode *name = f->names[i];
|
AstNode *name = f->names[i];
|
||||||
|
|||||||
@@ -43,6 +43,9 @@ enum EntityFlag {
|
|||||||
EntityFlag_Value = 1<<9,
|
EntityFlag_Value = 1<<9,
|
||||||
EntityFlag_Sret = 1<<10,
|
EntityFlag_Sret = 1<<10,
|
||||||
EntityFlag_BitFieldValue = 1<<11,
|
EntityFlag_BitFieldValue = 1<<11,
|
||||||
|
|
||||||
|
EntityFlag_CVarArg = 1<<20,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Zero value means the overloading process is not yet done
|
// Zero value means the overloading process is not yet done
|
||||||
|
|||||||
+33
-4
@@ -1477,7 +1477,11 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_
|
|||||||
Type *results = pt->Proc.results;
|
Type *results = pt->Proc.results;
|
||||||
|
|
||||||
isize param_count = pt->Proc.param_count;
|
isize param_count = pt->Proc.param_count;
|
||||||
GB_ASSERT(param_count == arg_count);
|
if (pt->Proc.c_vararg) {
|
||||||
|
GB_ASSERT(param_count-1 <= arg_count);
|
||||||
|
} else {
|
||||||
|
GB_ASSERT(param_count == arg_count);
|
||||||
|
}
|
||||||
for (isize i = 0; i < param_count; i++) {
|
for (isize i = 0; i < param_count; i++) {
|
||||||
Type *original_type = pt->Proc.params->Tuple.variables[i]->type;
|
Type *original_type = pt->Proc.params->Tuple.variables[i]->type;
|
||||||
Type *new_type = pt->Proc.abi_compat_params[i];
|
Type *new_type = pt->Proc.abi_compat_params[i];
|
||||||
@@ -4649,6 +4653,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count));
|
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, gb_max(type->param_count, arg_count));
|
||||||
bool variadic = type->variadic;
|
bool variadic = type->variadic;
|
||||||
bool vari_expand = ce->ellipsis.pos.line != 0;
|
bool vari_expand = ce->ellipsis.pos.line != 0;
|
||||||
|
bool is_c_vararg = type->c_vararg;
|
||||||
|
|
||||||
for_array(i, ce->args) {
|
for_array(i, ce->args) {
|
||||||
irValue *a = ir_build_expr(proc, ce->args[i]);
|
irValue *a = ir_build_expr(proc, ce->args[i]);
|
||||||
@@ -4683,7 +4688,26 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (variadic) {
|
if (is_c_vararg) {
|
||||||
|
GB_ASSERT(variadic);
|
||||||
|
GB_ASSERT(!vari_expand);
|
||||||
|
isize i = 0;
|
||||||
|
for (; i < type->param_count-1; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
|
||||||
|
}
|
||||||
|
Type *variadic_type = pt->variables[i]->type;
|
||||||
|
GB_ASSERT(is_type_slice(variadic_type));
|
||||||
|
variadic_type = base_type(variadic_type)->Slice.elem;
|
||||||
|
if (!is_type_any(variadic_type)) {
|
||||||
|
for (; i < arg_count; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], variadic_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (; i < arg_count; i++) {
|
||||||
|
args[i] = ir_emit_conv(proc, args[i], default_type(ir_type(args[i])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (variadic) {
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
for (; i < type->param_count-1; i++) {
|
for (; i < type->param_count-1; i++) {
|
||||||
args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
|
args[i] = ir_emit_conv(proc, args[i], pt->variables[i]->type);
|
||||||
@@ -4702,7 +4726,12 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (variadic && !vari_expand) {
|
i64 final_count = type->param_count;
|
||||||
|
if (is_c_vararg) {
|
||||||
|
final_count = arg_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variadic && !vari_expand && !is_c_vararg) {
|
||||||
ir_emit_comment(proc, str_lit("variadic call argument generation"));
|
ir_emit_comment(proc, str_lit("variadic call argument generation"));
|
||||||
gbAllocator allocator = proc->module->allocator;
|
gbAllocator allocator = proc->module->allocator;
|
||||||
Type *slice_type = pt->variables[type->param_count-1]->type;
|
Type *slice_type = pt->variables[type->param_count-1]->type;
|
||||||
@@ -4727,7 +4756,7 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
|||||||
args[arg_count-1] = ir_emit_load(proc, slice);
|
args[arg_count-1] = ir_emit_load(proc, slice);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ir_emit_call(proc, value, args, type->param_count);
|
return ir_emit_call(proc, value, args, final_count);
|
||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(se, SliceExpr, expr);
|
case_ast_node(se, SliceExpr, expr);
|
||||||
|
|||||||
+95
-43
@@ -161,10 +161,11 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
isize count = rt->Tuple.variable_count;
|
isize count = rt->Tuple.variable_count;
|
||||||
ir_fprintf(f, "{");
|
ir_fprintf(f, "{");
|
||||||
for (isize i = 0; i < count; i++) {
|
for (isize i = 0; i < count; i++) {
|
||||||
|
Entity *e = rt->Tuple.variables[i];
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, rt->Tuple.variables[i]->type);
|
ir_print_type(f, m, e->type);
|
||||||
}
|
}
|
||||||
ir_fprintf(f, "}");
|
ir_fprintf(f, "}");
|
||||||
}
|
}
|
||||||
@@ -172,6 +173,35 @@ void ir_print_proc_results(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ir_print_proc_type_without_pointer(irFileBuffer *f, irModule *m, Type *t) {
|
||||||
|
i64 word_bits = 8*build_context.word_size;
|
||||||
|
t = base_type(t);
|
||||||
|
GB_ASSERT(is_type_proc(t));
|
||||||
|
|
||||||
|
isize param_count = t->Proc.param_count;
|
||||||
|
isize result_count = t->Proc.result_count;
|
||||||
|
ir_print_proc_results(f, m, t);
|
||||||
|
ir_fprintf(f, " (");
|
||||||
|
if (t->Proc.return_by_pointer) {
|
||||||
|
ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
|
||||||
|
ir_fprintf(f, "* sret noalias ");
|
||||||
|
if (param_count > 0) {
|
||||||
|
ir_fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (isize i = 0; i < param_count; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
ir_fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
if (i+1 == param_count && t->Proc.c_vararg) {
|
||||||
|
ir_fprintf(f, "...");
|
||||||
|
} else {
|
||||||
|
ir_print_type(f, m, t->Proc.abi_compat_params[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ir_fprintf(f, ")");
|
||||||
|
}
|
||||||
|
|
||||||
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
||||||
i64 word_bits = 8*build_context.word_size;
|
i64 word_bits = 8*build_context.word_size;
|
||||||
GB_ASSERT_NOT_NULL(t);
|
GB_ASSERT_NOT_NULL(t);
|
||||||
@@ -328,24 +358,8 @@ void ir_print_type(irFileBuffer *f, irModule *m, Type *t) {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case Type_Proc: {
|
case Type_Proc: {
|
||||||
isize param_count = t->Proc.param_count;
|
ir_print_proc_type_without_pointer(f, m, t);
|
||||||
isize result_count = t->Proc.result_count;
|
ir_fprintf(f, "*");
|
||||||
ir_print_proc_results(f, m, t);
|
|
||||||
ir_fprintf(f, " (");
|
|
||||||
if (t->Proc.return_by_pointer) {
|
|
||||||
ir_print_type(f, m, reduce_tuple_to_single_type(t->Proc.results));
|
|
||||||
ir_fprintf(f, "* sret noalias ");
|
|
||||||
if (param_count > 0) {
|
|
||||||
ir_fprintf(f, ", ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (isize i = 0; i < param_count; i++) {
|
|
||||||
if (i > 0) {
|
|
||||||
ir_fprintf(f, ", ");
|
|
||||||
}
|
|
||||||
ir_print_type(f, m, t->Proc.abi_compat_params[i]);
|
|
||||||
}
|
|
||||||
ir_fprintf(f, ")*");
|
|
||||||
} return;
|
} return;
|
||||||
|
|
||||||
case Type_Map: {
|
case Type_Map: {
|
||||||
@@ -1216,13 +1230,16 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
irInstrCall *call = &instr->Call;
|
irInstrCall *call = &instr->Call;
|
||||||
Type *proc_type = base_type(ir_type(call->value));
|
Type *proc_type = base_type(ir_type(call->value));
|
||||||
GB_ASSERT(is_type_proc(proc_type));
|
GB_ASSERT(is_type_proc(proc_type));
|
||||||
|
bool is_c_vararg = proc_type->Proc.c_vararg;
|
||||||
Type *result_type = call->type;
|
Type *result_type = call->type;
|
||||||
if (result_type) {
|
if (result_type) {
|
||||||
ir_fprintf(f, "%%%d = ", value->index);
|
ir_fprintf(f, "%%%d = ", value->index);
|
||||||
}
|
}
|
||||||
ir_fprintf(f, "call ");
|
ir_fprintf(f, "call ");
|
||||||
ir_print_calling_convention(f, m, proc_type->Proc.calling_convention);
|
ir_print_calling_convention(f, m, proc_type->Proc.calling_convention);
|
||||||
if (result_type && !proc_type->Proc.return_by_pointer) {
|
if (is_c_vararg) {
|
||||||
|
ir_print_proc_type_without_pointer(f, m, proc_type);
|
||||||
|
} else if (result_type && !proc_type->Proc.return_by_pointer) {
|
||||||
ir_print_proc_results(f, m, proc_type);
|
ir_print_proc_results(f, m, proc_type);
|
||||||
} else {
|
} else {
|
||||||
ir_fprintf(f, "void");
|
ir_fprintf(f, "void");
|
||||||
@@ -1242,24 +1259,55 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (call->arg_count > 0) {
|
if (call->arg_count > 0) {
|
||||||
Type *proc_type = base_type(ir_type(call->value));
|
Type *proc_type = base_type(ir_type(call->value));
|
||||||
GB_ASSERT(proc_type->kind == Type_Proc);
|
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||||
TypeTuple *params = &proc_type->Proc.params->Tuple;
|
TypeTuple *params = &proc_type->Proc.params->Tuple;
|
||||||
for (isize i = 0; i < call->arg_count; i++) {
|
if (proc_type->Proc.c_vararg) {
|
||||||
Entity *e = params->variables[i];
|
isize i = 0;
|
||||||
GB_ASSERT(e != NULL);
|
for (; i < params->variable_count-1; i++) {
|
||||||
Type *t = proc_type->Proc.abi_compat_params[i];
|
Entity *e = params->variables[i];
|
||||||
if (i > 0) {
|
GB_ASSERT(e != NULL);
|
||||||
ir_fprintf(f, ", ");
|
Type *t = proc_type->Proc.abi_compat_params[i];
|
||||||
|
if (i > 0) {
|
||||||
|
ir_fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
ir_print_type(f, m, t);
|
||||||
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
|
ir_fprintf(f, " noalias");
|
||||||
|
}
|
||||||
|
ir_fprintf(f, " ");
|
||||||
|
irValue *arg = call->args[i];
|
||||||
|
ir_print_value(f, m, arg, t);
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, t);
|
for (; i < call->arg_count; i++) {
|
||||||
if (e->flags&EntityFlag_NoAlias) {
|
if (i > 0) {
|
||||||
ir_fprintf(f, " noalias");
|
ir_fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
irValue *arg = call->args[i];
|
||||||
|
Type *t = ir_type(arg);
|
||||||
|
ir_print_type(f, m, t);
|
||||||
|
ir_fprintf(f, " ");
|
||||||
|
ir_print_value(f, m, arg, t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (isize i = 0; i < call->arg_count; i++) {
|
||||||
|
Entity *e = params->variables[i];
|
||||||
|
GB_ASSERT(e != NULL);
|
||||||
|
irValue *arg = call->args[i];
|
||||||
|
Type *t = proc_type->Proc.abi_compat_params[i];
|
||||||
|
if (i > 0) {
|
||||||
|
ir_fprintf(f, ", ");
|
||||||
|
}
|
||||||
|
ir_print_type(f, m, t);
|
||||||
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
|
ir_fprintf(f, " noalias");
|
||||||
|
}
|
||||||
|
ir_fprintf(f, " ");
|
||||||
|
ir_print_value(f, m, arg, t);
|
||||||
}
|
}
|
||||||
ir_fprintf(f, " ");
|
|
||||||
irValue *arg = call->args[i];
|
|
||||||
ir_print_value(f, m, arg, t);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir_fprintf(f, ")\n");
|
ir_fprintf(f, ")\n");
|
||||||
@@ -1495,17 +1543,21 @@ void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
ir_fprintf(f, ", ");
|
ir_fprintf(f, ", ");
|
||||||
}
|
}
|
||||||
ir_print_type(f, m, abi_type);
|
if (i+1 == params->variable_count && proc_type->c_vararg) {
|
||||||
if (e->flags&EntityFlag_NoAlias) {
|
ir_fprintf(f, " ...");
|
||||||
ir_fprintf(f, " noalias");
|
} else {
|
||||||
}
|
ir_print_type(f, m, abi_type);
|
||||||
if (proc->body != NULL) {
|
if (e->flags&EntityFlag_NoAlias) {
|
||||||
if (e->token.string != "" &&
|
ir_fprintf(f, " noalias");
|
||||||
e->token.string != "_") {
|
}
|
||||||
ir_fprintf(f, " ");
|
if (proc->body != NULL) {
|
||||||
ir_print_encoded_local(f, e->token.string);
|
if (e->token.string != "" &&
|
||||||
} else {
|
e->token.string != "_") {
|
||||||
ir_fprintf(f, " %%_.param_%td", i);
|
ir_fprintf(f, " ");
|
||||||
|
ir_print_encoded_local(f, e->token.string);
|
||||||
|
} else {
|
||||||
|
ir_fprintf(f, " %%_.param_%td", i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-3
@@ -65,6 +65,7 @@ enum ProcTag {
|
|||||||
ProcTag_bounds_check = 1<<0,
|
ProcTag_bounds_check = 1<<0,
|
||||||
ProcTag_no_bounds_check = 1<<1,
|
ProcTag_no_bounds_check = 1<<1,
|
||||||
|
|
||||||
|
|
||||||
ProcTag_require_results = 1<<4,
|
ProcTag_require_results = 1<<4,
|
||||||
|
|
||||||
ProcTag_foreign = 1<<10,
|
ProcTag_foreign = 1<<10,
|
||||||
@@ -72,6 +73,7 @@ enum ProcTag {
|
|||||||
ProcTag_link_name = 1<<12,
|
ProcTag_link_name = 1<<12,
|
||||||
ProcTag_inline = 1<<13,
|
ProcTag_inline = 1<<13,
|
||||||
ProcTag_no_inline = 1<<14,
|
ProcTag_no_inline = 1<<14,
|
||||||
|
|
||||||
// ProcTag_dll_import = 1<<15,
|
// ProcTag_dll_import = 1<<15,
|
||||||
// ProcTag_dll_export = 1<<16,
|
// ProcTag_dll_export = 1<<16,
|
||||||
};
|
};
|
||||||
@@ -100,8 +102,9 @@ enum FieldFlag {
|
|||||||
FieldFlag_ellipsis = 1<<0,
|
FieldFlag_ellipsis = 1<<0,
|
||||||
FieldFlag_using = 1<<1,
|
FieldFlag_using = 1<<1,
|
||||||
FieldFlag_no_alias = 1<<2,
|
FieldFlag_no_alias = 1<<2,
|
||||||
|
FieldFlag_c_vararg = 1<<3,
|
||||||
|
|
||||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias,
|
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StmtAllowFlag {
|
enum StmtAllowFlag {
|
||||||
@@ -2999,7 +3002,7 @@ AstNode *parse_proc_type(AstFile *f, Token proc_token, String *link_name_) {
|
|||||||
|
|
||||||
parse_proc_tags(f, &tags, &link_name, &cc);
|
parse_proc_tags(f, &tags, &link_name, &cc);
|
||||||
|
|
||||||
if (link_name_) *link_name_ = link_name;
|
if (link_name_) *link_name_ = link_name;
|
||||||
|
|
||||||
return ast_proc_type(f, proc_token, params, results, tags, cc);
|
return ast_proc_type(f, proc_token, params, results, tags, cc);
|
||||||
}
|
}
|
||||||
@@ -3030,6 +3033,7 @@ enum FieldPrefixKind {
|
|||||||
|
|
||||||
FieldPrefix_Using,
|
FieldPrefix_Using,
|
||||||
FieldPrefix_NoAlias,
|
FieldPrefix_NoAlias,
|
||||||
|
FieldPrefix_CVarArg,
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
||||||
@@ -3047,6 +3051,9 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
|||||||
if (f->curr_token.string == "no_alias") {
|
if (f->curr_token.string == "no_alias") {
|
||||||
return FieldPrefix_NoAlias;
|
return FieldPrefix_NoAlias;
|
||||||
}
|
}
|
||||||
|
if (f->curr_token.string == "c_vararg") {
|
||||||
|
return FieldPrefix_CVarArg;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
@@ -3058,6 +3065,7 @@ FieldPrefixKind is_token_field_prefix(AstFile *f) {
|
|||||||
u32 parse_field_prefixes(AstFile *f) {
|
u32 parse_field_prefixes(AstFile *f) {
|
||||||
i32 using_count = 0;
|
i32 using_count = 0;
|
||||||
i32 no_alias_count = 0;
|
i32 no_alias_count = 0;
|
||||||
|
i32 c_vararg_count = 0;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
FieldPrefixKind kind = is_token_field_prefix(f);
|
FieldPrefixKind kind = is_token_field_prefix(f);
|
||||||
@@ -3067,15 +3075,18 @@ u32 parse_field_prefixes(AstFile *f) {
|
|||||||
switch (kind) {
|
switch (kind) {
|
||||||
case FieldPrefix_Using: using_count += 1; next_token(f); break;
|
case FieldPrefix_Using: using_count += 1; next_token(f); break;
|
||||||
case FieldPrefix_NoAlias: no_alias_count += 1; next_token(f); break;
|
case FieldPrefix_NoAlias: no_alias_count += 1; next_token(f); break;
|
||||||
|
case FieldPrefix_CVarArg: c_vararg_count += 1; next_token(f); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
|
if (using_count > 1) syntax_error(f->curr_token, "Multiple `using` in this field list");
|
||||||
if (no_alias_count > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list");
|
if (no_alias_count > 1) syntax_error(f->curr_token, "Multiple `#no_alias` in this field list");
|
||||||
|
if (c_vararg_count > 1) syntax_error(f->curr_token, "Multiple `#c_vararg` in this field list");
|
||||||
|
|
||||||
|
|
||||||
u32 field_flags = 0;
|
u32 field_flags = 0;
|
||||||
if (using_count > 0) field_flags |= FieldFlag_using;
|
if (using_count > 0) field_flags |= FieldFlag_using;
|
||||||
if (no_alias_count > 0) field_flags |= FieldFlag_no_alias;
|
if (no_alias_count > 0) field_flags |= FieldFlag_no_alias;
|
||||||
|
if (c_vararg_count > 0) field_flags |= FieldFlag_c_vararg;
|
||||||
return field_flags;
|
return field_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3090,9 +3101,13 @@ u32 check_field_prefixes(AstFile *f, isize name_count, u32 allowed_flags, u32 se
|
|||||||
set_flags &= ~FieldFlag_using;
|
set_flags &= ~FieldFlag_using;
|
||||||
}
|
}
|
||||||
if ((allowed_flags&FieldFlag_no_alias) == 0 && (set_flags&FieldFlag_no_alias)) {
|
if ((allowed_flags&FieldFlag_no_alias) == 0 && (set_flags&FieldFlag_no_alias)) {
|
||||||
syntax_error(f->curr_token, "`no_alias` is not allowed within this field list");
|
syntax_error(f->curr_token, "`#no_alias` is not allowed within this field list");
|
||||||
set_flags &= ~FieldFlag_no_alias;
|
set_flags &= ~FieldFlag_no_alias;
|
||||||
}
|
}
|
||||||
|
if ((allowed_flags&FieldFlag_c_vararg) == 0 && (set_flags&FieldFlag_c_vararg)) {
|
||||||
|
syntax_error(f->curr_token, "`#c_vararg` is not allowed within this field list");
|
||||||
|
set_flags &= ~FieldFlag_c_vararg;
|
||||||
|
}
|
||||||
return set_flags;
|
return set_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-1
@@ -142,6 +142,7 @@ struct TypeRecord {
|
|||||||
Type * abi_compat_result_type; \
|
Type * abi_compat_result_type; \
|
||||||
bool variadic; \
|
bool variadic; \
|
||||||
bool require_results; \
|
bool require_results; \
|
||||||
|
bool c_vararg; \
|
||||||
ProcCallingConvention calling_convention; \
|
ProcCallingConvention calling_convention; \
|
||||||
}) \
|
}) \
|
||||||
TYPE_KIND(Map, struct { \
|
TYPE_KIND(Map, struct { \
|
||||||
@@ -1070,7 +1071,9 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
if (y->kind == Type_Tuple) {
|
if (y->kind == Type_Tuple) {
|
||||||
if (x->Tuple.variable_count == y->Tuple.variable_count) {
|
if (x->Tuple.variable_count == y->Tuple.variable_count) {
|
||||||
for (isize i = 0; i < x->Tuple.variable_count; i++) {
|
for (isize i = 0; i < x->Tuple.variable_count; i++) {
|
||||||
if (!are_types_identical(x->Tuple.variables[i]->type, y->Tuple.variables[i]->type)) {
|
Entity *xe = x->Tuple.variables[i];
|
||||||
|
Entity *ye = y->Tuple.variables[i];
|
||||||
|
if (!are_types_identical(xe->type, ye->type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1082,6 +1085,7 @@ bool are_types_identical(Type *x, Type *y) {
|
|||||||
case Type_Proc:
|
case Type_Proc:
|
||||||
if (y->kind == Type_Proc) {
|
if (y->kind == Type_Proc) {
|
||||||
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
return x->Proc.calling_convention == y->Proc.calling_convention &&
|
||||||
|
x->Proc.c_vararg == y->Proc.c_vararg &&
|
||||||
x->Proc.variadic == y->Proc.variadic &&
|
x->Proc.variadic == y->Proc.variadic &&
|
||||||
are_types_identical(x->Proc.params, y->Proc.params) &&
|
are_types_identical(x->Proc.params, y->Proc.params) &&
|
||||||
are_types_identical(x->Proc.results, y->Proc.results);
|
are_types_identical(x->Proc.results, y->Proc.results);
|
||||||
@@ -2292,6 +2296,9 @@ gbString write_type_to_string(gbString str, Type *type) {
|
|||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
str = gb_string_appendc(str, ", ");
|
str = gb_string_appendc(str, ", ");
|
||||||
}
|
}
|
||||||
|
if (var->flags&EntityFlag_CVarArg) {
|
||||||
|
str = gb_string_appendc(str, "#c_vararg ");
|
||||||
|
}
|
||||||
if (var->flags&EntityFlag_Ellipsis) {
|
if (var->flags&EntityFlag_Ellipsis) {
|
||||||
Type *slice = base_type(var->type);
|
Type *slice = base_type(var->type);
|
||||||
str = gb_string_appendc(str, "..");
|
str = gb_string_appendc(str, "..");
|
||||||
|
|||||||
Reference in New Issue
Block a user