mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-08 22:01:47 -04:00
Catch calls of a deferred out proc in short circuits during check
This commit is contained in:
1 parent
0b3f7a5509
commit
db46204e38
5 files changed
+60
No files matched your search
@@ -9081,6 +9081,17 @@ gb_internal ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *c
|
||||
gb_zero_item(operand);
|
||||
operand->expr = call;
|
||||
|
||||
if ((call->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) == 0) {
|
||||
// NOTE: which procedure of a group is called is only known once its arguments are checked
|
||||
Entity *e = entity_of_node(call->CallExpr.proc);
|
||||
if (e != nullptr && e->kind == Entity_Procedure && e->Procedure.deferred_procedure.entity != nullptr) {
|
||||
call->viral_state_flags |= ViralStateFlag_ContainsDeferredProcedure;
|
||||
if (c->decl) {
|
||||
c->decl->defer_used += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result_type == t_invalid) {
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
@@ -10110,6 +10121,13 @@ gb_internal ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *n
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (te->x->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
|
||||
error(te->x, "Procedure calls that have an associated deferred procedure are not allowed within ternary expressions");
|
||||
}
|
||||
if (te->y->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
|
||||
error(te->y, "Procedure calls that have an associated deferred procedure are not allowed within ternary expressions");
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Type || y.mode == Addressing_Type) {
|
||||
Ast *type_expr = (x.mode == Addressing_Type) ? x.expr : y.expr;
|
||||
gbString type_string = expr_to_string(type_expr);
|
||||
@@ -10282,6 +10300,9 @@ gb_internal ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node
|
||||
|
||||
bool y_is_diverging = false;
|
||||
check_expr_base(c, &y, default_value, left_type);
|
||||
if (default_value->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
|
||||
error(default_value, "Procedure calls that have an associated deferred procedure are not allowed on the right-hand side of 'or_else'");
|
||||
}
|
||||
switch (y.mode) {
|
||||
case Addressing_NoValue:
|
||||
if (is_diverging_expr(y.expr)) {
|
||||
|
||||
@@ -1315,6 +1315,9 @@ gb_internal void check_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags
|
||||
} else {
|
||||
check_expr_with_type_hint(ctx, &y, expr, x.type);
|
||||
}
|
||||
if (expr->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
|
||||
error(expr, "Procedure calls that have an associated deferred procedure are not allowed within case clauses");
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Invalid ||
|
||||
y.mode == Addressing_Invalid) {
|
||||
|
||||
@@ -25,6 +25,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
|
||||
..\..\..\odin build ..\test_issue_5043.odin %COMMON% || exit /b
|
||||
..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b
|
||||
..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b
|
||||
..\..\..\odin check ..\test_issue_5105_5569.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "4" || exit /b
|
||||
..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b
|
||||
..\..\..\odin test ..\test_issue_5318.odin %COMMON% || exit /b
|
||||
..\..\..\odin build ..\test_issue_5573.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b
|
||||
|
||||
@@ -32,6 +32,12 @@ fi
|
||||
$ODIN build ../test_issue_5043.odin $COMMON
|
||||
$ODIN build ../test_issue_5097.odin $COMMON
|
||||
$ODIN build ../test_issue_5097-2.odin $COMMON
|
||||
if [[ $($ODIN check ../test_issue_5105_5569.odin $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 4 ]]; then
|
||||
echo "SUCCESSFUL 1/1"
|
||||
else
|
||||
echo "SUCCESSFUL 0/1"
|
||||
exit 1
|
||||
fi
|
||||
$ODIN build ../test_issue_5265.odin $COMMON
|
||||
$ODIN test ../test_issue_5318.odin $COMMON
|
||||
if [[ $($ODIN build ../test_issue_5573.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Tests issues #5105 https://github.com/odin-lang/Odin/issues/5105
|
||||
// and #5569 https://github.com/odin-lang/Odin/issues/5569
|
||||
package test_issues
|
||||
|
||||
import "core:sync"
|
||||
|
||||
// A procedure call with a deferred procedure is not allowed where it may not be evaluated.
|
||||
// The associated deferred procedure would be called at the end of the scope regardless.
|
||||
|
||||
@(deferred_out = finish)
|
||||
start :: proc(x: int) -> int { return x }
|
||||
finish :: proc(_: int) {}
|
||||
|
||||
maybe :: proc(x: int) -> (int, bool) { return x, x > 0 }
|
||||
|
||||
m: sync.Mutex
|
||||
|
||||
main :: proc() {
|
||||
flag := true
|
||||
|
||||
_ = start(1) if flag else 2 // Error
|
||||
_ = maybe(1) or_else start(2) // Error
|
||||
switch {
|
||||
case flag, start(3) > 0: // Error
|
||||
}
|
||||
if flag && sync.guard(&m) {} // Error, `sync.guard` is a procedure group
|
||||
|
||||
_ = start(4) + 1
|
||||
}
|
||||
Reference in new issue
Block a user