diff --git a/releasenotes.md b/releasenotes.md index 678692c43..a823e08e4 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -30,7 +30,7 @@ - Allowed passing arguments to @test / @benchmark runners via `c3c test[benchmark] -- -o --opt1 ` - 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. diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 7a0aed78e..598f7865a 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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 diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 46f20e97c..c88e25416 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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: diff --git a/test/test_suite/compile_time/mod_in_other_scope.c3 b/test/test_suite/compile_time/mod_in_other_scope.c3 new file mode 100644 index 000000000..a029de6b2 --- /dev/null +++ b/test/test_suite/compile_time/mod_in_other_scope.c3 @@ -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; +} \ No newline at end of file diff --git a/test/test_suite/macros/hash_ident.c3 b/test/test_suite/macros/hash_ident.c3 index c2d3e449f..e16659d87 100644 --- a/test/test_suite/macros/hash_ident.c3 +++ b/test/test_suite/macros/hash_ident.c3 @@ -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 }