From d23c2712891f52bc6463c512994dad9c6b2a0861 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sun, 3 May 2020 16:45:16 +0200 Subject: [PATCH] Throw/catch works correctly with defer. --- resources/testfragments/super_simple.c3 | 13 +++++++++++-- src/compiler/compiler_internal.h | 4 +++- src/compiler/enums.h | 7 ------- src/compiler/llvm_codegen_expr.c | 22 ++++++++++++++++++++-- src/compiler/llvm_codegen_stmt.c | 5 ++--- src/compiler/sema_expr.c | 4 ++-- src/compiler/sema_stmts.c | 3 ++- 7 files changed, 40 insertions(+), 18 deletions(-) diff --git a/resources/testfragments/super_simple.c3 b/resources/testfragments/super_simple.c3 index 2e9fcd983..523c5f3f8 100644 --- a/resources/testfragments/super_simple.c3 +++ b/resources/testfragments/super_simple.c3 @@ -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"); } diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index f2c6508b9..37885cca0 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -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 diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 571ba5bd6..c6f2d97e5 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -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 { diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index e46a146a9..8de865b30 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -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); diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 6f6a54d4e..214743bd9 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -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 && diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index b04e77723..e38aa94f5 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -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++) { diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index c2182a875..ad3f4e573 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -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;