From 6287e8dfbfa1a186236a81ce1ba7bfa05390d193 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 26 Sep 2025 21:19:38 +0200 Subject: [PATCH] Restore some `out` checking. --- lib/std/crypto/aes.c3 | 2 +- src/compiler/sema_expr.c | 28 ++++++++++++++++++---- test/test_suite/contracts/out_subscript.c3 | 8 ++++--- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/lib/std/crypto/aes.c3 b/lib/std/crypto/aes.c3 index eb65d60ca..b42a8a13d 100644 --- a/lib/std/crypto/aes.c3 +++ b/lib/std/crypto/aes.c3 @@ -584,7 +584,7 @@ fn void inv_cipher(Aes* aes, char[] round_key) <*ยจ @param type : "The AES variant to expant the key for" - @param [out] round_key : "Key to expand into" + @param [inout] round_key : "Key to expand into" @param [in] key : "The key to expand" @require key.len == type.key.key_len : "Key does not match expected length." *> diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 1acea7107..16a9424ba 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -6676,6 +6676,17 @@ static bool sema_expr_analyse_slice_assign(SemaContext *context, Expr *expr, Typ return true; SLICE_COPY:; + while (right->expr_kind == EXPR_SLICE) + { + Expr *inner = exprptr(right->slice_expr.expr); + if (inner->expr_kind != EXPR_IDENTIFIER) break; + Decl *decl = inner->ident_expr; + if (decl->decl_kind != DECL_VAR) break; + if (!decl->var.out_param || decl->var.in_param) break; + if (context->active_scope.flags & (SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) break; + RETURN_SEMA_ERROR(right, "'out' parameters may not be read."); + } + if (!sema_analyse_expr_rhs(context, left_type, right, false, NULL, false)) return false; Range *left_range = &left->slice_expr.range; IndexDiff left_len = range_const_len(left_range); @@ -11661,19 +11672,26 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr, bool mutat case EXPR_IDENTIFIER: if (mutate && !sema_cast_ident_rvalue(context, expr)) return false; break; - case EXPR_SUBSCRIPT: case EXPR_SLICE: - /* { - Expr *inner = exprptr(expr->expr_kind == EXPR_SUBSCRIPT ? expr->subscript_expr.expr : expr->slice_expr.expr); + Expr *inner = exprptr(expr->subscript_expr.expr); + if (inner->expr_kind != EXPR_IDENTIFIER) break; + Decl *decl = inner->ident_expr; + if (decl->decl_kind != DECL_VAR) break; + if (!decl->var.out_param || decl->var.in_param) break; + if (context->active_scope.flags & (SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) break; + break; + } + case EXPR_SUBSCRIPT: + { + Expr *inner = exprptr(expr->subscript_expr.expr); if (inner->expr_kind != EXPR_IDENTIFIER) break; Decl *decl = inner->ident_expr; if (decl->decl_kind != DECL_VAR) break; if (!decl->var.out_param || decl->var.in_param) break; if (context->active_scope.flags & (SCOPE_ENSURE | SCOPE_ENSURE_MACRO)) break; RETURN_SEMA_ERROR(expr, "'out' parameters may not be read."); - }*/ - break; + } case EXPR_UNARY: { if (expr->unary_expr.operator != UNARYOP_DEREF) break; diff --git a/test/test_suite/contracts/out_subscript.c3 b/test/test_suite/contracts/out_subscript.c3 index 70a163894..5fca32125 100644 --- a/test/test_suite/contracts/out_subscript.c3 +++ b/test/test_suite/contracts/out_subscript.c3 @@ -5,9 +5,11 @@ *> fn void tes2t(char* z, char[] out_data, char[] in_data) { z[0] = 2; - z[0] += 1; // error: 'out' parameters may not be read + z[0] += 1; // #error: 'out' parameters may not be read out_data[0] = 3; - out_data[0] *= 1; // error: 'out' parameters may not be read - out_data[0..3]; // error: 'out' parameters may not be read + out_data[0] *= 1; // #error: 'out' parameters may not be read + out_data[0..3]; out_data[0..3] = 23; + out_data[0..3] = out_data[0..3]; // #error: parameters may not be read + } \ No newline at end of file