mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Check pointer/slice/etc on [out] and & params. #2156.
This commit is contained in:
@@ -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"
|
||||
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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(¯o_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
test/test_suite/contracts/inout_macro.c3
Normal file
12
test/test_suite/contracts/inout_macro.c3
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user