mirror of
https://github.com/odin-lang/Odin.git
synced 2026-09-02 18:23:35 +00:00
Support asm template groups
This commit is contained in:
@@ -1985,6 +1985,151 @@ gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *pg_entity, D
|
||||
check_objc_methods(ctx, pg_entity, ac);
|
||||
}
|
||||
|
||||
gb_internal void check_asm_group_decl(CheckerContext *ctx, Entity *asm_entity, DeclInfo *d) {
|
||||
GB_ASSERT(asm_entity->kind == Entity_ProcGroup);
|
||||
auto *pge = &asm_entity->ProcGroup;
|
||||
String proc_group_name = asm_entity->token.string;
|
||||
|
||||
ast_node(pg, AsmGroup, d->init_expr);
|
||||
|
||||
pge->entities = array_make<Entity*>(permanent_allocator(), 0, pg->args.count);
|
||||
|
||||
// NOTE(bill): This must be set here to prevent cycles in checking if someone
|
||||
// places the entity within itself
|
||||
asm_entity->type = t_invalid;
|
||||
|
||||
PtrSet<Entity *> entity_set = {};
|
||||
ptr_set_init(&entity_set, 2*pg->args.count);
|
||||
|
||||
for (Ast *arg_ : pg->args) {
|
||||
Ast *arg = arg_;
|
||||
Entity *e = nullptr;
|
||||
Operand o = {};
|
||||
if (arg->kind == Ast_BinaryExpr && arg->BinaryExpr.op.kind == Token_where) {
|
||||
Ast *cond_expr = arg->BinaryExpr.right;
|
||||
Operand cond = {};
|
||||
check_expr(ctx, &cond, cond_expr);
|
||||
if (cond.mode != Addressing_Invalid) {
|
||||
if (cond.mode != Addressing_Constant || !is_type_boolean(cond.type) || cond.value.kind != ExactValue_Bool) {
|
||||
error(arg, "Expected a constant binary expression for the 'where' clause");
|
||||
} else if (!cond.value.value_bool) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
arg = arg->BinaryExpr.left;
|
||||
}
|
||||
|
||||
if (arg->kind == Ast_Ident) {
|
||||
e = check_ident(ctx, &o, arg, nullptr, nullptr, true);
|
||||
} else if (arg->kind == Ast_SelectorExpr) {
|
||||
e = check_selector(ctx, &o, arg, nullptr);
|
||||
}
|
||||
if (e == nullptr) {
|
||||
error(arg, "Expected a valid entity name in asm group, got %.*s", LIT(ast_strings[arg->kind]));
|
||||
continue;
|
||||
}
|
||||
if (e->kind != Entity_AsmTemplate) {
|
||||
error(arg, "Expected an asm template");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ptr_set_update(&entity_set, e)) {
|
||||
error(arg, "Previous use of `%.*s` in asm group", LIT(e->token.string));
|
||||
continue;
|
||||
}
|
||||
array_add(&pge->entities, e);
|
||||
}
|
||||
|
||||
ptr_set_destroy(&entity_set);
|
||||
|
||||
for (isize j = 0; j < pge->entities.count; j++) {
|
||||
Entity *p = pge->entities[j];
|
||||
if (p->type == t_invalid) {
|
||||
// NOTE(bill): This invalid overload has already been handled
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->flags & EntityFlag_Disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = p->token.string;
|
||||
|
||||
for (isize k = j+1; k < pge->entities.count; k++) {
|
||||
Entity *q = pge->entities[k];
|
||||
GB_ASSERT(p != q);
|
||||
|
||||
bool is_invalid = false;
|
||||
|
||||
TokenPos pos = q->token.pos;
|
||||
|
||||
if (q->type == nullptr || q->type == t_invalid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
ERROR_BLOCK();
|
||||
|
||||
if (q->flags & EntityFlag_Disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcTypeOverloadKind kind = are_proc_types_overload_safe(p->type, q->type);
|
||||
bool both_have_where_clauses = false;
|
||||
if (p->decl_info != nullptr && q->decl_info != nullptr &&
|
||||
p->decl_info->proc_lit != nullptr && q->decl_info->proc_lit != nullptr) {
|
||||
GB_ASSERT(p->decl_info->proc_lit->kind == Ast_ProcLit);
|
||||
GB_ASSERT(q->decl_info->proc_lit->kind == Ast_ProcLit);
|
||||
auto pl = &p->decl_info->proc_lit->ProcLit;
|
||||
auto ql = &q->decl_info->proc_lit->ProcLit;
|
||||
|
||||
// Allow collisions if the procedures both have 'where' clauses and are both polymorphic
|
||||
bool pw = pl->where_token.kind != Token_Invalid && is_type_polymorphic(p->type, true);
|
||||
bool qw = ql->where_token.kind != Token_Invalid && is_type_polymorphic(q->type, true);
|
||||
both_have_where_clauses = pw && qw;
|
||||
}
|
||||
|
||||
if (!both_have_where_clauses) switch (kind) {
|
||||
case ProcOverload_Identical:
|
||||
error(p->token, "Overloaded asm template '%.*s' has the same type as another asm template in the asm template group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
// case ProcOverload_CallingConvention:
|
||||
// error(p->token, "Overloaded asm template '%.*s' has the same type as another asm template in the asm template group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
// is_invalid = true;
|
||||
// break;
|
||||
case ProcOverload_ParamVariadic:
|
||||
error(p->token, "Overloaded asm template '%.*s' has the same type as another asm template in the asm template group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_ResultCount:
|
||||
case ProcOverload_ResultTypes:
|
||||
error(p->token, "Overloaded asm template '%.*s' has the same parameters but different results in the asm template group '%.*s'", LIT(name), LIT(proc_group_name));
|
||||
is_invalid = true;
|
||||
break;
|
||||
case ProcOverload_Polymorphic:
|
||||
break;
|
||||
case ProcOverload_ParamCount:
|
||||
case ProcOverload_ParamTypes:
|
||||
case ProcOverload_TargetFeatures:
|
||||
// This is okay :)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (is_invalid) {
|
||||
error_line("\tprevious asm template at %s\n", token_pos_to_string(pos));
|
||||
q->type = t_invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AttributeContext ac = {};
|
||||
check_decl_attributes(ctx, d->attributes, proc_group_attribute, &ac);
|
||||
check_objc_methods(ctx, asm_entity, ac);
|
||||
}
|
||||
|
||||
#include "check_asm.cpp"
|
||||
|
||||
|
||||
@@ -2061,7 +2206,11 @@ gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d,
|
||||
check_proc_decl(&c, e, d);
|
||||
break;
|
||||
case Entity_ProcGroup:
|
||||
check_proc_group_decl(&c, e, d);
|
||||
if (e->ProcGroup.is_asm_group) {
|
||||
check_asm_group_decl(&c, e, d);
|
||||
} else {
|
||||
check_proc_group_decl(&c, e, d);
|
||||
}
|
||||
break;
|
||||
|
||||
case Entity_AsmTemplate:
|
||||
|
||||
Reference in New Issue
Block a user