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 arg
: param_path '=' expr : param_path '=' expr
| param_path
| type | type
| param_path '=' type | param_path '=' type
| expr | 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); return expr_list_is_constant_eval(expr->cond_expr, eval_kind);
case EXPR_DESIGNATOR: case EXPR_DESIGNATOR:
expr = expr->designator_expr.value; expr = expr->designator_expr.value;
if (!expr) return true;
goto RETRY; goto RETRY;
case EXPR_EXPR_BLOCK: case EXPR_EXPR_BLOCK:
case EXPR_DECL: case EXPR_DECL:

View File

@@ -465,7 +465,7 @@ Expr *parse_vasplat(ParseContext *c)
/** /**
* param_list ::= ('...' arg | arg (',' arg)*)? * 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) 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 = expr_new(EXPR_DESIGNATOR, start_span);
expr->designator_expr.path = path; expr->designator_expr.path = path;
// Expect the '=' after. if (try_consume(c, TOKEN_EQ)) {
CONSUME_OR_RET(TOKEN_EQ, false); ASSIGN_EXPR_OR_RET(expr->designator_expr.value, parse_expr(c), false);
}
// Now parse the rest
ASSIGN_EXPR_OR_RET(expr->designator_expr.value, parse_expr(c), false);
RANGE_EXTEND_PREV(expr); RANGE_EXTEND_PREV(expr);
} }

View File

@@ -1331,6 +1331,10 @@ INLINE bool sema_call_expand_arguments(SemaContext *context, CalledDecl *callee,
} }
// 8g. Set the parameter // 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; actual_args[index] = arg->designator_expr.value;
continue; continue;
} }

View File

@@ -406,15 +406,24 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type
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;
VECEACH(init_expressions, i) VECEACH(init_expressions, i)
{ {
Expr *expr = init_expressions[i]; Expr *expr = init_expressions[i];
Decl *member; Decl *member;
Type *result = sema_expr_analyse_designator(context, original, expr, &max_index, &member); Type *result = sema_expr_analyse_designator(context, original, expr, &max_index, &member);
if (!result) return false; if (!result) return false;
bool is_bitmember = member && member->decl_kind == DECL_VAR && member->var.kind == VARDECL_BITMEMBER;
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) {
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 (!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; 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; 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; Type *type;
if (!is_structlike && is_inferred) if (!is_structlike && is_inferred)
{ {
@@ -522,6 +534,7 @@ static void sema_create_const_initializer_from_designated_init(ConstInitializer
Expr *expr = init_expressions[i]; Expr *expr = init_expressions[i];
DesignatorElement **path = expr->designator_expr.path; DesignatorElement **path = expr->designator_expr.path;
Expr *value = expr->designator_expr.value; Expr *value = expr->designator_expr.value;
assert(value);
sema_update_const_initializer_with_designator(const_init, path, path + vec_size(path), 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() fn void test3()
{ {
Foo abc = { .x = -4, .z = 0, .y = 8 }; // #error: would be truncated 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
}