Fix: Compiler assert when attempting to define multiple faults in a generic module. #2706

This commit is contained in:
Christoffer Lerno
2026-01-05 21:04:23 +01:00
parent fa1951642b
commit d820a2356a
6 changed files with 58 additions and 8 deletions

View File

@@ -327,6 +327,45 @@ bool decl_is_defaulted_var(Decl *decl)
return decl->decl_kind == DECL_VAR && decl->var.no_init && decl->var.defaulted;
}
bool decl_may_be_generic(Decl *decl)
{
switch (decl->decl_kind)
{
case DECL_POISONED:
case DECL_BODYPARAM:
case DECL_CT_ASSERT:
case DECL_CT_ECHO:
case DECL_CT_EXEC:
case DECL_CT_INCLUDE:
case DECL_ALIAS_PATH:
case DECL_ENUM_CONSTANT:
case DECL_ERASED:
case DECL_FAULT:
case DECL_GROUP:
case DECL_GENERIC:
case DECL_GENERIC_INSTANCE:
case DECL_IMPORT:
case DECL_LABEL:
case DECL_CONST_ENUM:
return false;
case DECL_ATTRIBUTE:
case DECL_BITSTRUCT:
case DECL_DECLARRAY:
case DECL_ALIAS:
case DECL_TYPEDEF:
case DECL_ENUM:
case DECL_FNTYPE:
case DECL_FUNC:
case DECL_MACRO:
case DECL_INTERFACE:
case DECL_STRUCT:
case DECL_TYPE_ALIAS:
case DECL_UNION:
case DECL_VAR:
return true;
}
UNREACHABLE
}
/*
* Count the expected number of elements needed for an initializer
* by folding any anonymous structs and unions.

View File

@@ -2382,6 +2382,7 @@ const char *decl_to_name(Decl *decl);
const char *decl_to_a_name(Decl *decl);
int decl_count_elements(Decl *structlike);
bool decl_is_defaulted_var(Decl *decl);
bool decl_may_be_generic(Decl *decl);
void decl_append_links_to_global_during_codegen(Decl *decl);
Decl *decl_template_get_generic(Decl *decl);

View File

@@ -1323,12 +1323,18 @@ static bool parse_attributes_for_global(ParseContext *c, Decl *decl)
bool is_builtin = false;
bool is_cond;
Decl *generics = NULL;
bool can_be_generic = decl_may_be_generic(decl);
if (!parse_attributes(c, &decl->attributes, &visibility, decl_needs_prefix(decl) ? &is_builtin : NULL, &is_cond, &generics)) return false;
if (generics)
{
if (!can_be_generic)
{
print_error_at(decl->span, "This declaration cannot be generic.");
return false;
}
parse_attach_generics(c, generics);
}
if (!generics && c->unit->default_generic_section)
if (!generics && c->unit->default_generic_section && can_be_generic)
{
generics = c->unit->default_generic_section;
}
@@ -2318,7 +2324,7 @@ static inline Decl *parse_alias_type(ParseContext *c, AstId contracts)
{
advance_and_verify(c, TOKEN_ALIAS);
Decl *decl = decl_new(DECL_POISONED, symstr(c), c->span);
Decl *decl = decl_new(DECL_TYPE_ALIAS, symstr(c), c->span);
DEBUG_LOG("Parse def %s", decl->name);
if (!try_consume(c, TOKEN_TYPE_IDENT))
{

View File

@@ -251,9 +251,6 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
case DECL_POISONED:
continue;
case DECL_FAULT:
PRINT_ERROR_AT(decl, "Generic modules cannot use 'faultdef', place the declaration in a separate sub module or parent module instead.");
decl_poison(decl);
break;
case DECL_BODYPARAM:
case DECL_DECLARRAY:
case DECL_ENUM_CONSTANT:

View File

@@ -1,11 +1,11 @@
module abc {Type};
attrdef @Hello = @inline;
faultdef ABC; // #error: Generic modules cannot use 'faultdef'
faultdef ABC;
module bcd;
import abc;
fn void main()
{
Abc{int} a;
int? a = abc::ABC~;
}

View File

@@ -0,0 +1,7 @@
module g{T};
faultdef F0, F1;
module main;
fn void main() {}