Prevent #hash arguments from taking code that modifies ct variables. #1794

This commit is contained in:
Christoffer Lerno
2025-01-12 02:20:18 +01:00
parent f60bfa8442
commit a863d7fe9e
5 changed files with 49 additions and 4 deletions

View File

@@ -30,7 +30,7 @@
- Allowed passing arguments to @test / @benchmark runners via `c3c test[benchmark] -- -o --opt1 <arg1>`
- Handle bytes and string literals the same way in terms of zero termination.
- Function comments are stored and displayed with -P.
- Prevent `#hash` arguments from taking code that modifies ct variables. #1794
### Fixes
- Fix case trying to initialize a `char[*]*` from a String.
- Fix Map & HashMap `put_all_for_create` not copying all elements, causing `init_from_map` to create incomplete copy.

View File

@@ -1679,6 +1679,7 @@ typedef struct
bool ensures : 1;
bool pure : 1;
bool in_no_eval : 1;
bool in_other : 1;
SourceSpan in_if_resolution;
Decl **opt_returns;
union

View File

@@ -5677,6 +5677,11 @@ static bool sema_expr_analyse_ct_identifier_assign(SemaContext *context, Expr *e
// Evaluate right side to using inference from last type.
if (!sema_analyse_inferred_expr(context, left->type, right)) return false;
if (context->call_env.in_other)
{
RETURN_SEMA_ERROR(left, "Compile time variables may only be modified in the scope they are defined in.");
}
left->ct_ident_expr.decl->var.init_expr = right;
expr_replace(expr, right);
left->ct_ident_expr.decl->type = right->type;
@@ -5696,6 +5701,12 @@ static bool sema_expr_analyse_ct_type_identifier_assign(SemaContext *context, Ex
Decl *decl = sema_find_symbol(context, info->unresolved.name);
if (!decl) RETURN_SEMA_ERROR(info, "'%s' is not defined in this scope yet.", info->unresolved.name);
if (context->call_env.in_other)
{
RETURN_SEMA_ERROR(left, "Compile time variables may only be modified in the scope they are defined in.");
}
decl->var.init_expr = right;
expr->expr_kind = EXPR_NOP;
expr->type = type_void;
@@ -5792,6 +5803,10 @@ static bool sema_binary_analyse_ct_common_assign(SemaContext *context, Expr *exp
Decl *left_var = left->ct_ident_expr.decl;
if (!sema_cast_ct_ident_rvalue(context, left)) return false;
if (context->call_env.in_other)
{
RETURN_SEMA_ERROR(left, "Compile time variables may only be modified in the scope they are defined in.");
}
expr->binary_expr.operator = binaryop_assign_base_op(expr->binary_expr.operator);
if (!sema_expr_analyse_binary(context, expr, NULL)) return false;
@@ -9526,7 +9541,13 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr,
if (expr->resolve_status == RESOLVE_DONE) return expr_ok(expr);
ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_NOT_DONE);
expr->resolve_status = RESOLVE_RUNNING;
return sema_analyse_expr_dispatch(context, expr, check);
{
bool in_other = context->call_env.in_other;
context->call_env.in_other = true;
bool success = sema_analyse_expr_dispatch(context, expr, check);
context->call_env.in_other = in_other;
return success;
}
case EXPR_CT_CASTABLE:
return sema_expr_analyse_castable(context, expr);
case EXPR_EMBED:

View File

@@ -0,0 +1,23 @@
module test;
macro void @foo(#a)
{
#a;
}
macro void @bar(#a)
{
$typeof(#a) x;
}
fn int main()
{
int $i;
var $Type;
@foo($Type = int); // #error: only be modified
@foo($i = 2); // #error: only be modified
@foo($i += 1); // #error: only be modified
@bar($Type = int); // #error: only be modified
@bar($i = 2); // #error: only be modified
@bar($i += 1); // #error: only be modified
return 0;
}

View File

@@ -18,8 +18,8 @@ fn void main()
int x = 0;
@cofefe(x += 1);
@cofefe(xx());
@cofefe($x += 1);
$assert $x == 2;
$typeof($x += 1) xx;
$assert $x == 1;
@cofefe(y += 1); // #error: 'y' could not be found
}