Require parenthesized assignment expressions in condition of 'if' statements #2716 (#2729)

* Require parenthesized assignment expressions in condition of 'if' statements #2716

* Move analysis to semantic checker and also check while. And update tests and release notes.

---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
VarunVF
2026-01-15 07:43:58 +08:00
committed by GitHub
parent cd4c586c3f
commit 64ef33f09b
6 changed files with 31 additions and 7 deletions

View File

@@ -249,7 +249,7 @@ fn JsonTokenType? advance(JsonContext* context) @local
{ {
char c; char c;
// Skip whitespace // Skip whitespace
while WS: (c = read_next(context)!) while WS: ((c = read_next(context)!))
{ {
switch (c) switch (c)
{ {
@@ -272,12 +272,12 @@ fn JsonTokenType? advance(JsonContext* context) @local
while COMMENT: (true) while COMMENT: (true)
{ {
// Skip to */ // Skip to */
while (c = read_next(context)!) while ((c = read_next(context)!))
{ {
if (c == '\n') context.line++; if (c == '\n') context.line++;
if (c != '*') continue; if (c != '*') continue;
// Skip through all the '*' // Skip through all the '*'
while (c = read_next(context)!) while ((c = read_next(context)!))
{ {
if (c == '\n') context.line++; if (c == '\n') context.line++;
if (c != '*') break; if (c != '*') break;

View File

@@ -15,6 +15,7 @@
- Reduced memory usage for backtraces on Linux. - Reduced memory usage for backtraces on Linux.
- On win32 utf-8 console output is now enabled by default in compiled programs - On win32 utf-8 console output is now enabled by default in compiled programs
- Add `$$VERSION` and `$$PRERELEASE` compile time constants. - Add `$$VERSION` and `$$PRERELEASE` compile time constants.
- Require () around assignment in conditionals. #2716
### Fixes ### Fixes
- Regression with npot vector in struct triggering an assert #2219. - Regression with npot vector in struct triggering an assert #2219.

View File

@@ -1192,15 +1192,26 @@ static inline bool sema_analyse_cond(SemaContext *context, Expr *expr, CondType
{ {
RETURN_SEMA_ERROR(last->decl_expr->var.init_expr, "The expression needs to be convertible to a boolean."); RETURN_SEMA_ERROR(last->decl_expr->var.init_expr, "The expression needs to be convertible to a boolean.");
} }
cast_no_check(last, type_bool, false); cast_no_check(last, type_bool, false);
} }
if (cast_to_bool && expr_is_const_bool(init)) if (cast_to_bool && expr_is_const_bool(init))
{ {
*result = init->const_expr.b ? COND_TRUE : COND_FALSE; *result = init->const_expr.b ? COND_TRUE : COND_FALSE;
} }
return true; return true;
} }
if (cast_to_bool && last->expr_kind == EXPR_BINARY && last->binary_expr.operator >= BINARYOP_ASSIGN && !last->binary_expr.grouped)
{
if (vec_size(expr->cond_expr) > 1)
{
RETURN_SEMA_ERROR(last, "An assignment in the last conditional must be parenthesized - did you mean to use '==' instead?");
}
else
{
RETURN_SEMA_ERROR(last, "An assignment in a conditional must have an extra parenthesis - did you mean to use '==' instead?");
}
}
// 3a. Check for optional in case of an expression. // 3a. Check for optional in case of an expression.
if (IS_OPTIONAL(last)) if (IS_OPTIONAL(last))

View File

@@ -266,13 +266,13 @@ fn double mathFunc(double x, double y, double z,
fn void strcpy(char *s1, char *s2) { fn void strcpy(char *s1, char *s2) {
while (*s1++ = *s2++); while ((*s1++ = *s2++));
} }
fn void strcat(char *s1, char *s2) { fn void strcat(char *s1, char *s2) {
while (*s1++); while (*s1++);
s1--; s1--;
while (*s1++ = *s2++); while ((*s1++ = *s2++));
} }
fn int strcmp(char *s1, char *s2) { fn int strcmp(char *s1, char *s2) {

View File

@@ -0,0 +1,12 @@
fn void main()
{
int x = 5;
if (x = 1) {} // #error: An assignment in a conditional must have an extra parenthesis
if ((x = 1)) {}
while (x = 1) {} // #error: An assignment in a conditional must have an extra parenthesis
while (x = 1, x = 1) {} // #error: An assignment in the last conditional must be parenthesized
}

View File

@@ -12,7 +12,7 @@ macro @thing(; @body())
} }
fn void strcpy(char *s1, char *s2) { fn void strcpy(char *s1, char *s2) {
while (*s1++ = *s2++); while ((*s1++ = *s2++));
} }
fn void main() fn void main()