Check pointer/slice/etc on [out] and & params. #2156.

This commit is contained in:
Christoffer Lerno
2025-05-27 23:03:32 +02:00
parent b665e2cbe5
commit be3f9007c9
4 changed files with 54 additions and 28 deletions

View File

@@ -183,7 +183,7 @@ macro bool is_native_atomic_type($Type)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to be added to ptr."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -203,7 +203,7 @@ macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to be subtracted from ptr."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -223,7 +223,7 @@ macro fetch_sub(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to be multiplied with ptr."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -263,7 +263,7 @@ macro fetch_mul(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to divide ptr by."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -303,7 +303,7 @@ macro fetch_div(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to perform a bitwise or with."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -320,7 +320,7 @@ macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to perform a bitwise xor with."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -337,7 +337,7 @@ macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to perform a bitwise and with."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -354,7 +354,7 @@ macro fetch_and(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatil
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to shift ptr by."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -396,7 +396,7 @@ macro fetch_shift_right(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param [in] y : "the value to shift ptr by."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -438,7 +438,7 @@ macro fetch_shift_left(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"
@@ -466,7 +466,7 @@ macro flag_set(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT)
}
<*
@param [&in] ptr : "the variable or dereferenced pointer to the data."
@param [&inout] ptr : "the variable or dereferenced pointer to the data."
@param $ordering : "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@return "returns the old value of ptr"

View File

@@ -47,6 +47,7 @@
- Distinct types could not be used with tagof #2152.
- `$$sat_mul` was missing.
- `for` with incorrect `var` declaration caused crash #2154.
- Check pointer/slice/etc on `[out]` and `&` params. #2156.
### Stdlib changes
- Added `String.quick_ztr` and `String.is_zstr`

View File

@@ -2446,27 +2446,40 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s
// Skip raw vararg
if (!param) continue;
if (!sema_add_local(&macro_context, param)) goto EXIT_FAIL;
if (param->var.init_expr && param->var.not_null)
if (param->var.init_expr)
{
Expr *expr = expr_variable(param);
Expr *binary = expr_new_expr(EXPR_BINARY, expr);
binary->binary_expr.left = exprid(expr);
binary->binary_expr.right = exprid(expr_new_const_null(expr->span, type_voidptr));
binary->binary_expr.operator = BINARYOP_NE;
if (!sema_analyse_expr_rhs(context, type_bool, binary, false, NULL, false)) goto EXIT_FAIL;
const char *string = struct_var && idx == 0 ? "Called a method on a null value." : "Passed null to a ref ('&') parameter.";
if (expr_is_const_bool(binary) && !binary->const_expr.b)
Type *param_type = param->type;
if (param_type && (param->var.out_param || param->var.not_null))
{
sema_error_at(context, param->var.init_expr->span, string);
goto EXIT_FAIL;
param_type = type_flatten(param_type);
if (param_type->type_kind != TYPE_POINTER && param_type->type_kind != TYPE_SLICE && param_type->type_kind != TYPE_INTERFACE && param_type->type_kind != TYPE_ANY)
{
SEMA_ERROR(param->var.init_expr, "Expected a pointer, slice or interface value for '%s'.", param->name);
goto EXIT_FAIL;
}
}
if (param->var.not_null)
{
Expr *expr = expr_variable(param);
Expr *binary = expr_new_expr(EXPR_BINARY, expr);
binary->binary_expr.left = exprid(expr);
binary->binary_expr.right = exprid(expr_new_const_null(expr->span, type_voidptr));
binary->binary_expr.operator = BINARYOP_NE;
if (!sema_analyse_expr_rhs(context, type_bool, binary, false, NULL, false)) goto EXIT_FAIL;
const char *string = struct_var && idx == 0 ? "Called a method on a null value." : "Passed null to a ref ('&') parameter.";
if (expr_is_const_bool(binary) && !binary->const_expr.b)
{
sema_error_at(context, param->var.init_expr->span, string);
goto EXIT_FAIL;
}
Ast *assert = new_ast(AST_ASSERT_STMT, param->var.init_expr->span);
assert->assert_stmt.is_ensure = true;
assert->assert_stmt.expr = exprid(binary);
Expr *comment_expr = expr_new_const_string(expr->span, string);
assert->assert_stmt.message = exprid(comment_expr);
ast_append(&next, assert);
Ast *assert = new_ast(AST_ASSERT_STMT, param->var.init_expr->span);
assert->assert_stmt.is_ensure = true;
assert->assert_stmt.expr = exprid(binary);
Expr *comment_expr = expr_new_const_string(expr->span, string);
assert->assert_stmt.message = exprid(comment_expr);
ast_append(&next, assert);
}
}
}

View File

@@ -0,0 +1,12 @@
import std;
<*
@param [&out] x
@require $defined(*x) : "x must be a pointer"
*>
macro foo(x) => *x = 1;
fn int main()
{
foo(0); // #error: Expected a pointer
return 0;
}