mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Require exhaustive enum switching.
This commit is contained in:
@@ -3322,6 +3322,11 @@ INLINE bool expr_is_const_string(Expr *expr)
|
||||
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_STRING;
|
||||
}
|
||||
|
||||
INLINE bool expr_is_const_enum(Expr *expr)
|
||||
{
|
||||
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_ENUM;
|
||||
}
|
||||
|
||||
INLINE bool expr_is_const_pointer(Expr *expr)
|
||||
{
|
||||
return expr->expr_kind == EXPR_CONST && expr->const_expr.const_kind == CONST_POINTER;
|
||||
|
||||
@@ -2101,6 +2101,48 @@ static inline bool sema_check_value_case(SemaContext *context, Type *switch_type
|
||||
return true;
|
||||
}
|
||||
|
||||
INLINE const char *create_missing_enums_in_switch_error(Ast **cases, unsigned case_count, Decl **enums)
|
||||
{
|
||||
unsigned missing = vec_size(enums) - case_count;
|
||||
scratch_buffer_clear();
|
||||
if (missing == 1)
|
||||
{
|
||||
scratch_buffer_append("Enum value ");
|
||||
}
|
||||
else
|
||||
{
|
||||
scratch_buffer_printf("%u enum values were not handled in the switch: ", missing);
|
||||
}
|
||||
unsigned printed = 0;
|
||||
FOREACH_BEGIN(Decl *decl, enums)
|
||||
for (unsigned i = 0; i < case_count; i++)
|
||||
{
|
||||
Expr *e = cases[i]->case_stmt.expr;
|
||||
assert(expr_is_const_enum(e));
|
||||
if (e->const_expr.enum_err_val == decl) goto CONTINUE;
|
||||
}
|
||||
if (++printed != 1)
|
||||
{
|
||||
scratch_buffer_append(printed == missing ? " and " : ", ");
|
||||
}
|
||||
scratch_buffer_append(decl->name);
|
||||
if (printed > 2 && missing > 3)
|
||||
{
|
||||
scratch_buffer_append(", ...");
|
||||
goto DONE;
|
||||
}
|
||||
if (printed == missing) goto DONE;
|
||||
CONTINUE:;
|
||||
FOREACH_END();
|
||||
DONE:;
|
||||
if (missing == 1)
|
||||
{
|
||||
scratch_buffer_append(" was not handled in the switch - either add it or add 'default'.");
|
||||
return scratch_buffer_to_string();
|
||||
}
|
||||
scratch_buffer_append(" - either add them or use 'default'.");
|
||||
return scratch_buffer_to_string();
|
||||
}
|
||||
static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, SourceSpan expr_span, Type *switch_type, Ast **cases, ExprAnySwitch *any_switch, Decl *var_holder)
|
||||
{
|
||||
bool use_type_id = false;
|
||||
@@ -2165,7 +2207,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
|
||||
POP_NEXT();
|
||||
}
|
||||
|
||||
if (!exhaustive && is_enum_switch && case_count == vec_size(flat->decl->enums.values)) exhaustive = true;
|
||||
if (!exhaustive && is_enum_switch) exhaustive = case_count >= vec_size(flat->decl->enums.values);
|
||||
bool all_jump_end = exhaustive;
|
||||
for (unsigned i = 0; i < case_count; i++)
|
||||
{
|
||||
@@ -2217,6 +2259,11 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc
|
||||
all_jump_end &= context->active_scope.jump_end;
|
||||
SCOPE_END;
|
||||
}
|
||||
if (is_enum_switch && !exhaustive && success)
|
||||
{
|
||||
SEMA_ERROR(statement, create_missing_enums_in_switch_error(cases, case_count, flat->decl->enums.values));
|
||||
success = false;
|
||||
}
|
||||
statement->flow.no_exit = all_jump_end;
|
||||
statement->switch_stmt.flow.if_chain = if_chain || max_ranged;
|
||||
return success;
|
||||
|
||||
@@ -91,14 +91,14 @@ enum Baz
|
||||
|
||||
fn void test_missing_all_cases(Baz x)
|
||||
{
|
||||
switch (x) // -error: 4 enumeration values not handled in switch: A, B, C, ...
|
||||
switch (x) // #error: not handled in the switch: A, B, C, ...
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
fn void test_missing_some_cases(Baz x)
|
||||
{
|
||||
switch (x) // -error: 4 enumeration B, C and D not handled in switch
|
||||
switch (x) // #error: not handled in the switch: B, C and D
|
||||
{
|
||||
case A:
|
||||
break;
|
||||
@@ -107,7 +107,7 @@ fn void test_missing_some_cases(Baz x)
|
||||
|
||||
fn void test_missing_some_cases2(Baz x)
|
||||
{
|
||||
switch (x) // -error: 4 enumeration B and D not handled in switch
|
||||
switch (x) // #error: B and D
|
||||
{
|
||||
case C:
|
||||
case A:
|
||||
@@ -117,7 +117,7 @@ fn void test_missing_some_cases2(Baz x)
|
||||
|
||||
fn void test_missing_some_cases3(Baz x)
|
||||
{
|
||||
switch (x) // -error: 4 enumeration B and D not handled in switch
|
||||
switch (x) // #error: Enum value D was not handled in the switch
|
||||
{
|
||||
case B:
|
||||
case C:
|
||||
|
||||
Reference in New Issue
Block a user