- Bitstruct as substruct fails to properly work with designated initializers. #2827

This commit is contained in:
Christoffer Lerno
2026-01-25 12:48:36 +01:00
parent cf9784afee
commit c65c378b7f
4 changed files with 20 additions and 11 deletions

View File

@@ -127,6 +127,7 @@
- Empty enums would return the values as zero sized arrays #2838 - Empty enums would return the values as zero sized arrays #2838
- Store of zero in lowering did not properly handle optionals in some cases #2837 - Store of zero in lowering did not properly handle optionals in some cases #2837
- Bitstruct accidentally allowed other arrays than char arrays #2836 - Bitstruct accidentally allowed other arrays than char arrays #2836
- Bitstruct as substruct fails to properly work with designated initializers. #2827
### Stdlib changes ### Stdlib changes
- Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads. - Add `ThreadPool` join function to wait for all threads to finish in the pool without destroying the threads.

View File

@@ -519,13 +519,11 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
} }
} }
Type *original = flattened->canonical; Type *original = flattened->canonical;
bool is_bitstruct = original->type_kind == TYPE_BITSTRUCT; bool is_structlike = type_is_union_or_strukt(original) || original->type_kind == TYPE_BITSTRUCT;
bool is_structlike = type_is_union_or_strukt(original) || is_bitstruct;
ArrayIndex max_index = -1; ArrayIndex max_index = -1;
bool optional = false; bool optional = false;
Type *inner_type = NULL; Type *inner_type = NULL;
bool is_inferred = type_is_inferred(flattened); bool is_inferred = type_is_inferred(flattened);
int bitmember_count_without_value = 0;
FOREACH(Expr *, expr, init_expressions) FOREACH(Expr *, expr, init_expressions)
{ {
Decl *member; Decl *member;
@@ -535,10 +533,8 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
Expr *value = expr->designator_expr.value; Expr *value = expr->designator_expr.value;
if (!value && is_bitmember && member->var.start_bit == member->var.end_bit && type_flatten(result) == type_bool) if (!value && is_bitmember && member->var.start_bit == member->var.end_bit && type_flatten(result) == type_bool)
{ {
ASSERT(is_bitstruct);
value = expr_new_const_bool(INVALID_SPAN, type_bool, true); value = expr_new_const_bool(INVALID_SPAN, type_bool, true);
expr->designator_expr.value = value; expr->designator_expr.value = value;
bitmember_count_without_value += 1;
} }
if (!value) RETURN_SEMA_ERROR(expr, "This initializer needs a value."); if (!value) RETURN_SEMA_ERROR(expr, "This initializer needs a value.");
if (!sema_analyse_expr_rhs(context, result, value, true, no_match_ref, false)) return false; if (!sema_analyse_expr_rhs(context, result, value, true, no_match_ref, false)) return false;
@@ -553,10 +549,6 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
inner_type = type_no_optional(value->type); inner_type = type_no_optional(value->type);
} }
} }
if (bitmember_count_without_value != 0 && bitmember_count_without_value != vec_size(init_expressions))
{
RETURN_SEMA_ERROR(initializer, "Mixing the omission of initializers is not permitted.");
}
Type *type; Type *type;
if (!is_structlike && is_inferred) if (!is_structlike && is_inferred)
{ {

View File

@@ -0,0 +1,18 @@
// #target: macos-x64
module test;
struct Foo4
{
bitstruct : short
{
short expand : 1..7;
bool b : 8;
}
}
fn void main()
{
Foo4 f4 = { .expand = 2, .b };
}
/* #expect: test.ll
@.__const = private unnamed_addr constant %Foo4 { i16 260 }, align 2

View File

@@ -91,12 +91,10 @@ fn void test4()
Flags1 flags1 = {.a, .b, .c}; Flags1 flags1 = {.a, .b, .c};
flags1 = {.a}; flags1 = {.a};
flags1 = {.a = true, .b = true, .c = false}; flags1 = {.a = true, .b = true, .c = false};
flags1 = {.a, .b = true, .c = true}; // #error: Mixing the omission
Foo foo = { .x = 0, .z }; // #error: needs a value Foo foo = { .x = 0, .z }; // #error: needs a value
Flags2 flags2 = {.b, .d}; Flags2 flags2 = {.b, .d};
flags2 = {.b, .c, .d}; // #error: needs a value flags2 = {.b, .c, .d}; // #error: needs a value
flags2 = {.a, .c = 1, .d}; // #error: Mixing the omission
Flags2_Struct flags2s; Flags2_Struct flags2s;
flags2s = {.b, .c, .d}; // #error: needs a value flags2s = {.b, .c, .d}; // #error: needs a value