Allow omitting = true for designated initializers of bitstruct bools.

This commit is contained in:
Christian Buttner
2024-06-22 14:53:44 +02:00
committed by Christoffer Lerno
parent 0dc2f0e923
commit 41db9c43e5
6 changed files with 67 additions and 8 deletions

View File

@@ -441,6 +441,7 @@ param_path
arg
: param_path '=' expr
| param_path
| type
| param_path '=' type
| expr

View File

@@ -211,6 +211,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind)
return expr_list_is_constant_eval(expr->cond_expr, eval_kind);
case EXPR_DESIGNATOR:
expr = expr->designator_expr.value;
if (!expr) return true;
goto RETRY;
case EXPR_EXPR_BLOCK:
case EXPR_DECL:

View File

@@ -465,7 +465,7 @@ Expr *parse_vasplat(ParseContext *c)
/**
* param_list ::= ('...' arg | arg (',' arg)*)?
*
* parameter ::= (param_path '=')? expr
* parameter ::= ((param_path '=')? expr) | param_path
*/
bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *splat, bool vasplat)
{
@@ -483,11 +483,9 @@ bool parse_arg_list(ParseContext *c, Expr ***result, TokenType param_end, bool *
expr = expr_new(EXPR_DESIGNATOR, start_span);
expr->designator_expr.path = path;
// Expect the '=' after.
CONSUME_OR_RET(TOKEN_EQ, false);
// Now parse the rest
ASSIGN_EXPR_OR_RET(expr->designator_expr.value, parse_expr(c), false);
if (try_consume(c, TOKEN_EQ)) {
ASSIGN_EXPR_OR_RET(expr->designator_expr.value, parse_expr(c), false);
}
RANGE_EXTEND_PREV(expr);
}

View File

@@ -1331,6 +1331,10 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
}
// 8g. Set the parameter
if (!arg->designator_expr.value)
{
RETURN_SEMA_ERROR(arg, "Expected a value for this argument.");
}
actual_args[index] = arg->designator_expr.value;
continue;
}

View File

@@ -406,15 +406,24 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
bool optional = false;
Type *inner_type = NULL;
bool is_inferred = type_is_inferred(flattened);
int bitmember_count_without_value = 0;
VECEACH(init_expressions, i)
{
Expr *expr = init_expressions[i];
Decl *member;
Type *result = sema_expr_analyse_designator(context, original, expr, &max_index, &member);
if (!result) return false;
bool is_bitmember = member && member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER;
Expr *value = expr->designator_expr.value;
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);
expr->designator_expr.value = value;
bitmember_count_without_value += 1;
}
if (!value) RETURN_SEMA_ERROR(expr, "This initializer needs a value.");
if (!sema_analyse_expr_rhs(context, result, value, true, NULL)) return false;
if (member && member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER)
if (is_bitmember)
{
if (!sema_bit_assignment_check(context, value, member)) return false;
}
@@ -426,6 +435,9 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
continue;
}
}
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;
if (!is_structlike && is_inferred)
{
@@ -522,6 +534,7 @@ static void sema_create_const_initializer_from_designated_init(ConstInitializer
Expr *expr = init_expressions[i];
DesignatorElement **path = expr->designator_expr.path;
Expr *value = expr->designator_expr.value;
assert(value);
sema_update_const_initializer_with_designator(const_init, path, path + vec_size(path), value);
}
}

View File

@@ -59,4 +59,46 @@ fn void test2()
fn void test3()
{
Foo abc = { .x = -4, .z = 0, .y = 8 }; // #error: would be truncated
}
}
bitstruct Flags1 : int
{
bool a;
bool b;
bool c;
}
distinct Bool = bool;
bitstruct Flags2 : int
{
bool a : 0;
Bool b : 1;
int c : 2..3;
bool d : 6;
}
struct Flags2_Struct
{
bool a;
bool b;
int c;
bool d;
}
fn void test4()
{
Flags1 flags1 = {.a, .b, .c};
flags1 = {.a};
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
Flags2 flags2 = {.b, .d};
flags2 = {.b, .c, .d}; // #error: needs a value
flags2 = {.a, .c = 1, .d}; // #error: Mixing the omission
Flags2_Struct flags2s;
flags2s = {.b, .c, .d}; // #error: needs a value
flags2s = {.a, .c = 1, .d}; // #error: needs a value
}