Throw/catch works correctly with defer.

This commit is contained in:
Christoffer Lerno
2020-05-03 16:45:16 +02:00
parent 333b3df47d
commit d23c271289
7 changed files with 40 additions and 18 deletions

View File

@@ -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");
}

View File

@@ -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

View File

@@ -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
{

View File

@@ -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);

View File

@@ -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 &&

View File

@@ -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++)
{

View File

@@ -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;