mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Throw/catch works correctly with defer.
This commit is contained in:
@@ -669,15 +669,22 @@ func int oekt() throws
|
||||
|
||||
func void testErrorMulti()
|
||||
{
|
||||
|
||||
defer printf("End defer\n");
|
||||
printf("Test error multi\n");
|
||||
int z = try oekt();
|
||||
{
|
||||
defer printf("Defer\n");
|
||||
printf("Will call\n");
|
||||
int z = try oekt();
|
||||
printf("Got here\n");
|
||||
}
|
||||
catch (Err e)
|
||||
{
|
||||
defer printf("Left error\n");
|
||||
printf("Expected particular error.\n");
|
||||
}
|
||||
catch (error e)
|
||||
{
|
||||
defer printf("Left any error\n");
|
||||
printf("Unexpected any error error.\n");
|
||||
}
|
||||
printf("End\n");
|
||||
@@ -686,8 +693,10 @@ func void testErrorMulti()
|
||||
func void throwAOrB(int i) throws Err, Err2
|
||||
{
|
||||
printf("AB\n");
|
||||
defer printf("A-Err\n");
|
||||
if (i == 1) throw Err.TEST_ERR1;
|
||||
printf("B\n");
|
||||
defer printf("B-Err\n");
|
||||
if (i == 2) throw Err2.TEST_ERR2;
|
||||
printf("None\n");
|
||||
}
|
||||
|
||||
@@ -511,12 +511,13 @@ typedef struct
|
||||
Ast *catch;
|
||||
Decl *error;
|
||||
};
|
||||
Ast *defer;
|
||||
} CatchInfo;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool is_completely_handled;
|
||||
DeferList defers;
|
||||
Ast *defer;
|
||||
CatchInfo *catches;
|
||||
} ThrowInfo;
|
||||
|
||||
@@ -798,6 +799,7 @@ typedef struct
|
||||
typedef struct
|
||||
{
|
||||
Expr *throw_value;
|
||||
Ast *defer;
|
||||
} AstThrowStmt;
|
||||
|
||||
typedef struct
|
||||
|
||||
@@ -240,13 +240,6 @@ typedef enum
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
NUMBER_TYPE_BOOL,
|
||||
NUMBER_TYPE_FLOAT,
|
||||
NUMBER_TYPE_SIGNED_INT,
|
||||
NUMBER_TYPE_UNSIGNED_INT,
|
||||
} NumberType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
@@ -1152,13 +1152,13 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
LLVMBasicBlockRef else_block = gencontext_create_free_block(context, "erret_one");
|
||||
gencontext_emit_cond_br(context, comparison, else_block, after_block);
|
||||
gencontext_emit_block(context, else_block);
|
||||
gencontext_emit_defer(context, throw_info->defer, NULL);
|
||||
gencontext_emit_return_value(context, value);
|
||||
gencontext_emit_block(context, after_block);
|
||||
return;
|
||||
}
|
||||
case CATCH_RETURN_MANY:
|
||||
{
|
||||
TODO // Check type
|
||||
LLVMBasicBlockRef else_block = gencontext_create_free_block(context, "erret_many");
|
||||
gencontext_emit_cond_br(context, comparison, else_block, after_block);
|
||||
gencontext_emit_block(context, else_block);
|
||||
@@ -1166,6 +1166,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
{
|
||||
value = gencontext_emit_cast(context, CAST_ERREU, value, type_error_union, call_error_type);
|
||||
}
|
||||
gencontext_emit_defer(context, throw_info->defer, NULL);
|
||||
gencontext_emit_return_value(context, value);
|
||||
gencontext_emit_block(context, after_block);
|
||||
return;
|
||||
@@ -1173,7 +1174,17 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
case CATCH_TRY_ELSE:
|
||||
{
|
||||
LLVMBasicBlockRef else_block = gencontext_get_try_target(context, catch->try_else);
|
||||
gencontext_emit_cond_br(context, comparison, else_block, after_block);
|
||||
if (throw_info->defer != catch->defer)
|
||||
{
|
||||
LLVMBasicBlockRef defer_block = gencontext_create_free_block(context, "defer");
|
||||
gencontext_emit_cond_br(context, comparison, defer_block, after_block);
|
||||
gencontext_emit_defer(context, throw_info->defer, catch->defer);
|
||||
gencontext_emit_br(context, else_block);
|
||||
}
|
||||
else
|
||||
{
|
||||
gencontext_emit_cond_br(context, comparison, else_block, after_block);
|
||||
}
|
||||
gencontext_emit_block(context, after_block);
|
||||
return;
|
||||
}
|
||||
@@ -1186,6 +1197,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
{
|
||||
value = gencontext_emit_cast(context, CAST_ERREU, value, type_error_union, errors[0]->type);
|
||||
}
|
||||
gencontext_emit_defer(context, throw_info->defer, NULL);
|
||||
gencontext_emit_return_value(context, value);
|
||||
gencontext_emit_block(context, after_block);
|
||||
return;
|
||||
@@ -1205,6 +1217,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
}
|
||||
}
|
||||
LLVMBuildStore(context->builder, value, error_param->var.backend_ref);
|
||||
gencontext_emit_defer(context, throw_info->defer, catch->defer);
|
||||
gencontext_emit_br(context, catch->catch->catch_stmt.block);
|
||||
gencontext_emit_block(context, after_block);
|
||||
return;
|
||||
@@ -1238,6 +1251,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
LLVMValueRef offset = LLVMBuildBitCast(context->builder, catch->error->error.start_value, llvm_type(type_error_union), "");
|
||||
LLVMValueRef negated = LLVMBuildNeg(context->builder, offset, "");
|
||||
LLVMValueRef final_value = LLVMBuildAnd(context->builder, negated, value, "");
|
||||
gencontext_emit_defer(context, throw_info->defer, NULL);
|
||||
gencontext_emit_return_value(context, final_value);
|
||||
gencontext_emit_block(context, after_block);
|
||||
assert(i == vec_size(throw_info->catches) - 1);
|
||||
@@ -1247,6 +1261,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
case CATCH_RETURN_ANY:
|
||||
{
|
||||
// This is simple, just return our value.
|
||||
gencontext_emit_defer(context, throw_info->defer, NULL);
|
||||
gencontext_emit_return_value(context, value);
|
||||
gencontext_emit_block(context, after_block);
|
||||
assert(i == vec_size(throw_info->catches) - 1);
|
||||
@@ -1255,6 +1270,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
case CATCH_TRY_ELSE:
|
||||
{
|
||||
// This should be the last catch.
|
||||
gencontext_emit_defer(context, throw_info->defer, catch->defer);
|
||||
LLVMBasicBlockRef else_block = gencontext_get_try_target(context, catch->try_else);
|
||||
gencontext_emit_br(context, else_block);
|
||||
gencontext_emit_block(context, after_block);
|
||||
@@ -1272,6 +1288,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
{
|
||||
// Store the value, then jump
|
||||
LLVMBuildStore(context->builder, value, error_param->var.backend_ref);
|
||||
gencontext_emit_defer(context, throw_info->defer, catch->defer);
|
||||
gencontext_emit_br(context, catch->catch->catch_stmt.block);
|
||||
gencontext_emit_block(context, after_block);
|
||||
assert(i == vec_size(throw_info->catches) - 1);
|
||||
@@ -1292,6 +1309,7 @@ static inline void gencontext_emit_throw_branch(GenContext *context, LLVMValueRe
|
||||
LLVMBasicBlockRef match_block = gencontext_create_free_block(context, "match");
|
||||
gencontext_emit_cond_br(context, match, match_block, err_handling_block);
|
||||
gencontext_emit_block(context, match_block);
|
||||
gencontext_emit_defer(context, throw_info->defer, catch->defer);
|
||||
|
||||
LLVMBuildStore(context->builder, comp_value, error_param->var.backend_ref);
|
||||
gencontext_emit_br(context, catch->catch->catch_stmt.block);
|
||||
|
||||
@@ -146,11 +146,10 @@ static inline void gencontext_emit_throw(GenContext *context, Ast *ast)
|
||||
// Ensure we are on a branch that is non empty.
|
||||
if (!gencontext_check_block_branch_emit(context)) return;
|
||||
|
||||
// TODO defer
|
||||
// gencontext_emit_defer(context, ast->throw_stmt.defers.start, ast->throw_stmt.defers.end);
|
||||
|
||||
LLVMValueRef error_val = gencontext_emit_expr(context, ast->throw_stmt.throw_value);
|
||||
|
||||
gencontext_emit_defer(context, ast->throw_stmt.defer, NULL);
|
||||
|
||||
// In the case that the throw actually contains a single error, but the function is throwing an error union,
|
||||
// we must insert a conversion.
|
||||
if (context->cur_func_decl->func.function_signature.error_return != ERROR_RETURN_ONE &&
|
||||
|
||||
@@ -260,7 +260,7 @@ static inline bool sema_expr_analyse_func_call(Context *context, Type *to, Expr
|
||||
FunctionSignature *signature = &decl->func.function_signature;
|
||||
Decl **func_params = signature->params;
|
||||
expr->call_expr.throw_info = CALLOCS(ThrowInfo);
|
||||
expr->call_expr.throw_info->defers = context->current_scope->defers;
|
||||
expr->call_expr.throw_info->defer = context->current_scope->defers.start;
|
||||
unsigned error_params = signature->throw_any || signature->throws;
|
||||
if (error_params)
|
||||
{
|
||||
@@ -2261,7 +2261,7 @@ static inline bool sema_expr_analyse_try(Context *context, Type *to, Expr *expr)
|
||||
}
|
||||
if (expr->try_expr.else_expr)
|
||||
{
|
||||
CatchInfo info = { .kind = CATCH_TRY_ELSE, .try_else = expr };
|
||||
CatchInfo info = { .kind = CATCH_TRY_ELSE, .try_else = expr, .defer = context->current_scope->defers.start };
|
||||
// Absorb all errors.
|
||||
for (unsigned i = prev_throws; i < new_throws; i++)
|
||||
{
|
||||
|
||||
@@ -498,7 +498,7 @@ static bool sema_analyse_catch_stmt(Context *context, Ast *statement)
|
||||
variable->type = variable->var.type_info->type;
|
||||
Type *error_type = variable->type->canonical;
|
||||
|
||||
CatchInfo catch = { .kind = CATCH_REGULAR, .catch = statement };
|
||||
CatchInfo catch = { .kind = CATCH_REGULAR, .catch = statement, .defer = context->current_scope->defers.start };
|
||||
// 4. Absorb all errors in case of a type error union.
|
||||
if (error_type == type_error_union)
|
||||
{
|
||||
@@ -833,6 +833,7 @@ static bool sema_analyse_switch_stmt(Context *context, Ast *statement)
|
||||
static bool sema_analyse_throw_stmt(Context *context, Ast *statement)
|
||||
{
|
||||
Expr *throw_value = statement->throw_stmt.throw_value;
|
||||
statement->throw_stmt.defer = context->current_scope->defers.end;
|
||||
UPDATE_EXIT(EXIT_THROW);
|
||||
if (!sema_analyse_expr(context, NULL, throw_value)) return false;
|
||||
Type *type = throw_value->type->canonical;
|
||||
|
||||
Reference in New Issue
Block a user