From 34bd5fa6da340971e8e8b8e880fe3c5c6e2f8a50 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Mon, 28 Mar 2022 10:08:07 +0200 Subject: [PATCH] Fix of macro defer with bodies. --- src/compiler/compiler_internal.h | 3 - src/compiler/sema_expr.c | 29 ++++- src/compiler/symtab.c | 6 - test/test_suite/macros/macro_body_defer.c3t | 126 ++++++++++++++++++++ 4 files changed, 149 insertions(+), 15 deletions(-) create mode 100644 test/test_suite/macros/macro_body_defer.c3t diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 50ab6a671..f7d7f5f09 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1590,7 +1590,6 @@ extern const char *kw_out; extern const char *kw_inout; extern const char *kw_deprecated; extern const char *kw_distinct; -extern const char *kw_ensure; extern const char *kw_inline; extern const char *kw_inf; extern const char *kw_elementat; @@ -1602,10 +1601,8 @@ extern const char *kw_noinline; extern const char *kw_main; extern const char *kw_ordinal; extern const char *kw_pure; -extern const char *kw_param; extern const char *kw_ptr; extern const char *kw_values; -extern const char *kw_errors; extern const char *kw_return; extern const char *kw_type; extern const char *kw_FILE; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index abcf21394..db789dfe6 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1861,11 +1861,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s if (!sema_add_local(¯o_context, param)) goto EXIT_FAIL; } - AstId current = body->compound_stmt.first_stmt; - while (current) - { - if (!sema_analyse_statement(¯o_context, ast_next(¤t))) goto EXIT_FAIL; - } + if (!sema_analyse_statement(¯o_context, body)) goto EXIT_FAIL; bool is_no_return = decl->macro_decl.attr_noreturn; @@ -2072,17 +2068,33 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call) Expr *expr = args[i]; if (!sema_analyse_expr(macro_context, expr)) return false; } + + AstId macro_defer = macro_context->active_scope.defer_last; + Ast *first_defer = NULL; SemaContext *context = macro_context->yield_context; Decl **params = macro_context->yield_params; + Expr *func_expr = exprptr(call_expr->function); assert(func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION); expr_replace(call, func_expr); call->body_expansion_expr.values = args; call->body_expansion_expr.declarations = macro_context->yield_params; - + AstId last_defer = context->active_scope.defer_last; bool success; SCOPE_START + + if (macro_defer) + { + Ast *macro_defer_ast = astptr(macro_defer); + first_defer = macro_defer_ast; + while (first_defer->defer_stmt.prev_defer) + { + first_defer = astptr(first_defer->defer_stmt.prev_defer); + } + first_defer->defer_stmt.prev_defer = context->active_scope.defer_last; + context->active_scope.defer_last = macro_defer; + } VECEACH(params, i) { Decl *param = params[i]; @@ -2091,6 +2103,11 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call) call->body_expansion_expr.ast = ast_macro_copy(macro_context->yield_body); success = sema_analyse_statement(context, call->body_expansion_expr.ast); + if (first_defer) + { + first_defer->defer_stmt.prev_defer = 0; + context->active_scope.defer_last = last_defer; + } SCOPE_END; return success; } diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 2be8ba335..3dcd96593 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -45,9 +45,7 @@ const char *kw_inout; const char *kw_align; const char *kw_deprecated; const char *kw_distinct; -const char *kw_ensure; const char *kw_elements; -const char *kw_errors; const char *kw_return; const char *kw_type; const char *kw_inf; @@ -62,7 +60,6 @@ const char *kw_min; const char *kw_nan; const char *kw_noinline; const char *kw_ordinal; -const char *kw_param; const char *kw_ptr; const char *kw_pure; const char *kw_std; @@ -132,8 +129,6 @@ void symtab_init(uint32_t capacity) kw_deprecated = KW_DEF("deprecated"); kw_distinct = KW_DEF("distinct"); kw_elements = KW_DEF("elements"); - kw_ensure = KW_DEF("ensure"); - kw_errors = KW_DEF("errors"); kw_type = KW_DEF("type"); kw_inf = KW_DEF("inf"); kw_inline = KW_DEF("inline"); @@ -147,7 +142,6 @@ void symtab_init(uint32_t capacity) kw_nan = KW_DEF("nan"); kw_noinline = KW_DEF("noinline"); kw_ordinal = KW_DEF("ordinal"); - kw_param = KW_DEF("param"); kw_ptr = KW_DEF("ptr"); kw_pure = KW_DEF("pure"); KW_DEF("require"); diff --git a/test/test_suite/macros/macro_body_defer.c3t b/test/test_suite/macros/macro_body_defer.c3t new file mode 100644 index 000000000..112e1382b --- /dev/null +++ b/test/test_suite/macros/macro_body_defer.c3t @@ -0,0 +1,126 @@ +// #target: x64-darwin +module foo; +extern fn void printf(char*,...); + +fn int! foo() { return 1; } + +macro foo_test(int i; @body()) +{ + defer printf("%d\n", i); + @body(); + defer printf("2:%d\n", i); +} + +macro foo_defer() +{ + defer printf("A\n"); + printf("B\n"); + defer printf("C\n"); +} +fn void! main() +{ + @foo_defer(); + @foo_test(34) { + defer printf("inside_defer\n"); + }; + while (1) + { + defer printf("outside\n"); + @foo_test(3) + { + defer printf("Inside will it jump?\n"); + printf("3-test\n"); + break; + }; + } + while (1) + { + defer printf("outside2\n"); + printf("--\n"); + @foo_test(3) + { + defer printf("Inside will it jump?\n"); + printf("--3\n"); + return; + }; + } + printf("Should not reach\n"); +} + +/* #expect: foo.ll + +define i64 @foo.foo(i32* %0) #0 { +entry: + %reterr = alloca i64, align 8 + store i32 1, i32* %0, align 4 + ret i64 0 +} + +define i64 @foo.main() #0 { +entry: + %i = alloca i32, align 4 + %i1 = alloca i32, align 4 + %i3 = alloca i32, align 4 + %reterr = alloca i64, align 8 + %reterr5 = alloca i64, align 8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str, i32 0, i32 0)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.1, i32 0, i32 0)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @.str.2, i32 0, i32 0)) + store i32 34, i32* %i, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* @.str.3, i32 0, i32 0)) + %0 = load i32, i32* %i, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.4, i32 0, i32 0), i32 %0) + %1 = load i32, i32* %i, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.5, i32 0, i32 0), i32 %1) + br label %loop.body + +loop.body: ; preds = %entry + store i32 3, i32* %i1, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.6, i32 0, i32 0)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.7, i32 0, i32 0)) + %2 = load i32, i32* %i1, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.8, i32 0, i32 0), i32 %2) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.9, i32 0, i32 0)) + br label %loop.exit + +loop.exit: ; preds = %loop.body + br label %loop.body2 + +loop.body2: ; preds = %loop.exit + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.13, i32 0, i32 0)) + store i32 3, i32* %i3, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.14, i32 0, i32 0)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* @.str.15, i32 0, i32 0)) + %3 = load i32, i32* %i3, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.16, i32 0, i32 0), i32 %3) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0)) + ret i64 0 + +loop.exit4: ; No predecessors! + call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.21, i32 0, i32 0)) + ret i64 0 +} + +; Function Attrs: nounwind +define i32 @main(i32 %0, i8** %1) #0 { +entry: + %2 = call i64 @foo.main() + %not_err = icmp eq i64 %2, 0 + br i1 %not_err, label %after.errcheck, label %error_block + +after.errcheck: ; preds = %entry + br label %noerr_block + +noerr_block: ; preds = %after.errcheck + br label %phi_trycatch_block + +error_block: ; preds = %entry + br label %phi_trycatch_block + +phi_trycatch_block: ; preds = %error_block, %noerr_block + %val = phi i8 [ 1, %noerr_block ], [ 0, %error_block ] + %3 = trunc i8 %val to i1 + %not = xor i1 %3, true + %boolsi = zext i1 %not to i32 + ret i32 %boolsi +} \ No newline at end of file