From 069a2d40cb7eb0a58a8538c141f93752ab0065c4 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Sat, 5 Mar 2022 01:44:09 +0100 Subject: [PATCH] Changing how defer works. Remove of undef. Simplify ensure. --- src/compiler/ast.c | 5 +- src/compiler/compiler_internal.h | 308 ++++++----- src/compiler/copying.c | 326 ++++++++---- src/compiler/enums.h | 6 +- src/compiler/llvm_codegen_expr.c | 36 +- src/compiler/llvm_codegen_function.c | 2 - src/compiler/llvm_codegen_internal.h | 14 +- src/compiler/llvm_codegen_stmt.c | 188 +++---- src/compiler/parse_expr.c | 32 +- src/compiler/parse_global.c | 26 +- src/compiler/parse_stmt.c | 74 +-- src/compiler/parser_internal.h | 1 - src/compiler/sema_casts.c | 4 +- src/compiler/sema_decls.c | 30 +- src/compiler/sema_expr.c | 81 ++- src/compiler/sema_internal.h | 4 +- src/compiler/sema_stmts.c | 503 +++++++----------- src/compiler/semantic_analyser.c | 91 ++-- src/version.h | 2 +- test/test_suite/contracts/simple_test.c3t | 16 +- test/test_suite/from_docs/examples_defer.c3t | 34 +- test/test_suite/macros/macro_defer_exit.c3t | 83 +++ .../test_suite/macros/macro_defer_noscope.c3t | 6 - test/test_suite/macros/macro_defer_scope.c3t | 6 +- .../macros/macro_defer_with_body.c3t | 6 - test/test_suite/macros/userland_bitcast.c3t | 49 +- test/test_suite/statements/defer_break.c3t | 71 +-- .../statements/defer_break_simple.c3t | 19 +- .../statements/defer_break_switch.c3t | 14 +- test/test_suite/statements/defer_do_while.c3t | 38 ++ test/test_suite/statements/defer_in_block.c3t | 71 +++ test/test_suite/statements/defer_in_defer.c3t | 10 +- .../test_suite/statements/defer_in_defer2.c3t | 120 +++++ .../statements/defer_next_switch.c3t | 16 +- test/test_suite/statements/defer_return.c3t | 71 +-- test/test_suite/statements/defer_test.c3 | 1 - .../test_suite/statements/defer_with_loop.c3t | 108 ++++ test/test_suite/statements/if_tests.c3t | 5 +- test/test_suite/statements/label_errors.c3 | 4 +- test/test_suite/symbols/various.c3 | 10 - 40 files changed, 1411 insertions(+), 1080 deletions(-) create mode 100644 test/test_suite/macros/macro_defer_exit.c3t create mode 100644 test/test_suite/statements/defer_do_while.c3t create mode 100644 test/test_suite/statements/defer_in_block.c3t create mode 100644 test/test_suite/statements/defer_in_defer2.c3t create mode 100644 test/test_suite/statements/defer_with_loop.c3t diff --git a/src/compiler/ast.c b/src/compiler/ast.c index 8dd170846..5ae5d6ccc 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -235,6 +235,7 @@ bool expr_is_pure(Expr *expr) case EXPR_NOP: case EXPR_PTR: case EXPR_STRINGIFY: + case EXPR_RETVAL: return true; case EXPR_ARGV_TO_SUBARRAY: case EXPR_BITASSIGN: @@ -284,7 +285,6 @@ bool expr_is_pure(Expr *expr) case EXPR_SLICE_ASSIGN: case EXPR_TRY_UNWRAP: case EXPR_TRY_UNWRAP_CHAIN: - case EXPR_UNDEF: case EXPR_TYPEINFO: case EXPR_FORCE_UNWRAP: return false; @@ -489,8 +489,7 @@ bool ast_is_not_empty(Ast *ast) { Ast *stmt = astptr(first); if (stmt->next) return true; - if (ast->compound_stmt.defer_list.start != ast->compound_stmt.defer_list.end) return true; return ast_is_not_empty(stmt); } - return ast->compound_stmt.defer_list.start != ast->compound_stmt.defer_list.end; + return false; } \ No newline at end of file diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index b6e610058..a74ab9cae 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -49,6 +49,7 @@ typedef Type CanonicalType; typedef unsigned AstId; typedef unsigned ExprId; +typedef unsigned DeclId; typedef struct Int128_ { @@ -143,13 +144,6 @@ typedef struct }; } ExprConst; - -typedef struct -{ - AstId start; - AstId end; -} DeferList; - typedef uint16_t FileId; typedef struct { @@ -343,6 +337,7 @@ typedef struct VarDecl_ bool is_written : 1; bool is_addr : 1; bool is_threadlocal : 1; + bool no_init : 1; TypeInfo *type_info; union { @@ -689,14 +684,15 @@ typedef struct bool force_inline : 1; bool force_noinline : 1; bool is_builtin : 1; + bool is_func_ref : 1; + AstId body; union { - Expr *function; - Decl *func_ref; + ExprId function; + DeclId func_ref; }; Expr **arguments; Decl **body_arguments; - Ast *body; Attr **attributes; } ExprCall; @@ -709,9 +705,9 @@ typedef struct typedef struct { - Expr *expr; bool start_from_back : 1; bool end_from_back : 1; + Expr *expr; Expr *start; Expr *end; } ExprSlice; @@ -816,7 +812,7 @@ typedef struct typedef struct { Expr *expr; - DeferList defers; + AstId defer_stmts; } ExprScope; typedef struct @@ -849,7 +845,7 @@ typedef struct typedef struct { Expr *inner; - AstId defer; + AstId cleanup; } ExprGuard; @@ -935,61 +931,61 @@ struct Expr_ SourceSpan span; Type *type; union { - ExprVariantSwitch variant_switch; - ExprLen len_expr; - ExprCast cast_expr; - TypeInfo *type_expr; - ExprConst const_expr; - ExprArgv argv_expr; - ExprGuard rethrow_expr; - Decl *decl_expr; - ExprOrError or_error_expr; - ExprSliceAssign slice_assign_expr; - ExprBinary binary_expr; - ExprTernary ternary_expr; - ExprUnary unary_expr; - Expr** try_unwrap_chain_expr; - ExprTryUnwrap try_unwrap_expr; - ExprCall call_expr; - ExprSlice slice_expr; - Expr *inner_expr; - ExprCatchUnwrap catch_unwrap_expr; - ExprSubscript subscript_expr; - ExprAccess access_expr; - ExprDesignator designator_expr; - ExprIdentifier identifier_expr; - ExprIdentifierRaw ct_ident_expr; - ExprCtCall ct_call_expr; - ExprIdentifierRaw ct_macro_ident_expr; - ExprMacroExpansion macro_expansion_expr; - ExprIdentifierRaw hash_ident_expr; - TypeInfo *typeid_expr; - ExprBodyExpansion body_expansion_expr; - ExprCompoundLiteral expr_compound_literal; - Expr** expression_list; - Expr** initializer_list; - Expr** designated_init_list; - ExprScope expr_scope; - ExprFuncBlock expr_block; - ExprMacroBlock macro_block; - Expr** cond_expr; - ExprBuiltin builtin_expr; + ExprVariantSwitch variant_switch; // 32 + ExprLen len_expr; // 8 + ExprCast cast_expr; // 32 + TypeInfo *type_expr; // 8 + ExprConst const_expr; // 32 + ExprArgv argv_expr; // 16 + ExprGuard rethrow_expr; // 16 + Decl *decl_expr; // 8 + ExprOrError or_error_expr; // 24 + ExprSliceAssign slice_assign_expr; // 8 + ExprBinary binary_expr; // 24 + ExprTernary ternary_expr; // 32 + ExprUnary unary_expr; // 16 + Expr** try_unwrap_chain_expr; // 8 + ExprTryUnwrap try_unwrap_expr; // 24 + ExprCall call_expr; // 40 + ExprSlice slice_expr; // 32 + Expr *inner_expr; // 8 + ExprCatchUnwrap catch_unwrap_expr; // 24 + ExprSubscript subscript_expr; // 24 + ExprAccess access_expr; // 16 + ExprDesignator designator_expr; // 16 + ExprIdentifier identifier_expr; // 32 + ExprIdentifierRaw ct_ident_expr; // 24 + ExprCtCall ct_call_expr; // 24 + ExprIdentifierRaw ct_macro_ident_expr; // 24 + ExprMacroExpansion macro_expansion_expr; // 16 + ExprIdentifierRaw hash_ident_expr; // 24 + TypeInfo *typeid_expr; // 8 + ExprBodyExpansion body_expansion_expr; // 24 + ExprCompoundLiteral expr_compound_literal; // 16 + Expr** expression_list; // 8 + Expr** initializer_list; // 8 + Expr** designated_init_list; // 8 + ExprScope expr_scope; // 16 + ExprFuncBlock expr_block; // 4 + ExprMacroBlock macro_block; // 24 + Expr** cond_expr; // 8 + ExprBuiltin builtin_expr; // 16 }; }; +static_assert(sizeof(ExprCall) == 40, "Ooops"); - +static_assert(sizeof(Expr) == 64, "Ooops"); typedef struct { AstId first_stmt; - DeferList defer_list; } AstCompoundStmt; typedef struct { Expr *expr; // May be NULL - AstId defer; + AstId cleanup; } AstReturnStmt; typedef struct @@ -997,45 +993,28 @@ typedef struct bool has_break : 1; bool no_exit : 1; bool skip_first : 1; + bool if_chain : 1; Decl *label; } FlowCommon; -typedef struct -{ - FlowCommon flow; - ExprId cond; - AstId body; - void *break_block; - void *continue_block; -} AstWhileStmt; + typedef struct { FlowCommon flow; - DeferList expr_defer; - DeferList body_defer; union { struct { - void *break_block; - void *continue_block; + ExprId cond; + AstId then_body; + AstId else_body; }; struct { - Expr *expr; - AstId body; - }; + void *break_block; + } codegen; }; -} AstDoStmt; - -typedef struct -{ - FlowCommon flow; - Expr *cond; - Ast *then_body; - Ast *else_body; - void *break_block; } AstIfStmt; @@ -1051,15 +1030,14 @@ typedef struct typedef struct { FlowCommon flow; - AstId defer; - Expr *cond; - Ast **cases; union { struct { - Ast* scope_defer; - bool if_chain; + ExprId cond; + AstId defer; + Ast **cases; + Ast *scope_defer; }; struct { @@ -1073,12 +1051,21 @@ typedef struct typedef struct { FlowCommon flow; - Expr *init; - Expr *cond; - Expr *incr; - AstId body; - void *continue_block; - void *exit_block; + union + { + struct + { + ExprId cond; + ExprId incr; + ExprId init; + AstId body; + }; + struct + { + void *continue_block; + void *exit_block; + } codegen; + }; } AstForStmt; typedef struct @@ -1087,24 +1074,17 @@ typedef struct bool index_by_ref : 1; bool value_by_ref : 1; bool iterator : 1; - CastKind cast; - Decl *index; - Decl *variable; - Expr *enumeration; - Ast *body; - void *continue_block; - void *exit_block; + CastKind cast : 8; + ExprId enumeration; + AstId body; + DeclId index; + DeclId variable; } AstForeachStmt; typedef struct { AstId prev_defer; - Ast *body; // Compound statement - struct - { - void *exit_block; - uint64_t exit_val; - } codegen; + AstId body; // Compound statement } AstDeferStmt; @@ -1117,12 +1097,6 @@ typedef struct AstCtIfStmt_ } AstCtIfStmt; -typedef struct -{ - AstId stmt; - DeferList defers; -} AstScopedStmt; - typedef struct { Expr *cond; @@ -1136,25 +1110,26 @@ typedef struct const char *value_name; SourceSpan index_span; SourceSpan value_span; - Expr *expr; AstId body; + ExprId expr; } AstCtForeachStmt; typedef struct { - bool is_label; + bool is_label : 1; + bool is_resolved : 1; + AstId defers; union { Label label; AstId ast; }; - DeferList defers; } AstContinueBreakStmt; typedef struct { - DeferList defers; + AstId defer_id; union { struct @@ -1204,7 +1179,7 @@ typedef struct typedef struct AstDocDirective_ { SourceSpan span; - DocDirectiveKind kind; + DocDirectiveKind kind : 4; union { struct @@ -1240,35 +1215,33 @@ typedef struct Ast_ AstKind ast_kind : 8; union { - FlowCommon flow; // Shared struct - AstAsmStmt asm_stmt; // 24 - AstCompoundStmt compound_stmt; // 16 - Decl *declare_stmt; // 8 - Expr *expr_stmt; // 8 - Decl *var_stmt; // 8 - AstReturnStmt return_stmt; // 16 - AstWhileStmt while_stmt; // 24 - AstDoStmt do_stmt; // 32 - AstIfStmt if_stmt; // 32 - AstDeferStmt defer_stmt; // 32 - AstSwitchStmt switch_stmt; // 24 - AstCaseStmt case_stmt; // 32 - AstCtSwitchStmt ct_switch_stmt; // 16 - AstContinueBreakStmt contbreak_stmt; // 8 - AstNextcaseStmt nextcase_stmt; // 16 + FlowCommon flow; // Shared struct + AstAsmStmt asm_stmt; // 16 + AstCompoundStmt compound_stmt; // 12 + Decl *declare_stmt; // 8 + Expr *expr_stmt; // 8 + Decl *var_stmt; // 8 + AstReturnStmt return_stmt; // 16 + AstIfStmt if_stmt; // 32 + AstDeferStmt defer_stmt; // 8 + AstSwitchStmt switch_stmt; // 40 + AstCaseStmt case_stmt; // 32 + AstCtSwitchStmt ct_switch_stmt; // 16 + AstContinueBreakStmt contbreak_stmt;// 24 + AstNextcaseStmt nextcase_stmt; // 32 AstForStmt for_stmt; // 32 - AstForeachStmt foreach_stmt; + AstForeachStmt foreach_stmt; // 40 AstCtIfStmt ct_if_stmt; // 24 - AstId ct_else_stmt; // 8 - AstCtForeachStmt ct_foreach_stmt; // 64 - AstScopedStmt scoped_stmt; // 16 - AstAssertStmt ct_assert_stmt; - AstAssertStmt assert_stmt; - AstDocDirective *directives; + AstId ct_else_stmt; // 4 + AstCtForeachStmt ct_foreach_stmt; // 40 + AstAssertStmt ct_assert_stmt; // 16 + AstAssertStmt assert_stmt; // 16 + AstDocDirective *directives; // 8 }; } Ast; - +//static_assert(sizeof(AstContinueBreakStmt) == 24, "Ooops"); +//static_assert(sizeof(Ast) == 56, "Oops"); typedef struct Module_ { @@ -1409,10 +1382,12 @@ typedef struct SemaContext_ }; Decl *current_macro; ScopeId scope_id; + bool ensures; AstId break_target; AstId break_defer; AstId continue_target; AstId continue_defer; + AstId block_return_defer; AstId next_target; Ast *next_switch; AstId next_defer; @@ -1427,7 +1402,6 @@ typedef struct SemaContext_ // Reusable returns cache. Ast **returns_cache; }; - Decl *return_var; Type *rtype; struct SemaContext_ *yield_context; Decl** locals; @@ -2464,25 +2438,45 @@ static inline bool type_is_promotable_float(Type *type) return type_is_float(type->canonical) && type->builtin.bytesize < type_double->builtin.bytesize; } -#define MACRO_COPY_DECL(x) x = copy_decl(x) -#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(x) -#define MACRO_COPY_EXPR(x) x = copy_expr(x) -#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(x) -#define MACRO_COPY_TYPE(x) x = copy_type_info(x) -#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(x) -#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(x) -#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(x) -#define MACRO_COPY_AST(x) x = ast_copy_deep(x) -#define MACRO_COPY_ASTID(x) x = astid_copy_deep(x) +#define MAX_FIXUPS 0xFFFFF -Expr **copy_expr_list(Expr **expr_list); -Expr *copy_expr(Expr *source_expr); -Ast *ast_copy_deep(Ast *source); -Ast **copy_ast_list(Ast **to_copy); -Decl *decl_copy_local_from_macro(Decl *to_copy); -Decl *copy_decl(Decl *decl); -Decl **copy_decl_list(Decl **decl_list); -TypeInfo *copy_type_info(TypeInfo *source); +typedef struct +{ + void *original; + void *new_ptr; +} CopyFixup; + +typedef struct CopyStruct_ +{ + CopyFixup fixups[MAX_FIXUPS]; + CopyFixup *current_fixup; +} CopyStruct; + +#define MACRO_COPY_DECL(x) x = copy_decl(c, x) +#define MACRO_COPY_DECLID(x) x = declid_copy_deep(c, x) +#define MACRO_COPY_DECL_LIST(x) x = copy_decl_list(c, x) +#define MACRO_COPY_EXPR(x) x = copy_expr(c, x) +#define MACRO_COPY_EXPRID(x) x = exprid_copy_deep(c, x) +#define MACRO_COPY_TYPE(x) x = copy_type_info(c, x) +#define MACRO_COPY_TYPE_LIST(x) x = type_info_copy_list_from_macro(c, x) +#define MACRO_COPY_EXPR_LIST(x) x = copy_expr_list(c, x) +#define MACRO_COPY_AST_LIST(x) x = copy_ast_list(c, x) +#define MACRO_COPY_AST(x) x = ast_copy_deep(c, x) +#define MACRO_COPY_ASTID(x) x = astid_copy_deep(c, x) + + +Expr *expr_macro_copy(Expr *source_expr); +Decl **decl_copy_list(Decl **decl_list); +Ast *ast_macro_copy(Ast *source_ast); + +Expr **copy_expr_list(CopyStruct *c, Expr **expr_list); +Expr *copy_expr(CopyStruct *c, Expr *source_expr); +Ast *ast_copy_deep(CopyStruct *c, Ast *source); +Ast **copy_ast_list(CopyStruct *c, Ast **to_copy); +Decl *decl_copy_local_from_macro(CopyStruct *c, Decl *to_copy); +Decl *copy_decl(CopyStruct *c, Decl *decl); +Decl **copy_decl_list(CopyStruct *c, Decl **decl_list); +TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source); /** * Minimum alignment, values are either offsets or alignments. diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 64264d302..4384012fa 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -1,53 +1,114 @@ #include "compiler_internal.h" -Expr **copy_expr_list(Expr **expr_list) +#define SCOPE_FIXUP_START do { CopyFixup *current = c->current_fixup; +#define SCOPE_FIXUP_END c->current_fixup = current; } while (0) + + + +static inline void copy_reg_ref(CopyStruct *c, void *original, void *result) +{ + c->current_fixup->new_ptr = result; + c->current_fixup->original = original; + c->current_fixup++; + if (c->current_fixup == &c->fixups[MAX_FIXUPS]) + { + error_exit("Too many fixups for macros."); + } +} + +static inline void *fixup(CopyStruct *c, void *original) +{ + CopyFixup *fixup_entry = c->current_fixup; + CopyFixup *first = &c->fixups[0]; + while (fixup_entry != first) + { + fixup_entry--; + if (original == fixup_entry->original) + { + return fixup_entry->new_ptr; + } + } + return NULL; +} + +INLINE void fixup_decl(CopyStruct *c, Decl **decl_ref) +{ + Decl *new_decl = fixup(c, *decl_ref); + if (new_decl) *decl_ref = new_decl; +} + +INLINE void fixup_declid(CopyStruct *c, DeclId *declid_ref) +{ + DeclId id = *declid_ref; + if (!id) return; + Decl *decl = declptr(id); + decl = fixup(c, decl); + if (decl) *declid_ref = declid(decl); +} + +INLINE void fixup_astid(CopyStruct *c, AstId *astid_ref) +{ + AstId id = *astid_ref; + if (!id) return; + Ast *ast = astptr(id); + ast = fixup(c, ast); + if (ast) *astid_ref = astid(ast); +} + +Expr **copy_expr_list(CopyStruct *c, Expr **expr_list) { Expr **result = NULL; VECEACH(expr_list, i) { - vec_add(result, copy_expr(expr_list[i])); + vec_add(result, copy_expr(c, expr_list[i])); } return result; } -static inline Decl *decl_copy_label_from_macro(Decl *to_copy, Ast *ast) +static inline Decl *decl_copy_label_from_macro(CopyStruct *c, Decl *to_copy, Ast *ast) { if (!to_copy) return NULL; - to_copy = copy_decl(to_copy); + to_copy = copy_decl(c, to_copy); to_copy->label.parent = astid(ast); return to_copy; } -static inline void copy_flow(Ast *ast) +static inline void copy_flow(CopyStruct *c, Ast *ast) { - ast->flow.label = decl_copy_label_from_macro(ast->flow.label, ast); + ast->flow.label = decl_copy_label_from_macro(c, ast->flow.label, ast); } -static TypeInfo** type_info_copy_list_from_macro(TypeInfo **to_copy) +static TypeInfo** type_info_copy_list_from_macro(CopyStruct *c, TypeInfo **to_copy) { TypeInfo **result = NULL; VECEACH(to_copy, i) { - vec_add(result, copy_type_info(to_copy[i])); + vec_add(result, copy_type_info(c, to_copy[i])); } return result; } -static AstId astid_copy_deep(AstId source) +INLINE AstId astid_copy_deep(CopyStruct *c, AstId source) { if (!source) return 0; - return astid(ast_copy_deep(astptr(source))); + return astid(ast_copy_deep(c, astptr(source))); } -static ExprId exprid_copy_deep(ExprId source) +INLINE ExprId exprid_copy_deep(CopyStruct *c, ExprId source) { if (!source) return 0; - return exprid(copy_expr(exprptr(source))); + return exprid(copy_expr(c, exprptr(source))); +} + +INLINE DeclId declid_copy_deep(CopyStruct *c, DeclId source) +{ + if (!source) return 0; + return declid(copy_decl(c, declptr(source))); } -static DesignatorElement **macro_copy_designator_list(DesignatorElement **list) +static DesignatorElement **macro_copy_designator_list(CopyStruct *c, DesignatorElement **list) { DesignatorElement **result = NULL; VECEACH(list, i) @@ -74,8 +135,21 @@ static DesignatorElement **macro_copy_designator_list(DesignatorElement **list) return result; } +static CopyStruct copy_struct; -Expr *copy_expr(Expr *source_expr) +Ast *ast_macro_copy(Ast *source_ast) +{ + copy_struct.current_fixup = copy_struct.fixups; + return ast_copy_deep(©_struct, source_ast); +} + +Expr *expr_macro_copy(Expr *source_expr) +{ + copy_struct.current_fixup = copy_struct.fixups; + return copy_expr(©_struct, source_expr); +} + +Expr *copy_expr(CopyStruct *c, Expr *source_expr) { if (!source_expr) return NULL; Expr *expr = expr_copy(source_expr); @@ -86,9 +160,9 @@ Expr *copy_expr(Expr *source_expr) case EXPR_ARGV_TO_SUBARRAY: UNREACHABLE case EXPR_FLATPATH: - case EXPR_UNDEF: case EXPR_NOP: case EXPR_BUILTIN: + case EXPR_RETVAL: return expr; case EXPR_DECL: MACRO_COPY_DECL(expr->decl_expr); @@ -107,16 +181,25 @@ Expr *copy_expr(Expr *source_expr) MACRO_COPY_EXPR_LIST(expr->catch_unwrap_expr.exprs); MACRO_COPY_TYPE(expr->catch_unwrap_expr.type); return expr; - case EXPR_CT_IDENT: case EXPR_IDENTIFIER: + if (expr->resolve_status == RESOLVE_DONE) + { + fixup_decl(c, &expr->identifier_expr.decl); + } + return expr; + case EXPR_CT_IDENT: case EXPR_HASH_IDENT: + assert(expr->resolve_status != RESOLVE_DONE); + return expr; case EXPR_COMPILER_CONST: return expr; case EXPR_MACRO_EXPANSION: - MACRO_COPY_EXPR(expr->macro_expansion_expr.inner); + SCOPE_FIXUP_START + MACRO_COPY_EXPR(expr->macro_expansion_expr.inner); + SCOPE_FIXUP_END; return expr; case EXPR_DESIGNATOR: - expr->designator_expr.path = macro_copy_designator_list(expr->designator_expr.path); + expr->designator_expr.path = macro_copy_designator_list(c, expr->designator_expr.path); MACRO_COPY_EXPR(expr->designator_expr.value); return expr; case EXPR_TYPEINFO: @@ -166,7 +249,7 @@ Expr *copy_expr(Expr *source_expr) MACRO_COPY_TYPE(expr->expr_compound_literal.type_info); return expr; case EXPR_EXPR_BLOCK: - expr->expr_block.first_stmt = astid_copy_deep(expr->expr_block.first_stmt); + MACRO_COPY_ASTID(expr->expr_block.first_stmt); return expr; case EXPR_POISONED: return source_expr; @@ -193,11 +276,18 @@ Expr *copy_expr(Expr *source_expr) MACRO_COPY_TYPE(expr->typeid_expr); return expr; case EXPR_CALL: - if (expr->resolve_status != RESOLVE_DONE || expr->call_expr.is_pointer_call) + if (expr->call_expr.is_func_ref) { - MACRO_COPY_EXPR(expr->call_expr.function); + fixup_declid(c, &expr->call_expr.func_ref); } + else + { + MACRO_COPY_EXPRID(expr->call_expr.function); + } + MACRO_COPY_ASTID(expr->call_expr.body); + MACRO_COPY_DECL_LIST(expr->call_expr.body_arguments); MACRO_COPY_EXPR_LIST(expr->call_expr.arguments); + if (expr->call_expr.attributes) REMINDER("Copy attributes?"); return expr; case EXPR_SUBSCRIPT: case EXPR_SUBSCRIPT_ADDR: @@ -222,13 +312,15 @@ Expr *copy_expr(Expr *source_expr) MACRO_COPY_TYPE(expr->cast_expr.type_info); return expr; case EXPR_SCOPED_EXPR: - MACRO_COPY_EXPR(expr->expr_scope.expr); + SCOPE_FIXUP_START + MACRO_COPY_EXPR(expr->expr_scope.expr); + SCOPE_FIXUP_END; return expr; } UNREACHABLE } -AstDocDirective *doc_directive_copy(AstDocDirective *docs) +AstDocDirective *doc_directive_copy(CopyStruct *c, AstDocDirective *docs) { AstDocDirective *directive_new = NULL; VECEACH(docs, i) @@ -252,140 +344,167 @@ AstDocDirective *doc_directive_copy(AstDocDirective *docs) return directive_new; } -Ast *ast_copy_deep(Ast *source) +Ast *ast_copy_deep(CopyStruct *c, Ast *source) { if (!source) return NULL; Ast *ast = ast_copy(source); - ast->next = astid_copy_deep(ast->next); + Ast *first_return = ast; + AstId *assign_to = NULL; +RETRY: + if (assign_to) + { + ast = ast_copy(source); + *assign_to = astid(ast); + } switch (source->ast_kind) { case AST_POISONED: - return ast; + break; case AST_ASM_STMT: MACRO_COPY_EXPR(ast->asm_stmt.body); - return ast; + break; case AST_ASSERT_STMT: MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); MACRO_COPY_EXPR(ast->ct_assert_stmt.message); - return ast; + break; case AST_BREAK_STMT: case AST_CONTINUE_STMT: - return ast; + if (ast->contbreak_stmt.is_resolved) + { + fixup_astid(c, &ast->contbreak_stmt.ast); + } + break; case AST_CASE_STMT: + copy_reg_ref(c, source, ast); MACRO_COPY_AST(ast->case_stmt.body); MACRO_COPY_EXPR(ast->case_stmt.expr); MACRO_COPY_EXPR(ast->case_stmt.to_expr); - return ast; + break; case AST_COMPOUND_STMT: - ast->compound_stmt.first_stmt = astid_copy_deep(ast->compound_stmt.first_stmt); - return ast; + MACRO_COPY_ASTID(ast->compound_stmt.first_stmt); + break; case AST_CT_ASSERT: MACRO_COPY_EXPR(ast->ct_assert_stmt.message); MACRO_COPY_EXPR(ast->ct_assert_stmt.expr); - return ast; + break; case AST_CT_IF_STMT: MACRO_COPY_EXPR(ast->ct_if_stmt.expr); MACRO_COPY_AST(ast->ct_if_stmt.elif); MACRO_COPY_ASTID(ast->ct_if_stmt.then); - return ast; + break; case AST_CT_ELSE_STMT: MACRO_COPY_ASTID(ast->ct_else_stmt); - return ast; + break; case AST_CT_FOREACH_STMT: - ast->ct_foreach_stmt.body = astid_copy_deep(ast->ct_foreach_stmt.body); - MACRO_COPY_EXPR(ast->ct_foreach_stmt.expr); - return ast; + MACRO_COPY_ASTID(ast->ct_foreach_stmt.body); + MACRO_COPY_EXPRID(ast->ct_foreach_stmt.expr); + break; case AST_CT_SWITCH_STMT: MACRO_COPY_EXPR(ast->ct_switch_stmt.cond); MACRO_COPY_AST_LIST(ast->ct_switch_stmt.body); - return ast; + break; case AST_DECLARE_STMT: MACRO_COPY_DECL(ast->declare_stmt); - return ast; + break; case AST_DEFAULT_STMT: MACRO_COPY_AST(ast->case_stmt.body); - return ast; + break; case AST_DEFER_STMT: - assert(!ast->defer_stmt.prev_defer); - MACRO_COPY_AST(ast->defer_stmt.body); - return ast; - case AST_DO_STMT: - copy_flow(ast); - MACRO_COPY_ASTID(ast->do_stmt.body); - MACRO_COPY_EXPR(ast->do_stmt.expr); - return ast; + MACRO_COPY_ASTID(ast->defer_stmt.body); + copy_reg_ref(c, source, ast); + fixup_astid(c, &ast->defer_stmt.prev_defer); + break; case AST_EXPR_STMT: MACRO_COPY_EXPR(ast->expr_stmt); - return ast; + break; case AST_FOR_STMT: case AST_CT_FOR_STMT: - copy_flow(ast); - MACRO_COPY_EXPR(ast->for_stmt.cond); - MACRO_COPY_EXPR(ast->for_stmt.incr); - ast->for_stmt.body = astid_copy_deep(ast->for_stmt.body); - MACRO_COPY_EXPR(ast->for_stmt.init); - return ast; + copy_reg_ref(c, source, ast); + SCOPE_FIXUP_START + copy_flow(c, ast); + MACRO_COPY_EXPRID(ast->for_stmt.init); + MACRO_COPY_EXPRID(ast->for_stmt.cond); + MACRO_COPY_ASTID(ast->for_stmt.body); + MACRO_COPY_EXPRID(ast->for_stmt.incr); + SCOPE_FIXUP_END; + break; case AST_FOREACH_STMT: - copy_flow(ast); - MACRO_COPY_DECL(ast->foreach_stmt.index); - MACRO_COPY_DECL(ast->foreach_stmt.variable); - MACRO_COPY_EXPR(ast->foreach_stmt.enumeration); - MACRO_COPY_AST(ast->foreach_stmt.body); - return ast; + copy_reg_ref(c, source, ast); + SCOPE_FIXUP_START + copy_flow(c, ast); + MACRO_COPY_EXPRID(ast->foreach_stmt.enumeration); + MACRO_COPY_DECLID(ast->foreach_stmt.index); + MACRO_COPY_DECLID(ast->foreach_stmt.variable); + MACRO_COPY_ASTID(ast->foreach_stmt.body); + SCOPE_FIXUP_END; + break; case AST_IF_STMT: - copy_flow(ast); - MACRO_COPY_EXPR(ast->if_stmt.cond); - MACRO_COPY_AST(ast->if_stmt.else_body); - MACRO_COPY_AST(ast->if_stmt.then_body); - return ast; + // We don't scope "if" for the simple reason that it might introduce a wrapper alias. + copy_reg_ref(c, source, ast); + copy_flow(c, ast); + MACRO_COPY_EXPRID(ast->if_stmt.cond); + MACRO_COPY_ASTID(ast->if_stmt.else_body); + MACRO_COPY_ASTID(ast->if_stmt.then_body); + break; case AST_NEXT_STMT: MACRO_COPY_EXPR(ast->nextcase_stmt.expr); - return ast; + break; case AST_NOP_STMT: - return ast; + break; + case AST_BLOCK_EXIT_STMT: case AST_RETURN_STMT: MACRO_COPY_EXPR(ast->return_stmt.expr); - return ast; - case AST_SCOPED_STMT: - ast->scoped_stmt.stmt = astid_copy_deep(ast->scoped_stmt.stmt); - return ast; + MACRO_COPY_ASTID(ast->return_stmt.cleanup); + break; case AST_SWITCH_STMT: case AST_IF_CATCH_SWITCH_STMT: - copy_flow(ast); - MACRO_COPY_EXPR(ast->switch_stmt.cond); - MACRO_COPY_AST_LIST(ast->switch_stmt.cases); - return ast; - case AST_WHILE_STMT: - copy_flow(ast); - MACRO_COPY_EXPRID(ast->while_stmt.cond); - MACRO_COPY_ASTID(ast->while_stmt.body); - return ast; + SCOPE_FIXUP_START + copy_flow(c, ast); + MACRO_COPY_EXPRID(ast->switch_stmt.cond); + MACRO_COPY_AST_LIST(ast->switch_stmt.cases); + SCOPE_FIXUP_END; + break; } - UNREACHABLE; + assign_to = &ast->next; + AstId next = *assign_to; + if (!next) return first_return; + source = astptr(next); + goto RETRY; } -Ast **copy_ast_list(Ast **to_copy) +Ast **copy_ast_list(CopyStruct *c, Ast **to_copy) { Ast **result = NULL; VECEACH(to_copy, i) { - vec_add(result, ast_copy_deep(to_copy[i])); + vec_add(result, ast_copy_deep(c, to_copy[i])); } return result; } -Decl **copy_decl_list(Decl **decl_list) +Decl **decl_copy_list(Decl **decl_list) +{ + copy_struct.current_fixup = copy_struct.fixups; + Decl **result = NULL; + VECEACH(decl_list, i) + { + vec_add(result, copy_decl(©_struct, decl_list[i])); + } + return result; +} + +Decl **copy_decl_list(CopyStruct *c, Decl **decl_list) { Decl **result = NULL; VECEACH(decl_list, i) { - vec_add(result, copy_decl(decl_list[i])); + vec_add(result, copy_decl(c, decl_list[i])); } return result; } -Decl *decl_copy_local_from_macro(Decl *to_copy) +Decl *decl_copy_local_from_macro(CopyStruct *c, Decl *to_copy) { if (!to_copy) return NULL; assert(to_copy->decl_kind == DECL_VAR); @@ -395,7 +514,7 @@ Decl *decl_copy_local_from_macro(Decl *to_copy) return copy; } -TypeInfo *copy_type_info(TypeInfo *source) +TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source) { if (!source) return NULL; TypeInfo *copy = type_info_copy(source); @@ -410,27 +529,27 @@ TypeInfo *copy_type_info(TypeInfo *source) case TYPE_INFO_EVALTYPE: case TYPE_INFO_EXPRESSION: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->unresolved_type_expr = copy_expr(source->unresolved_type_expr); + copy->unresolved_type_expr = copy_expr(c, source->unresolved_type_expr); return copy; case TYPE_INFO_VECTOR: case TYPE_INFO_ARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.len = copy_expr(source->array.len); - copy->array.base = copy_type_info(source->array.base); + copy->array.len = copy_expr(c, source->array.len); + copy->array.base = copy_type_info(c, source->array.base); return copy; case TYPE_INFO_INFERRED_ARRAY: case TYPE_INFO_SUBARRAY: assert(source->resolve_status == RESOLVE_NOT_DONE); - copy->array.base = copy_type_info(source->array.base); + copy->array.base = copy_type_info(c, source->array.base); return copy; case TYPE_INFO_POINTER: - copy->pointer = copy_type_info(source->pointer); + copy->pointer = copy_type_info(c, source->pointer); return copy; } UNREACHABLE } -static void copy_function_signature_deep(FunctionSignature *signature) +static void copy_function_signature_deep(CopyStruct *c, FunctionSignature *signature) { MACRO_COPY_DECL_LIST(signature->params); MACRO_COPY_TYPE(signature->returntype); @@ -446,7 +565,7 @@ void copy_decl_type(Decl *decl) decl->type = copy; } -static Attr **copy_attributes(Attr** attr_list) +static Attr **copy_attributes(CopyStruct *c, Attr** attr_list) { if (!attr_list) return attr_list; Attr** list = NULL; @@ -460,12 +579,13 @@ static Attr **copy_attributes(Attr** attr_list) } return list; } -Decl *copy_decl(Decl *decl) +Decl *copy_decl(CopyStruct *c, Decl *decl) { if (!decl) return NULL; Decl *copy = decl_copy(decl); - copy->docs = doc_directive_copy(copy->docs); - copy->attributes = copy_attributes(copy->attributes); + copy_reg_ref(c, decl, copy); + copy->docs = doc_directive_copy(c, copy->docs); + copy->attributes = copy_attributes(c, copy->attributes); switch (decl->decl_kind) { case DECL_POISONED: @@ -490,7 +610,7 @@ Decl *copy_decl(Decl *decl) case DECL_FUNC: MACRO_COPY_TYPE(copy->func_decl.type_parent); copy->func_decl.annotations = NULL; - copy_function_signature_deep(©->func_decl.function_signature); + copy_function_signature_deep(c, ©->func_decl.function_signature); MACRO_COPY_AST(copy->func_decl.body); break; case DECL_VAR: @@ -518,7 +638,7 @@ Decl *copy_decl(Decl *decl) case DECL_TYPEDEF: if (copy->typedef_decl.is_func) { - copy_function_signature_deep(©->typedef_decl.function_signature); + copy_function_signature_deep(c, ©->typedef_decl.function_signature); break; } MACRO_COPY_TYPE(copy->typedef_decl.type_info); @@ -527,7 +647,7 @@ Decl *copy_decl(Decl *decl) MACRO_COPY_DECL_LIST(copy->methods); if (copy->distinct_decl.typedef_decl.is_func) { - copy_function_signature_deep(©->distinct_decl.typedef_decl.function_signature); + copy_function_signature_deep(c, ©->distinct_decl.typedef_decl.function_signature); break; } MACRO_COPY_TYPE(copy->distinct_decl.typedef_decl.type_info); @@ -578,7 +698,7 @@ Decl *copy_decl(Decl *decl) case DEFINE_IDENT_ALIAS: break; case DEFINE_ATTRIBUTE: - decl->define_decl.attributes.attrs = copy_attributes(decl->define_decl.attributes.attrs); + decl->define_decl.attributes.attrs = copy_attributes(c, decl->define_decl.attributes.attrs); MACRO_COPY_DECL_LIST(decl->define_decl.attributes.params); break; } diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 1a2619688..392cb792b 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -59,7 +59,6 @@ typedef enum AST_DECLARE_STMT, AST_DEFAULT_STMT, AST_DEFER_STMT, - AST_DO_STMT, AST_EXPR_STMT, AST_FOR_STMT, AST_FOREACH_STMT, @@ -67,10 +66,9 @@ typedef enum AST_IF_STMT, AST_NOP_STMT, AST_RETURN_STMT, + AST_BLOCK_EXIT_STMT, AST_SWITCH_STMT, AST_NEXT_STMT, - AST_WHILE_STMT, - AST_SCOPED_STMT, } AstKind; @@ -200,6 +198,7 @@ typedef enum EXPR_MACRO_BLOCK, EXPR_MACRO_EXPANSION, EXPR_IDENTIFIER, + EXPR_RETVAL, EXPR_FLATPATH, EXPR_INITIALIZER_LIST, EXPR_DESIGNATED_INITIALIZER_LIST, @@ -221,7 +220,6 @@ typedef enum EXPR_TYPEOFANY, EXPR_TYPEINFO, EXPR_UNARY, - EXPR_UNDEF, EXPR_VARIANTSWITCH, EXPR_NOP, } ExprKind; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 9711b4630..0a4647836 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1082,10 +1082,16 @@ static inline void gencontext_emit_access_addr(GenContext *context, BEValue *be_ gencontext_emit_member_addr(context, be_value, type_lowering(parent->type)->decl, member); } -static void gencontext_emit_scoped_expr(GenContext *context, BEValue *value, Expr *expr) +static void llvm_emit_scoped_expr(GenContext *c, BEValue *value, Expr *expr) { - llvm_emit_expr(context, value, expr->expr_scope.expr); - llvm_emit_defer(context, expr->expr_scope.defers.start, expr->expr_scope.defers.end); + llvm_emit_expr(c, value, expr->expr_scope.expr); + AstId current = expr->expr_scope.defer_stmts; + while (current) + { + Ast *ast = astptr(current); + llvm_emit_stmt(c, ast); + current = ast->next; + } } @@ -3521,7 +3527,7 @@ static inline void llvm_emit_rethrow_expr(GenContext *c, BEValue *be_value, Expr // Ensure we are on a branch that is non empty. if (llvm_emit_check_block_branch(c)) { - llvm_emit_defer(c, expr->rethrow_expr.defer, 0); + llvm_emit_statement_chain(c, expr->rethrow_expr.cleanup); BEValue value; llvm_value_set_address_abi_aligned(&value, error_var, type_anyerr); llvm_emit_return_abi(c, NULL, &value); @@ -4430,7 +4436,7 @@ LLVMAtomicOrdering llvm_atomic_ordering(Atomicity atomicity) void llvm_emit_builtin_call(GenContext *c, BEValue *result_value, Expr *expr) { - BuiltinFunction func = expr->call_expr.function->builtin_expr.builtin; + BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin; if (func == BUILTIN_VOLATILE_STORE) { BEValue value; @@ -4496,9 +4502,9 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) FunctionPrototype *prototype; // 1. Call through a pointer. - if (expr->call_expr.is_pointer_call) + if (!expr->call_expr.is_func_ref) { - Expr *function = expr->call_expr.function; + Expr *function = exprptr(expr->call_expr.function); // 1a. Find the pointee type for the function pointer: Type *type = function->type->canonical->pointer; @@ -4508,7 +4514,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) // 1c. Evaluate the pointer expression. BEValue func_value; - llvm_emit_expr(c, &func_value, expr->call_expr.function); + llvm_emit_expr(c, &func_value, function); // 1d. Load it as a value func = llvm_load_value_store(c, &func_value); @@ -4520,7 +4526,7 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) { // 2a. Get the function declaration - Decl *function_decl = expr->call_expr.func_ref; + Decl *function_decl = declptr(expr->call_expr.func_ref); always_inline = function_decl->func_decl.attr_inline; // 2b. Set signature, function and function type @@ -4974,11 +4980,11 @@ static inline void llvm_emit_return_block(GenContext *context, BEValue *be_value // Do we have a void function? That's the only // possible case if the last statement isn't return. - if (value->ast_kind != AST_RETURN_STMT) break; + if (value->ast_kind != AST_BLOCK_EXIT_STMT) break; // Defers? In that case we also use the default behaviour. // We might optimize this later. - if (value->return_stmt.defer) break; + if (value->return_stmt.cleanup) break; Expr *ret_expr = value->return_stmt.expr; @@ -5457,6 +5463,9 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_COND: case EXPR_MACRO_EXPANSION: UNREACHABLE + case EXPR_RETVAL: + *value = c->retval; + return; case EXPR_ARGV_TO_SUBARRAY: llvm_emit_argv_to_subarray(c, value, expr); return; @@ -5469,9 +5478,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_CATCH_UNWRAP: llvm_emit_catch_unwrap(c, value, expr); return; - case EXPR_UNDEF: - // Should never reach this. - UNREACHABLE case EXPR_PTR: llvm_emit_ptr(c, value, expr); return; @@ -5518,7 +5524,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) llvm_emit_expr_block(c, value, expr); return; case EXPR_SCOPED_EXPR: - gencontext_emit_scoped_expr(c, value, expr); + llvm_emit_scoped_expr(c, value, expr); return; case EXPR_UNARY: gencontext_emit_unary_expr(c, value, expr); diff --git a/src/compiler/llvm_codegen_function.c b/src/compiler/llvm_codegen_function.c index b0c073cf1..f377a8a59 100644 --- a/src/compiler/llvm_codegen_function.c +++ b/src/compiler/llvm_codegen_function.c @@ -490,8 +490,6 @@ void llvm_emit_function_body(GenContext *context, Decl *decl) // Insert a return (and defer) if needed. if (context->current_block && !LLVMGetBasicBlockTerminator(context->current_block)) { - assert(!decl->func_decl.body->compound_stmt.defer_list.end); - llvm_emit_defer(context, decl->func_decl.body->compound_stmt.defer_list.start, 0); llvm_emit_return_implicit(context); } diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index 3ee1258d6..b50823744 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -87,7 +87,6 @@ typedef struct int simple_return_expressions; unsigned pointer_alignment; int return_expressions; - Ast **defer_stack; DebugContext debug; Module *code_module; LLVMValueRef return_out; @@ -95,6 +94,7 @@ typedef struct LLVMBasicBlockRef block_return_exit; LLVMBasicBlockRef block_failable_exit; LLVMValueRef block_error_var; + BEValue retval; int in_block; bool current_block_is_target : 1; bool did_call_stack_save : 1; @@ -239,7 +239,7 @@ BEValue llvm_emit_assign_expr(GenContext *context, BEValue *ref, Expr *expr, LLV static inline LLVMValueRef llvm_emit_bitcast(GenContext *context, LLVMValueRef value, Type *type); void llvm_emit_block(GenContext *c, LLVMBasicBlockRef next_block); void llvm_emit_br(GenContext *c, LLVMBasicBlockRef next_block); -void llvm_emit_compound_stmt(GenContext *context, Ast *ast); +void llvm_emit_compound_stmt(GenContext *c, Ast *ast); LLVMValueRef llvm_emit_const_bitstruct(GenContext *c, ConstInitializer *initializer); void llvm_emit_convert_value_from_coerced(GenContext *c, BEValue *result, LLVMTypeRef coerced, LLVMValueRef value, Type *original_type); void llvm_emit_coerce_store(GenContext *c, LLVMValueRef addr, AlignSize alignment, LLVMTypeRef coerced, LLVMValueRef value, LLVMTypeRef target_type); @@ -254,7 +254,7 @@ void llvm_emit_debug_location(GenContext *context, SourceSpan location); void llvm_emit_debug_parameter(GenContext *c, Decl *parameter, unsigned index); void llvm_emit_debug_local_var(GenContext *c, Decl *var); void llvm_emit_debug_global_var(GenContext *c, Decl *global); -void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end); + void llvm_emit_extern_decl(GenContext *context, Decl *decl); LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_init); void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr); @@ -475,6 +475,14 @@ static inline void llvm_set_alignment(LLVMValueRef alloca, AlignSize alignment) void llvm_set_error_exit(GenContext *c, LLVMBasicBlockRef block); void llvm_set_error_exit_and_value(GenContext *c, LLVMBasicBlockRef block, LLVMValueRef value); +INLINE void llvm_emit_statement_chain(GenContext *c, AstId current) +{ + while (current) + { + llvm_emit_stmt(c, ast_next(¤t)); + } +} + #define EMIT_LOC(c, x) do { if (c->debug.builder) llvm_emit_debug_location(c, x->span); } while (0); #define PUSH_ERROR() \ diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 4ff48ef50..0b9e38ae7 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -7,22 +7,17 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast); -void llvm_emit_compound_stmt(GenContext *context, Ast *ast) +void llvm_emit_compound_stmt(GenContext *c, Ast *ast) { - if (llvm_use_debug(context)) + if (llvm_use_debug(c)) { - llvm_debug_push_lexical_scope(context, ast->span); + llvm_debug_push_lexical_scope(c, ast->span); } assert(ast->ast_kind == AST_COMPOUND_STMT); - AstId current = ast->compound_stmt.first_stmt; - while (current) + llvm_emit_statement_chain(c, ast->compound_stmt.first_stmt); + if (llvm_use_debug(c)) { - llvm_emit_stmt(context, ast_next(¤t)); - } - llvm_emit_defer(context, ast->compound_stmt.defer_list.start, ast->compound_stmt.defer_list.end); - if (llvm_use_debug(context)) - { - llvm_debug_scope_pop(context); + llvm_debug_scope_pop(c); } } @@ -67,7 +62,7 @@ LLVMValueRef llvm_emit_local_decl(GenContext *c, Decl *decl) if (init) { // If we don't have undef, then make an assign. - if (init->expr_kind != EXPR_UNDEF) + if (!decl->var.no_init) { BEValue value; llvm_value_set_decl_address(&value, decl); @@ -152,21 +147,14 @@ void llvm_emit_jmp(GenContext *context, LLVMBasicBlockRef block) llvm_emit_block(context, post_jump_block); } -static inline void gencontext_emit_return(GenContext *c, Ast *ast) +static inline void llvm_emit_return(GenContext *c, Ast *ast) { - bool in_expression_block = c->in_block > 0; - PUSH_ERROR(); LLVMBasicBlockRef error_return_block = NULL; LLVMValueRef error_out = NULL; - if (in_expression_block) - { - c->error_var = c->block_error_var; - c->catch_block = c->block_failable_exit; - } - else if (type_is_failable(c->cur_func_decl->type->func.prototype->rtype)) + if (type_is_failable(c->cur_func_decl->type->func.prototype->rtype)) { error_return_block = llvm_basic_block_new(c, "err_retblock"); error_out = llvm_emit_alloca_aligned(c, type_anyerr, "reterr"); @@ -180,23 +168,15 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast) { llvm_emit_expr(c, &return_value, ast->return_stmt.expr); llvm_value_fold_failable(c, &return_value); + c->retval = return_value; } POP_ERROR(); - llvm_emit_defer(c, ast->return_stmt.defer, 0); + + llvm_emit_statement_chain(c, ast->return_stmt.cleanup); // Are we in an expression block? - if (in_expression_block) - { - if (c->return_out) - { - llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type)); - } - llvm_emit_jmp(c, c->block_return_exit); - return; - } - if (!has_return_value) { llvm_emit_return_implicit(c); @@ -218,6 +198,34 @@ static inline void gencontext_emit_return(GenContext *c, Ast *ast) llvm_emit_block(c, post_ret_block); } +static inline void llvm_emit_block_exit_return(GenContext *c, Ast *ast) +{ + + PUSH_ERROR(); + + LLVMBasicBlockRef error_return_block = NULL; + LLVMValueRef error_out = NULL; + c->error_var = c->block_error_var; + c->catch_block = c->block_failable_exit; + + bool has_return_value = ast->return_stmt.expr != NULL; + BEValue return_value = { 0 }; + if (has_return_value) + { + llvm_emit_expr(c, &return_value, ast->return_stmt.expr); + llvm_value_fold_failable(c, &return_value); + } + + POP_ERROR(); + + llvm_emit_statement_chain(c, ast->return_stmt.cleanup); + + if (c->return_out) + { + llvm_store_value_aligned(c, c->return_out, &return_value, type_alloca_alignment(return_value.type)); + } + llvm_emit_jmp(c, c->block_return_exit); +} /** @@ -236,7 +244,7 @@ void llvm_emit_if(GenContext *c, Ast *ast) LLVMBasicBlockRef then_block = exit_block; LLVMBasicBlockRef else_block = exit_block; - Ast *then_body = ast->if_stmt.then_body; + Ast *then_body = astptr(ast->if_stmt.then_body); // Only generate a target if if (ast_is_not_empty(then_body)) { @@ -244,12 +252,15 @@ void llvm_emit_if(GenContext *c, Ast *ast) } // We have an optional else block. - if (ast_is_not_empty(ast->if_stmt.else_body)) + AstId else_id = ast->if_stmt.else_body; + Ast *else_body = else_id ? astptr(else_id) : NULL; + if (ast_is_not_empty(else_body)) { else_block = llvm_basic_block_new(c, "if.else"); } - ast->if_stmt.break_block = exit_block; + Expr *cond = exprptr(ast->if_stmt.cond); + ast->if_stmt.codegen.break_block = exit_block; // Output boolean value and switch. @@ -265,7 +276,7 @@ void llvm_emit_if(GenContext *c, Ast *ast) if (then_body->ast_kind == AST_IF_CATCH_SWITCH_STMT) { - llvm_emit_decl_expr_list(c, &be_value, ast->if_stmt.cond, false); + llvm_emit_decl_expr_list(c, &be_value, cond, false); llvm_value_rvalue(c, &be_value); BEValue comp; llvm_emit_int_comp_zero(c, &comp, &be_value, BINARYOP_NE); @@ -277,7 +288,7 @@ void llvm_emit_if(GenContext *c, Ast *ast) goto EMIT_ELSE; } - llvm_emit_decl_expr_list(c, &be_value, ast->if_stmt.cond, true); + llvm_emit_decl_expr_list(c, &be_value, cond, true); llvm_value_rvalue(c, &be_value); @@ -313,7 +324,7 @@ void llvm_emit_if(GenContext *c, Ast *ast) if (then_block != exit_block) { llvm_emit_block(c, then_block); - llvm_emit_stmt(c, ast->if_stmt.then_body); + llvm_emit_stmt(c, then_body); // Jump to exit. llvm_emit_br(c, exit_block); @@ -324,7 +335,7 @@ void llvm_emit_if(GenContext *c, Ast *ast) if (else_block != exit_block) { llvm_emit_block(c, else_block); - llvm_emit_stmt(c, ast->if_stmt.else_body); + llvm_emit_stmt(c, else_body); llvm_emit_br(c, exit_block); } @@ -342,12 +353,12 @@ typedef enum LOOP_NONE } LoopType; -static inline LoopType loop_type_for_cond(Expr *cond, bool skip_first) +static inline LoopType loop_type_for_cond(Expr *cond, bool do_while) { if (!cond) { // We may have do-while (0) - if (skip_first) return LOOP_NONE; + if (do_while) return LOOP_NONE; // OR we have for (int x;;x++) return LOOP_INFINITE; @@ -375,10 +386,10 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) { // First, emit all inits. BEValue value; - if (ast->for_stmt.init) llvm_emit_expr(c, &value, ast->for_stmt.init); + if (ast->for_stmt.init) llvm_emit_expr(c, &value, exprptr(ast->for_stmt.init)); bool no_exit = ast->for_stmt.flow.no_exit; - Expr *incr = ast->for_stmt.incr; + ExprId incr = ast->for_stmt.incr; LLVMBasicBlockRef inc_block = incr ? llvm_basic_block_new(c, "loop.inc") : NULL; Ast *body = astptr(ast->for_stmt.body); @@ -388,7 +399,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) // Skipping first cond? This is do-while semantics bool skip_first = ast->for_stmt.flow.skip_first; - Expr *cond = ast->for_stmt.cond; + ExprId cond_id = ast->for_stmt.cond; + Expr *cond = cond_id ? exprptr(cond_id) : NULL; LoopType loop = loop_type_for_cond(cond, skip_first); // This is the starting block to loop back to, and may either be cond, body or inc @@ -433,8 +445,8 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) continue_block = loop == LOOP_NONE ? exit_block : loop_start_block; } - ast->for_stmt.continue_block = continue_block; - ast->for_stmt.exit_block = exit_block; + ast->for_stmt.codegen.continue_block = continue_block; + ast->for_stmt.codegen.exit_block = exit_block; // We have a normal loop, so we emit a cond. if (loop == LOOP_NORMAL) @@ -527,7 +539,7 @@ void llvm_emit_for_stmt(GenContext *c, Ast *ast) llvm_emit_block(c, inc_block); } BEValue dummy; - llvm_emit_expr(c, &dummy, incr); + llvm_emit_expr(c, &dummy, incr ? exprptr(incr) : NULL); } // Loop back. @@ -686,7 +698,9 @@ static void llvm_emit_switch_jump_table(GenContext *c, static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, Ast *switch_ast) { - bool is_if_chain = switch_ast->switch_stmt.if_chain; + bool is_if_chain = switch_ast->switch_stmt.flow.if_chain; + Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyerr) : exprptr(switch_ast->switch_stmt.cond)->type; + Ast **cases = switch_ast->switch_stmt.cases; ArraySize case_count = vec_size(cases); if (!case_count) @@ -738,8 +752,6 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As case_stmt->case_stmt.backend_block = next_block; } - - Type *switch_type = switch_ast->ast_kind == AST_IF_CATCH_SWITCH_STMT ? type_lowering(type_anyerr) : switch_ast->switch_stmt.cond->type; BEValue switch_var; llvm_value_set_address_abi_aligned(&switch_var, llvm_emit_alloca_aligned(c, switch_type, "switch"), switch_type); switch_ast->switch_stmt.codegen.retry_var = &switch_var; @@ -804,82 +816,54 @@ static void gencontext_emit_switch_body(GenContext *c, BEValue *switch_value, As void gencontext_emit_switch(GenContext *context, Ast *ast) { BEValue switch_value; - llvm_emit_decl_expr_list(context, &switch_value, ast->switch_stmt.cond, false); + llvm_emit_decl_expr_list(context, &switch_value, exprptr(ast->switch_stmt.cond), false); gencontext_emit_switch_body(context, &switch_value, ast); } -void llvm_emit_defer(GenContext *c, AstId defer_start, AstId defer_end) -{ - if (defer_start == defer_end) return; - AstId defer = defer_start; - while (defer && defer != defer_end) - { - Ast *def = astptr(defer); - LLVMBasicBlockRef exit = llvm_basic_block_new(c, "exit"); - Ast *body = def->defer_stmt.body; - def->defer_stmt.codegen.exit_block = exit; - llvm_emit_stmt(c, body); - llvm_emit_br(c, exit); - llvm_emit_block(c, exit); - defer = def->defer_stmt.prev_defer; - } -} - -void gencontext_emit_break(GenContext *context, Ast *ast) +void llvm_emit_break(GenContext *c, Ast *ast) { - llvm_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end); + llvm_emit_statement_chain(c, ast->contbreak_stmt.defers); Ast *jump_target = astptr(ast->contbreak_stmt.ast); LLVMBasicBlockRef jump; switch (jump_target->ast_kind) { case AST_IF_STMT: - jump = jump_target->if_stmt.break_block; - break; - case AST_FOREACH_STMT: - jump = jump_target->foreach_stmt.exit_block; + jump = jump_target->if_stmt.codegen.break_block; break; case AST_FOR_STMT: - jump = jump_target->for_stmt.exit_block; + jump = jump_target->for_stmt.codegen.exit_block; break; - case AST_DO_STMT: - case AST_WHILE_STMT: - UNREACHABLE case AST_IF_CATCH_SWITCH_STMT: case AST_SWITCH_STMT: jump = jump_target->switch_stmt.codegen.exit_block; break; - case AST_DEFER_STMT: - jump = jump_target->defer_stmt.codegen.exit_block; - break; + case AST_FOREACH_STMT: default: UNREACHABLE } - llvm_emit_jmp(context, jump); + llvm_emit_jmp(c, jump); } -void gencontext_emit_continue(GenContext *context, Ast *ast) +void llvm_emit_continue(GenContext *c, Ast *ast) { - llvm_emit_defer(context, ast->contbreak_stmt.defers.start, ast->contbreak_stmt.defers.end); + llvm_emit_statement_chain(c, ast->contbreak_stmt.defers); Ast *jump_target = astptr(ast->contbreak_stmt.ast); LLVMBasicBlockRef jump; switch (jump_target->ast_kind) { case AST_IF_STMT: case AST_SWITCH_STMT: - case AST_WHILE_STMT: - case AST_DO_STMT: - UNREACHABLE case AST_FOREACH_STMT: - jump = jump_target->foreach_stmt.continue_block; + UNREACHABLE break; case AST_FOR_STMT: - jump = jump_target->for_stmt.continue_block; + jump = jump_target->for_stmt.codegen.continue_block; break; default: UNREACHABLE } - llvm_emit_jmp(context, jump); + llvm_emit_jmp(c, jump); } void gencontext_emit_next_stmt(GenContext *context, Ast *ast) @@ -887,23 +871,17 @@ void gencontext_emit_next_stmt(GenContext *context, Ast *ast) Ast *jump_target = astptr(ast->nextcase_stmt.case_switch_stmt); if (jump_target->ast_kind != AST_SWITCH_STMT) { - llvm_emit_defer(context, ast->nextcase_stmt.defers.start, ast->nextcase_stmt.defers.end); + llvm_emit_statement_chain(context, ast->nextcase_stmt.defer_id); llvm_emit_jmp(context, jump_target->case_stmt.backend_block); return; } BEValue be_value; llvm_emit_expr(context, &be_value, ast->nextcase_stmt.switch_expr); llvm_store_value(context, jump_target->switch_stmt.codegen.retry_var, &be_value); - llvm_emit_defer(context, ast->nextcase_stmt.defers.start, ast->nextcase_stmt.defers.end); + llvm_emit_statement_chain(context, ast->nextcase_stmt.defer_id); llvm_emit_jmp(context, jump_target->switch_stmt.codegen.retry_block); } -void gencontext_emit_scoped_stmt(GenContext *context, Ast *ast) -{ - llvm_emit_stmt(context, astptr(ast->scoped_stmt.stmt)); - llvm_emit_defer(context, ast->scoped_stmt.defers.start, ast->scoped_stmt.defers.end); -} - static inline void llvm_emit_assume(GenContext *c, Expr *expr) { @@ -1232,12 +1210,7 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) case AST_POISONED: case AST_IF_CATCH_SWITCH_STMT: case AST_FOREACH_STMT: - case AST_WHILE_STMT: - case AST_DO_STMT: UNREACHABLE - case AST_SCOPED_STMT: - gencontext_emit_scoped_stmt(c, ast); - break; case AST_EXPR_STMT: gencontext_emit_expr_stmt(c, ast); break; @@ -1245,16 +1218,19 @@ void llvm_emit_stmt(GenContext *c, Ast *ast) llvm_emit_local_decl(c, ast->declare_stmt); break; case AST_BREAK_STMT: - gencontext_emit_break(c, ast); + llvm_emit_break(c, ast); break; case AST_CONTINUE_STMT: - gencontext_emit_continue(c, ast); + llvm_emit_continue(c, ast); break; case AST_IF_STMT: llvm_emit_if(c, ast); break; case AST_RETURN_STMT: - gencontext_emit_return(c, ast); + llvm_emit_return(c, ast); + break; + case AST_BLOCK_EXIT_STMT: + llvm_emit_block_exit_return(c, ast); break; case AST_COMPOUND_STMT: llvm_emit_compound_stmt(c, ast); diff --git a/src/compiler/parse_expr.c b/src/compiler/parse_expr.c index ab93b31d5..bf5c346da 100644 --- a/src/compiler/parse_expr.c +++ b/src/compiler/parse_expr.c @@ -565,28 +565,6 @@ static Expr *parse_grouping_expr(ParseContext *c, Expr *left) return expr; } -/** - * initializer - * : initializer_list - * | expr - * | void - * ; - * - * @param c - * @return the parsed expression - */ -Expr *parse_initializer(ParseContext *c) -{ - if (tok_is(c, TOKEN_VOID)) - { - Expr *expr = EXPR_NEW_TOKEN(EXPR_UNDEF); - expr->type = type_void; - expr->resolve_status = RESOLVE_DONE; - advance(c); - return expr; - } - return parse_expr(c); -} /** * initializer_list @@ -719,7 +697,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) advance(c); Expr *call = EXPR_NEW_EXPR(EXPR_CALL, left); - call->call_expr.function = left; + call->call_expr.function = exprid(left); call->call_expr.arguments = params; call->call_expr.unsplat_last = unsplat; call->call_expr.body_arguments = body_args; @@ -731,7 +709,7 @@ static Expr *parse_call_expr(ParseContext *c, Expr *left) } if (tok_is(c, TOKEN_LBRACE)) { - ASSIGN_AST_OR_RET(call->call_expr.body, parse_compound_stmt(c), poisoned_expr); + ASSIGN_ASTID_OR_RET(call->call_expr.body, parse_compound_stmt(c), poisoned_expr); } if (!parse_attributes(c, &call->call_expr.attributes)) return false; return call; @@ -911,6 +889,12 @@ static Expr *parse_ct_call(ParseContext *c, Expr *left) static Expr *parse_identifier(ParseContext *c, Expr *left) { assert(!left && "Unexpected left hand side"); + if (symstr(c) == kw_return) + { + Expr *expr = EXPR_NEW_TOKEN(EXPR_RETVAL); + advance(c); + return expr; + } Expr *expr = EXPR_NEW_TOKEN(EXPR_IDENTIFIER); expr->identifier_expr.ident = symstr(c); expr->identifier_expr.is_const = tok_is(c, TOKEN_CONST_IDENT); diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 00ee02e69..863b4d5a1 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -70,6 +70,22 @@ void recover_top_level(ParseContext *c) } } +static inline bool parse_decl_initializer(ParseContext *c, Decl *decl, bool allow_void) +{ + if (try_consume(c, TOKEN_VOID)) + { + if (!allow_void) + { + SEMA_ERROR_LAST("'void' is not allowed here, it's only allowed for non constant global and local variables."); + return false; + } + decl->var.no_init = true; + return true; + } + ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_expr(c), false); + return true; +} + // --- Parse CT conditional code static inline bool parse_top_level_block(ParseContext *c, Decl ***decls, TokenType end1, TokenType end2, TokenType end3) @@ -699,7 +715,7 @@ Decl *parse_decl_after_type(ParseContext *c, TypeInfo *type) return poisoned_decl; } advance_and_verify(c, TOKEN_EQ); - ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl); + if (!parse_decl_initializer(c, decl, true)) return poisoned_decl; } return decl; } @@ -763,7 +779,7 @@ static Decl *parse_const_declaration(ParseContext *c, Visibility visibility) CONSUME_OR_RET(TOKEN_EQ, poisoned_decl); - ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl); + if (!parse_decl_initializer(c, decl, false)) return poisoned_decl; RANGE_EXTEND_PREV(decl); @@ -904,7 +920,7 @@ static inline Decl *parse_global_declaration(ParseContext *c, Visibility visibil if (!parse_attributes(c, &decl->attributes)) return poisoned_decl; if (try_consume(c, TOKEN_EQ)) { - ASSIGN_EXPR_OR_RET(decl->var.init_expr, parse_initializer(c), poisoned_decl); + if (!parse_decl_initializer(c, decl, true)) return poisoned_decl; } CONSUME_EOS_OR_RET(poisoned_decl); return decl; @@ -945,7 +961,7 @@ static inline bool parse_param_decl(ParseContext *c, Visibility parent_visibilit } if (name && try_consume(c, TOKEN_EQ)) { - ASSIGN_EXPR_OR_RET(param->var.init_expr, parse_initializer(c), false); + if (!parse_decl_initializer(c, param, false)) return poisoned_decl; } vec_add(*parameters, param); @@ -1090,7 +1106,7 @@ bool parse_parameters(ParseContext *c, Visibility visibility, Decl ***params_ref advance(c); if (try_consume(c, TOKEN_EQ)) { - ASSIGN_EXPR_OR_RET(param->var.init_expr, parse_initializer(c), false); + if (!parse_decl_initializer(c, param, false)) return poisoned_decl; } } if (!parse_attributes(c, ¶m->attributes)) return false; diff --git a/src/compiler/parse_stmt.c b/src/compiler/parse_stmt.c index c449c38e9..b8f11ff1a 100644 --- a/src/compiler/parse_stmt.c +++ b/src/compiler/parse_stmt.c @@ -71,21 +71,29 @@ static inline Ast* parse_asm_stmt(ParseContext *c) */ static inline Ast* parse_do_stmt(ParseContext *c) { - Ast *do_ast = new_ast(AST_DO_STMT, c->span); + Ast *do_ast = new_ast(AST_FOR_STMT, c->span); advance_and_verify(c, TOKEN_DO); - ASSIGN_DECL_OR_RET(do_ast->do_stmt.flow.label, parse_optional_label(c, do_ast), poisoned_ast); - ASSIGN_ASTID_OR_RET(do_ast->do_stmt.body, parse_stmt(c), poisoned_ast); + do_ast->flow.skip_first = true; + ASSIGN_DECL_OR_RET(do_ast->for_stmt.flow.label, parse_optional_label(c, do_ast), poisoned_ast); + ASSIGN_ASTID_OR_RET(do_ast->for_stmt.body, parse_stmt(c), poisoned_ast); - if (try_consume(c, TOKEN_WHILE)) + if (try_consume(c, TOKEN_EOS)) { + Expr *exit = expr_new(EXPR_CONST, c->prev_span); + expr_const_set_bool(&exit->const_expr, false); + exit->type = type_bool; + do_ast->for_stmt.cond = exprid(exit); + } + else + { + CONSUME_OR_RET(TOKEN_WHILE, poisoned_ast); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - ASSIGN_EXPR_OR_RET(do_ast->do_stmt.expr, parse_expr(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(do_ast->for_stmt.cond, parse_expr(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); CONSUME_OR_RET(TOKEN_EOS, poisoned_ast); } - return do_ast; } @@ -117,7 +125,7 @@ static inline Ast* parse_defer_stmt(ParseContext *c) { advance_and_verify(c, TOKEN_DEFER); Ast *defer_stmt = new_ast(AST_DEFER_STMT, c->span); - ASSIGN_AST_OR_RET(defer_stmt->defer_stmt.body, parse_stmt(c), poisoned_ast); + ASSIGN_ASTID_OR_RET(defer_stmt->defer_stmt.body, parse_stmt(c), poisoned_ast); return defer_stmt; } @@ -127,15 +135,22 @@ static inline Ast* parse_defer_stmt(ParseContext *c) */ static inline Ast* parse_while_stmt(ParseContext *c) { - Ast *while_ast = new_ast(AST_WHILE_STMT, c->span); + Ast *while_ast = new_ast(AST_FOR_STMT, c->span); advance_and_verify(c, TOKEN_WHILE); - ASSIGN_DECL_OR_RET(while_ast->while_stmt.flow.label, parse_optional_label(c, while_ast), poisoned_ast); + ASSIGN_DECL_OR_RET(while_ast->for_stmt.flow.label, parse_optional_label(c, while_ast), poisoned_ast); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - ASSIGN_EXPRID_OR_RET(while_ast->while_stmt.cond, parse_cond(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(while_ast->for_stmt.cond, parse_cond(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); - ASSIGN_ASTID_OR_RET(while_ast->while_stmt.body, parse_stmt(c), poisoned_ast); + unsigned row = c->prev_span.row; + ASSIGN_AST_OR_RET(Ast *body, parse_stmt(c), poisoned_ast); + if (body->ast_kind != AST_COMPOUND_STMT && row != c->prev_span.row) + { + SEMA_ERROR(body, "A single statement after 'while' must be placed on the same line, or be enclosed in {}."); + return poisoned_ast; + } + while_ast->for_stmt.body = astid(body); return while_ast; } @@ -164,7 +179,7 @@ static inline Ast* parse_if_stmt(ParseContext *c) advance_and_verify(c, TOKEN_IF); ASSIGN_DECL_OR_RET(if_ast->if_stmt.flow.label, parse_optional_label(c, if_ast), poisoned_ast); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - ASSIGN_EXPR_OR_RET(if_ast->if_stmt.cond, parse_cond(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(if_ast->if_stmt.cond, parse_cond(c), poisoned_ast); unsigned row = c->span.row; CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); // Special case, we might have if ( ) { case ... } @@ -174,23 +189,23 @@ static inline Ast* parse_if_stmt(ParseContext *c) Ast **cases = NULL; if (!parse_switch_body(c, &cases, TOKEN_CASE, TOKEN_DEFAULT, true)) return poisoned_ast; stmt->switch_stmt.cases = cases; - if_ast->if_stmt.then_body = stmt; + if_ast->if_stmt.then_body = astid(stmt); } else { unsigned next_row = c->span.row; - ASSIGN_AST_OR_RET(if_ast->if_stmt.then_body, parse_stmt(c), poisoned_ast); - if (row != next_row && if_ast->if_stmt.then_body->ast_kind != AST_COMPOUND_STMT) + ASSIGN_ASTID_OR_RET(if_ast->if_stmt.then_body, parse_stmt(c), poisoned_ast); + if (row != next_row && astptr(if_ast->if_stmt.then_body)->ast_kind != AST_COMPOUND_STMT) { // Poison it and pick it up later. - ast_poison(if_ast->if_stmt.then_body); + ast_poison(astptr(if_ast->if_stmt.then_body)); } } if (!try_consume(c, TOKEN_ELSE)) { return if_ast; } - ASSIGN_AST_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast); + ASSIGN_ASTID_OR_RET(if_ast->if_stmt.else_body, parse_stmt(c), poisoned_ast); return if_ast; } @@ -283,7 +298,7 @@ static inline Ast* parse_switch_stmt(ParseContext *c) advance_and_verify(c, TOKEN_SWITCH); ASSIGN_DECL_OR_RET(switch_ast->switch_stmt.flow.label, parse_optional_label(c, switch_ast), poisoned_ast); CONSUME_OR_RET(TOKEN_LPAREN, poisoned_ast); - ASSIGN_EXPR_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(switch_ast->switch_stmt.cond, parse_cond(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); if (!parse_switch_body(c, &switch_ast->switch_stmt.cases, TOKEN_CASE, TOKEN_DEFAULT, false)) return poisoned_ast; @@ -310,25 +325,25 @@ static inline Ast* parse_for_stmt(ParseContext *c) if (!tok_is(c, TOKEN_EOS)) { - ASSIGN_EXPR_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_expression_list(c, true), poisoned_ast); } else { - ast->for_stmt.init = NULL; + ast->for_stmt.init = 0; } CONSUME_OR_RET(TOKEN_EOS, poisoned_ast); if (!tok_is(c, TOKEN_EOS)) { - ASSIGN_EXPR_OR_RET(ast->for_stmt.cond, parse_cond(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.cond, parse_cond(c), poisoned_ast); } CONSUME_OR_RET(TOKEN_EOS, poisoned_ast); if (!tok_is(c, TOKEN_RPAREN)) { - ast->for_stmt.incr = parse_expression_list(c, false); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.incr, parse_expression_list(c, false), poisoned_ast); } CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); @@ -366,7 +381,7 @@ static inline bool parse_foreach_var(ParseContext *c, Ast *foreach) SEMA_ERROR_HERE("Expected an identifier or type."); return false; } - foreach->foreach_stmt.variable = var; + foreach->foreach_stmt.variable = declid(var); return true; } /** @@ -398,12 +413,12 @@ static inline Ast* parse_foreach_stmt(ParseContext *c) CONSUME_OR_RET(TOKEN_COLON, poisoned_ast); - ASSIGN_EXPR_OR_RET(ast->foreach_stmt.enumeration, parse_initializer(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->foreach_stmt.enumeration, parse_expr(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); RANGE_EXTEND_PREV(ast); - ASSIGN_AST_OR_RET(ast->foreach_stmt.body, parse_stmt(c), poisoned_ast); + ASSIGN_ASTID_OR_RET(ast->foreach_stmt.body, parse_stmt(c), poisoned_ast); return ast; } @@ -608,7 +623,6 @@ static inline Ast *parse_return(ParseContext *c) { advance_and_verify(c, TOKEN_RETURN); Ast *ast = ast_new_curr(c, AST_RETURN_STMT); - ast->return_stmt.defer = 0; if (!tok_is(c, TOKEN_EOS)) { ASSIGN_EXPR_OR_RET(ast->return_stmt.expr, parse_expr(c), poisoned_ast); @@ -645,7 +659,7 @@ static inline Ast* parse_ct_foreach_stmt(ParseContext *c) ast->ct_foreach_stmt.value_span = c->span; TRY_CONSUME_OR_RET(TOKEN_CT_IDENT, "Expected a compile time variable", poisoned_ast); TRY_CONSUME_OR_RET(TOKEN_COLON, "Expected ':'.", poisoned_ast); - ASSIGN_EXPR_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->ct_foreach_stmt.expr, parse_expr(c), poisoned_ast); CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); CONSUME_OR_RET(TOKEN_COLON, poisoned_ast); Ast *body = new_ast(AST_COMPOUND_STMT, ast->span); @@ -673,17 +687,17 @@ static inline Ast* parse_ct_for_stmt(ParseContext *c) if (!tok_is(c, TOKEN_EOS)) { - ASSIGN_EXPR_OR_RET(ast->for_stmt.init, parse_ct_expression_list(c, true), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.init, parse_ct_expression_list(c, true), poisoned_ast); } CONSUME_OR_RET(TOKEN_EOS, poisoned_ast); // Cond is required. - ASSIGN_EXPR_OR_RET(ast->for_stmt.cond, parse_expr(c), poisoned_ast); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.cond, parse_expr(c), poisoned_ast); CONSUME_OR_RET(TOKEN_EOS, poisoned_ast); if (!tok_is(c, TOKEN_RPAREN)) { - ast->for_stmt.incr = parse_ct_expression_list(c, false); + ASSIGN_EXPRID_OR_RET(ast->for_stmt.incr, parse_ct_expression_list(c, false), poisoned_ast); } CONSUME_OR_RET(TOKEN_RPAREN, poisoned_ast); diff --git a/src/compiler/parser_internal.h b/src/compiler/parser_internal.h index ac4569433..b95dd84de 100644 --- a/src/compiler/parser_internal.h +++ b/src/compiler/parser_internal.h @@ -26,7 +26,6 @@ TypeInfo *parse_type(ParseContext *c); TypeInfo *parse_failable_type(ParseContext *c); TypeInfo *parse_type_with_base(ParseContext *c, TypeInfo *type_info); Expr* parse_constant_expr(ParseContext *c); -Expr *parse_initializer(ParseContext *c); void parse_imports(ParseContext *c); Decl *parse_decl(ParseContext *c); Expr *parse_decl_or_expr(ParseContext *c, Decl **decl_ref); diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index 483e56109..f34c96a18 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -755,6 +755,7 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_SLICE_ASSIGN: case EXPR_SLICE: case EXPR_SUBSCRIPT: + case EXPR_RETVAL: if (type_size(expr->type) > type_size(type)) return expr; return NULL; case EXPR_OR_ERROR: @@ -802,7 +803,6 @@ Expr *recursive_may_narrow_float(Expr *expr, Type *type) case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_TYPEID: case EXPR_TYPEINFO: - case EXPR_UNDEF: case EXPR_CT_CALL: case EXPR_NOP: case EXPR_LEN: @@ -912,6 +912,7 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_SLICE_ASSIGN: case EXPR_SLICE: case EXPR_SUBSCRIPT: + case EXPR_RETVAL: if (type_size(expr->type) > type_size(type)) return expr; return NULL; case EXPR_LEN: @@ -959,7 +960,6 @@ Expr *recursive_may_narrow_int(Expr *expr, Type *type) case EXPR_DESIGNATED_INITIALIZER_LIST: case EXPR_TYPEID: case EXPR_TYPEINFO: - case EXPR_UNDEF: case EXPR_CT_CALL: case EXPR_NOP: case EXPR_BUILTIN: diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 39f6f23f0..b1a14edfe 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1432,7 +1432,7 @@ static inline bool sema_analyse_main_function(SemaContext *context, Decl *decl) AstId *next = &body->compound_stmt.first_stmt; Ast *ret_stmt = new_ast(AST_RETURN_STMT, decl->span); Expr *call = expr_new(EXPR_CALL, decl->span); - call->call_expr.function = expr_variable(decl); + call->call_expr.function = exprid(expr_variable(decl)); if (subarray_param) { Expr *subarray = expr_new(EXPR_ARGV_TO_SUBARRAY, decl->span); @@ -1962,12 +1962,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) SEMA_ERROR(decl, "Constants need to have an initial value."); return false; } - // 1b. We require defined constants - if (init_expr->expr_kind == EXPR_UNDEF) - { - SEMA_ERROR(decl, "Constants cannot be undefined."); - return false; - } + assert(!decl->var.no_init); if (!decl->var.type_info) { if (!sema_analyse_expr(context, init_expr)) return false; @@ -1992,20 +1987,15 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) decl->external_name = scratch_buffer_copy(); } + bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY; + if (!decl->var.init_expr && type_is_inferred) + { + SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred without an initializer."); + return false; + } if (decl->var.init_expr) { - bool type_is_inferred = decl->type->type_kind == TYPE_INFERRED_ARRAY; Expr *init = decl->var.init_expr; - // Handle explicit undef - if (init->expr_kind == EXPR_UNDEF) - { - if (type_is_inferred) - { - SEMA_ERROR(decl->var.type_info, "Size of the array cannot be inferred with explicit undef."); - return false; - } - goto EXIT_OK; - } if (!type_is_inferred) { @@ -2054,8 +2044,8 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) static CompilationUnit *unit_copy(Module *module, CompilationUnit *unit) { CompilationUnit *copy = unit_create(unit->file); - copy->imports = copy_decl_list(unit->imports); - copy->global_decls = copy_decl_list(unit->global_decls); + copy->imports = decl_copy_list(unit->imports); + copy->global_decls = decl_copy_list(unit->global_decls); copy->module = module; assert(!unit->functions && !unit->macro_methods && !unit->methods && !unit->enums && !unit->ct_ifs && !unit->types && !unit->external_symbol_list); return copy; diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index ed6949882..acda6c1c0 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -153,7 +153,7 @@ Expr *expr_generate_decl(Decl *decl, Expr *assign) assert(decl->var.init_expr == NULL); Expr *expr_decl = expr_new(EXPR_DECL, decl->span); expr_decl->decl_expr = decl; - if (!assign) assign = expr_new(EXPR_UNDEF, decl->span); + if (!assign) decl->var.no_init = true; decl->var.init_expr = assign; return expr_decl; } @@ -346,6 +346,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) RETRY: switch (expr->expr_kind) { + case EXPR_RETVAL: + return false; case EXPR_BUILTIN: case EXPR_CT_EVAL: return false; @@ -385,7 +387,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_SLICE_ASSIGN: case EXPR_MACRO_BLOCK: case EXPR_RETHROW: - case EXPR_UNDEF: return false; case EXPR_IDENTIFIER: if (expr->identifier_expr.decl->decl_kind != DECL_VAR) return true; @@ -703,7 +704,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) UNREACHABLE } if (type_is_abi_aggregate(decl->type)) return true; - expr_replace(expr, copy_expr(decl->var.init_expr)); + expr_replace(expr, expr_macro_copy(decl->var.init_expr)); return sema_analyse_expr(context, expr); case VARDECL_PARAM_EXPR: UNREACHABLE @@ -716,7 +717,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) // Impossible to reach this, they are already unfolded UNREACHABLE case VARDECL_PARAM_REF: - expr_replace(expr, copy_expr(decl->var.init_expr)); + expr_replace(expr, expr_macro_copy(decl->var.init_expr)); return sema_cast_rvalue(context, expr); case VARDECL_PARAM: case VARDECL_GLOBAL: @@ -803,7 +804,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) } if (expr_is_constant_eval(cond, true)) { - Expr *copy = copy_expr(cond); + Expr *copy = expr_macro_copy(cond); cast(copy, type_bool); assert(cond->expr_kind == EXPR_CONST); path = cond->const_expr.b ? 1 : 0; @@ -955,7 +956,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, case VARDECL_CONST: if (!decl->type) { - Expr *copy = copy_expr(decl->var.init_expr); + Expr *copy = expr_macro_copy(decl->var.init_expr); if (!sema_analyse_expr(context, copy)) return false; if (!expr_is_constant_eval(copy, false)) { @@ -1055,7 +1056,8 @@ static inline bool sema_expr_analyse_hash_identifier(SemaContext *context, Expr DEBUG_LOG("Resolution successful of %s.", decl->name); assert(decl->decl_kind == DECL_VAR); - expr_replace(expr, copy_expr(decl->var.init_expr)); + expr_replace(expr, expr_macro_copy(decl->var.init_expr)); + REMINDER("Remove analysis for hash"); if (!sema_analyse_expr(decl->var.hash_var.context, expr)) { // Poison the decl so we don't evaluate twice. @@ -1376,7 +1378,7 @@ static inline bool sema_expand_call_arguments(SemaContext *context, CalledDecl * { if (callee->macro) { - actual_args[i] = copy_expr(init_expr); + actual_args[i] = expr_macro_copy(init_expr); } else { @@ -1744,6 +1746,7 @@ static bool sema_check_stmt_compile_time(SemaContext *context, Ast *ast) case AST_NOP_STMT: return true; case AST_RETURN_STMT: + case AST_BLOCK_EXIT_STMT: if (!ast->return_stmt.expr) return true; return expr_is_constant_eval(ast->return_stmt.expr, CONSTANT_EVAL_ANY); case AST_EXPR_STMT: @@ -1766,7 +1769,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s { assert(decl->decl_kind == DECL_MACRO); - Decl **params = copy_decl_list(decl->macro_decl.parameters); + Decl **params = decl_copy_list(decl->macro_decl.parameters); CalledDecl callee = { .macro = true, .block_parameter = decl->macro_decl.block_parameter, @@ -1822,7 +1825,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s if (!body_arg->alignment) body_arg->alignment = type_alloca_alignment(body_arg->type); } - Ast *body = ast_copy_deep(decl->macro_decl.body); + Ast *body = ast_macro_copy(decl->macro_decl.body); bool no_scope = decl->no_scope; bool escaping = decl->escaping; @@ -1850,9 +1853,11 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s rtype = decl->macro_decl.rtype ? decl->macro_decl.rtype->type : NULL; macro_context.expected_block_type = rtype; context_change_scope_with_flags(¯o_context, SCOPE_MACRO); + macro_context.block_return_defer = macro_context.active_scope.defer_last; } macro_context.current_macro = decl; - macro_context.yield_body = call_expr->call_expr.body; + AstId body_id = call_expr->call_expr.body; + macro_context.yield_body = body_id ? astptr(body_id) : NULL; macro_context.yield_params = body_params; macro_context.yield_context = context; macro_context.original_inline_line = context->original_inline_line ? context->original_inline_line : call_expr->span.row; @@ -2092,8 +2097,9 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call) SemaContext *context = macro_context->yield_context; Decl **params = macro_context->yield_params; - assert(call_expr->function->expr_kind == EXPR_MACRO_BODY_EXPANSION); - expr_replace(call, call_expr->function); + 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; @@ -2104,7 +2110,7 @@ static bool sema_analyse_body_expansion(SemaContext *macro_context, Expr *call) Decl *param = params[i]; if (!sema_add_local(context, param)) return SCOPE_POP_ERROR(); } - call->body_expansion_expr.ast = ast_copy_deep(macro_context->yield_body); + call->body_expansion_expr.ast = ast_macro_copy(macro_context->yield_body); success = sema_analyse_statement(context, call->body_expansion_expr.ast); SCOPE_END; @@ -2154,7 +2160,7 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl if (!sema_analyse_call_attributes(context, decl, expr)) return expr_poison(expr); if (decl == NULL) { - return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(expr->call_expr.function->type), failable); + return sema_expr_analyse_var_call(context, expr, type_flatten_distinct_failable(exprptr(expr->call_expr.function)->type), failable); } switch (decl->decl_kind) { @@ -2164,7 +2170,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl SEMA_ERROR(expr, "A macro neeeds to be called with a '@' prefix, please add it."); return false; } - expr->call_expr.func_ref = decl; + expr->call_expr.func_ref = declid(decl); + expr->call_expr.is_func_ref = true; return sema_expr_analyse_macro_call(context, expr, struct_var, decl, failable); case DECL_VAR: if (is_macro) @@ -2180,7 +2187,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl SEMA_ERROR(expr, "A function cannot be called with a '@' prefix, please remove it."); return false; } - expr->call_expr.func_ref = decl; + expr->call_expr.func_ref = declid(decl); + expr->call_expr.is_func_ref = true; return sema_expr_analyse_func_call(context, expr, decl, struct_var, failable); case DECL_GENERIC: if (is_macro) @@ -2188,7 +2196,8 @@ bool sema_expr_analyse_general_call(SemaContext *context, Expr *expr, Decl *decl SEMA_ERROR(expr, "A generic function cannot be called with a '@' prefix, please remove it."); return false; } - expr->call_expr.func_ref = decl; + expr->call_expr.func_ref = declid(decl); + expr->call_expr.is_func_ref = true; return sema_expr_analyse_generic_call(context, expr, struct_var, decl, failable); case DECL_POISONED: return false; @@ -2231,7 +2240,7 @@ static inline unsigned builtin_expected_args(BuiltinFunction func) static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *expr) { expr->call_expr.is_builtin = true; - BuiltinFunction func = expr->call_expr.function->builtin_expr.builtin; + BuiltinFunction func = exprptr(expr->call_expr.function)->builtin_expr.builtin; unsigned expected_args = builtin_expected_args(func); Expr **args = expr->call_expr.arguments; unsigned arg_count = vec_size(args); @@ -2363,7 +2372,7 @@ static inline bool sema_expr_analyse_builtin_call(SemaContext *context, Expr *ex static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr) { - Expr *func_expr = expr->call_expr.function; + Expr *func_expr = exprptr(expr->call_expr.function); if (!sema_analyse_expr_lvalue(context, func_expr)) return false; if (func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION) @@ -2697,7 +2706,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, expr->expr_kind = EXPR_CALL; Expr **args = NULL; vec_add(args, index); - expr->call_expr = (ExprCall){ .func_ref = decl, .arguments = args }; + expr->call_expr = (ExprCall){ .func_ref = declid(decl), .is_func_ref = true, .arguments = args }; expr->call_expr.is_type_method = true; return sema_expr_analyse_macro_call(context, expr, current_expr, decl, failable); } @@ -6079,7 +6088,9 @@ static inline bool sema_expr_analyse_rethrow(SemaContext *context, Expr *expr) { Expr *inner = expr->rethrow_expr.inner; if (!sema_analyse_expr(context, inner)) return false; - expr->rethrow_expr.defer = context->active_scope.defer_last; + + REMINDER("Return defers must be work with blocks"); + expr->rethrow_expr.cleanup = context_get_defers(context, context->active_scope.defer_last, 0); if (inner->type == type_anyfail) { SEMA_ERROR(expr, "This expression will always throw, which isn't allowed."); @@ -6147,14 +6158,17 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe context->expected_block_type = infer_type; SCOPE_START_WITH_FLAGS(SCOPE_EXPR_BLOCK) + context->block_return_defer = context->active_scope.defer_last; PUSH_CONTINUE(NULL); PUSH_BREAK(NULL); PUSH_NEXT(NULL, NULL); AstId current = expr->expr_block.first_stmt; + Ast *stmt = NULL; while (current) { - if (!sema_analyse_statement(context, ast_next(¤t))) + stmt = ast_next(¤t); + if (!sema_analyse_statement(context, stmt)) { success = false; goto EXIT; @@ -6180,6 +6194,7 @@ static inline bool sema_expr_analyse_expr_block(SemaContext *context, Type *infe POP_BREAKCONT(); POP_NEXT(); + context_pop_defers(context, &stmt->next); SCOPE_END; context->expected_block_type = stored_block_type; context_pop_returns(context, saved_returns); @@ -6852,6 +6867,21 @@ static inline BuiltinFunction builtin_by_name(const char *name) return BUILTIN_NONE; } +static inline bool sema_expr_analyse_retval(SemaContext *c, Expr *expr) +{ + if (c->active_scope.flags & SCOPE_MACRO) + { + TODO + } + if (expr->type == type_void) + { + SEMA_ERROR(expr, "'return' cannot be used on void functions."); + return false; + } + expr->type = c->rtype; + return true; +} + static inline bool sema_expr_analyse_builtin(SemaContext *context, Expr *expr, bool throw_error) { const char *builtin_char = expr->builtin_expr.ident; @@ -6873,7 +6903,6 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) switch (expr->expr_kind) { case EXPR_COND: - case EXPR_UNDEF: case EXPR_DESIGNATOR: case EXPR_MACRO_BODY_EXPANSION: case EXPR_FLATPATH: @@ -6894,6 +6923,8 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr) if (!sema_analyse_var_decl(context, expr->decl_expr, true)) return false; expr->type = expr->decl_expr->type; return true; + case EXPR_RETVAL: + return sema_expr_analyse_retval(context, expr); case EXPR_BUILTIN: return sema_expr_analyse_builtin(context, expr, true); case EXPR_CT_CALL: @@ -7018,7 +7049,7 @@ bool sema_analyse_expr_rhs(SemaContext *context, Type *to, Expr *expr, bool allo static inline bool sema_cast_ct_ident_rvalue(SemaContext *context, Expr *expr) { Decl *decl = expr->ct_ident_expr.decl; - Expr *copy = copy_expr(decl->var.init_expr); + Expr *copy = expr_macro_copy(decl->var.init_expr); if (!sema_analyse_expr(context, copy)) return false; expr_replace(expr, copy); return true; diff --git a/src/compiler/sema_internal.h b/src/compiler/sema_internal.h index f5c6997f7..66b53452b 100644 --- a/src/compiler/sema_internal.h +++ b/src/compiler/sema_internal.h @@ -34,12 +34,14 @@ do { \ #define SCOPE_ERROR_END_OUTER() \ do { context->active_scope = stored_scope; } while(0) -void context_pop_defers_to(SemaContext *context, DeferList *list); +AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom); +void context_pop_defers(SemaContext *context, AstId *next); Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr); void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr); void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast); void context_change_scope_for_label(SemaContext *context, Decl *label); void context_change_scope_with_flags(SemaContext *context, ScopeFlags flags); +bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body); #define PUSH_X(ast, X) AstId _old_##X##_defer = context->X##_defer; AstId _old_##X = context->X##_target; context->X##_target = ast ? astid(ast) : 0; context->X##_defer = context->active_scope.defer_last #define POP_X(X) context->X##_target = _old_##X; context->X##_defer = _old_##X##_defer diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 5a5436117..4bd30be54 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -82,9 +82,10 @@ static inline bool assert_create_from_contract(SemaContext *context, AstDocDirec return true; } -static inline bool sema_analyse_block_return_stmt(SemaContext *context, Ast *statement) +static inline bool sema_analyse_block_exit_stmt(SemaContext *context, Ast *statement) { assert(context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO)); + statement->ast_kind = AST_BLOCK_EXIT_STMT; context->active_scope.jump_end = true; Type *block_type = context->expected_block_type; if (statement->return_stmt.expr) @@ -106,6 +107,7 @@ static inline bool sema_analyse_block_return_stmt(SemaContext *context, Ast *sta return false; } } + statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, context->block_return_defer); vec_add(context->returns, statement); return true; } @@ -127,7 +129,7 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement // This might be a return in a function block or a macro which must be treated differently. if (context->active_scope.flags & (SCOPE_EXPR_BLOCK | SCOPE_MACRO)) { - return sema_analyse_block_return_stmt(context, statement); + return sema_analyse_block_exit_stmt(context, statement); } // 1. We mark that the current scope ends with a jump. context->active_scope.jump_end = true; @@ -136,7 +138,6 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement assert(expected_rtype && "We should always have known type from a function return."); Expr *return_expr = statement->return_stmt.expr; - statement->return_stmt.defer = context->active_scope.defer_last; if (return_expr) { @@ -149,27 +150,17 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement SEMA_ERROR(statement, "Expected to return a result of type %s.", type_to_error_string(expected_rtype)); return false; } + statement->return_stmt.cleanup = context_get_defers(context, context->active_scope.defer_last, 0); return true; } // Process any ensures. - if (context->return_var) + AstId cleanup = context_get_defers(context, context->active_scope.defer_last, 0); + if (context->ensures) { - AstId next_id = 0; - AstId *append_id = &next_id; + AstId first = 0; + AstId *append_id = &first; // Creating an assign statement - if (return_expr) - { - Expr *assign = expr_new(EXPR_BINARY, return_expr->span); - assign->binary_expr.operator = BINARYOP_ASSIGN; - assign->binary_expr.widen = true; - assign->binary_expr.left = expr_variable(context->return_var); - assign->binary_expr.right = return_expr; - Ast *new_ret = new_ast(AST_EXPR_STMT, assign->span); - new_ret->expr_stmt = assign; - if (!sema_analyse_statement(context, new_ret)) return false; - ast_append(&append_id, new_ret); - } AstDocDirective *directives = context->current_function->docs; VECEACH(directives, i) { @@ -177,21 +168,19 @@ static inline bool sema_analyse_return_stmt(SemaContext *context, Ast *statement if (directive->kind != DOC_DIRECTIVE_ENSURE) continue; if (!assert_create_from_contract(context, directive, &append_id)) return false; } - if (next_id) + + if (cleanup) { - Ast *new_return = new_ast(AST_RETURN_STMT, statement->span); - ast_append(&append_id, new_return); - if (return_expr) - { - new_return->return_stmt.expr = expr_variable(context->return_var); - } - new_return->return_stmt.defer = statement->return_stmt.defer; - new_return->next = statement->next; - statement->next = next_id; - statement->ast_kind = AST_NOP_STMT; + Ast *last = ast_last(astptr(cleanup)); + last->next = first; + } + else + { + cleanup = first; } } + statement->return_stmt.cleanup = cleanup; assert(type_no_fail(statement->return_stmt.expr->type)->canonical == type_no_fail(expected_rtype)->canonical); @@ -454,7 +443,7 @@ static inline bool sema_analyse_catch_unwrap(SemaContext *context, Expr *expr) // 4d. A new declaration is created. Decl *decl = decl_new_var(ident->identifier_expr.ident, ident->span, type, VARDECL_LOCAL, VISIBLE_LOCAL); - decl->var.init_expr = expr_new(EXPR_UNDEF, decl->span); + decl->var.no_init = true; // 4e. Analyse it if (!sema_analyse_var_decl(context, decl, true)) return false; @@ -696,134 +685,7 @@ static inline bool sema_analyse_stmt_placement(Expr *cond, Ast *stmt) return cond->span.row == stmt->span.row; } -/** - * Check "while" statement, including end of line placement of a single statement. - */ -static inline bool sema_analyse_while_stmt(SemaContext *context, Ast *statement) -{ - Expr *cond = exprptr(statement->while_stmt.cond); - Ast *body = astptr(statement->while_stmt.body); - bool success; - - // 1. Begin our scope, this is relevant in case we have something like - // while (File *f = @getFileAndClose!()) where the macro pushes a defer into the scope. - SCOPE_START_WITH_LABEL(statement->while_stmt.flow.label) - - // 2. Analyze the condition - if (!sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL)) - { - // 2a. In case of error, pop context and exit. - return SCOPE_POP_ERROR(); - } - - // 4. Push break / continue - which is independent of the scope. - PUSH_BREAKCONT(statement); - - // 6. Analyse the statement - success = sema_analyse_statement(context, body); - - // 7. Pop break / continue - POP_BREAKCONT(); - - // 8. Check placement, in case of a single statement, it must be placed on the same line. - if (success && !sema_analyse_stmt_placement(cond, body)) - { - SEMA_ERROR(body, "A single statement after 'while' must be placed on the same line, or be enclosed in {}."); - return SCOPE_POP_ERROR(); - } - - // 9. Pop defers attach them to the statement if needed - context_pop_defers_and_replace_ast(context, body); - - // 10. Pop the while scope. - SCOPE_END; - statement->ast_kind = AST_FOR_STMT; - AstForStmt for_stmt = { - .cond = cond, - .flow = statement->while_stmt.flow, - .incr = NULL, - .body = astid(body), - }; - statement->for_stmt = for_stmt; - return success; -} - -/** - * Check the do ... while (...) statement. - */ -static inline bool sema_analyse_do_stmt(SemaContext *context, Ast *statement) -{ - Expr *expr = statement->do_stmt.expr; - Ast *body = astptr(statement->do_stmt.body); - bool success; - - // 1. Begin pushing the scope and break / continue. - SCOPE_START_WITH_LABEL(statement->do_stmt.flow.label) - - PUSH_BREAKCONT(statement); - - // 2. We analyze the statement. - success = sema_analyse_statement(context, body); - - // 3. Pop break / continue - POP_BREAKCONT(); - - // 4. Pop any defers - context_pop_defers_and_replace_ast(context, body); - - // 5. If the current scope ended in a jump, then - // the do statement has no exit. - statement->do_stmt.flow.no_exit = context->active_scope.jump_end; - - // 6. Pop the scope - SCOPE_END; - - // 7. We can now exit if there was an error further up. - if (!success) return false; - - // 8. Handle the do { } expression - if (!statement->do_stmt.expr) - { - goto END; - } - - // 9. We next handle the while test. This is its own scope. - SCOPE_START - - // 10. Try to evaluate and implicitly cast to boolean. - if (!sema_analyse_cond_expr(context, expr)) - { - // 10a. On failure, pop and return false. - return SCOPE_POP_ERROR(); - } - - // 11. Pop any defers in the expression. - statement->do_stmt.expr = context_pop_defers_and_wrap_expr(context, expr); - - SCOPE_END; - - // 13. Check for infinite loops using do ... while (1). - // If it has no break then that means we've reached a statement which ends with a jump. - if (statement->do_stmt.expr->expr_kind == EXPR_CONST && statement->do_stmt.expr->const_expr.b) - { - // Unless there is a break, this won't ever exit. - context->active_scope.jump_end = !statement->do_stmt.flow.has_break; - } - -END:; - FlowCommon flow = statement->do_stmt.flow; - flow.skip_first = true; - statement->ast_kind = AST_FOR_STMT; - AstForStmt for_stmt = { - .cond = expr, - .flow = flow, - .incr = NULL, - .body = astid(body), - }; - statement->for_stmt = for_stmt; - return true; -} @@ -846,108 +708,141 @@ static inline bool sema_analyse_expr_stmt(SemaContext *context, Ast *statement) return true; } -static inline bool sema_analyse_defer_stmt(SemaContext *context, Ast *statement) +bool sema_analyse_defer_stmt_body(SemaContext *context, Ast *statement, Ast *body) { // TODO special parsing of "catch" bool success; SCOPE_START_WITH_FLAGS(SCOPE_DEFER) - context->active_scope.defer_last = 0; - context->active_scope.defer_start = 0; - context->active_scope.in_defer = statement; + context->active_scope.defer_last = 0; + context->active_scope.defer_start = 0; + context->active_scope.in_defer = statement; - PUSH_CONTINUE(NULL); - PUSH_BREAK(statement); - PUSH_NEXT(NULL, NULL); + PUSH_BREAKCONT(NULL); + PUSH_NEXT(NULL, NULL); - // Only ones allowed. - context->active_scope.flags &= SCOPE_DEFER; + // Only ones allowed. + context->active_scope.flags &= SCOPE_DEFER; - success = sema_analyse_statement(context, statement->defer_stmt.body); + success = sema_analyse_statement(context, body); - POP_BREAKCONT(); - POP_NEXT(); + POP_BREAKCONT(); + POP_NEXT(); - context_pop_defers_and_replace_ast(context, statement->defer_stmt.body); + context_pop_defers_and_replace_ast(context, body); SCOPE_END; - if (!success) return false; + return success; + +} +static inline bool sema_analyse_defer_stmt(SemaContext *context, Ast *statement) +{ + // TODO special parsing of "catch" + if (!sema_analyse_defer_stmt_body(context, statement, astptr(statement->defer_stmt.body))) return false; statement->defer_stmt.prev_defer = context->active_scope.defer_last; context->active_scope.defer_last = astid(statement); + return true; } +static inline bool sema_analyse_for_cond(SemaContext *context, ExprId *cond_ref, bool *infinite) +{ + ExprId cond_id = *cond_ref; + if (!cond_id) + { + *infinite = true; + return true; + } + Expr *cond = exprptr(cond_id); + if (cond->expr_kind == EXPR_COND) + { + if (!sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL)) return false; + } + else + { + if (!sema_analyse_cond_expr(context, cond)) return false; + } + cond = context_pop_defers_and_wrap_expr(context, cond); + + // If this is const true, then set this to infinite and remove the expression. + if (cond->expr_kind == EXPR_CONST && cond->const_expr.b) + { + cond = NULL; + *infinite = true; + } + else + { + *infinite = false; + } + *cond_ref = exprid(cond); + return true; +} static inline bool sema_analyse_for_stmt(SemaContext *context, Ast *statement) { bool success = true; - bool is_infinite; + bool is_infinite = false; // Enter for scope SCOPE_OUTER_START - is_infinite = statement->for_stmt.cond == NULL; if (statement->for_stmt.init) { - success = sema_analyse_expr(context, statement->for_stmt.init); + success = sema_analyse_expr(context, exprptr(statement->for_stmt.init)); } - if (success && statement->for_stmt.cond) - { - // Conditional scope start - SCOPE_START - Expr *cond = statement->for_stmt.cond; - if (cond->expr_kind == EXPR_COND) - { - success = sema_analyse_cond(context, cond, COND_TYPE_UNWRAP_BOOL); - } - else - { - success = sema_analyse_cond_expr(context, cond); - } - statement->for_stmt.cond = context_pop_defers_and_wrap_expr(context, cond); - // If this is const true, then set this to infinite and remove the expression. - if (statement->for_stmt.cond->expr_kind == EXPR_CONST && statement->for_stmt.cond->const_expr.b) - { - statement->for_stmt.cond = NULL; - is_infinite = true; - } - // Conditional scope end - SCOPE_END; - } - if (success && statement->for_stmt.incr) - { - // Incr scope start - SCOPE_START - Expr *incr = statement->for_stmt.incr; - success = sema_analyse_expr(context, incr); - statement->for_stmt.incr = context_pop_defers_and_wrap_expr(context, incr); - // Incr scope end - SCOPE_END; - } - if (!success) - { - SCOPE_ERROR_END_OUTER(); - return false; - } - - assert(statement->for_stmt.body); - Ast *body = astptr(statement->for_stmt.body); - // Create the for body scope. + // Conditional scope start SCOPE_START_WITH_LABEL(statement->for_stmt.flow.label) + if (!statement->for_stmt.flow.skip_first) + { + if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success) + { + SCOPE_ERROR_END_OUTER(); + return false; + } + } + + assert(statement->for_stmt.body); + Ast *body = astptr(statement->for_stmt.body); + PUSH_BREAKCONT(statement); success = sema_analyse_statement(context, body); statement->for_stmt.flow.no_exit = context->active_scope.jump_end; POP_BREAKCONT(); + // End for body scope context_pop_defers_and_replace_ast(context, body); + SCOPE_END; + if (statement->for_stmt.flow.skip_first) + { + SCOPE_START + if (!sema_analyse_for_cond(context, &statement->for_stmt.cond, &is_infinite) || !success) + { + SCOPE_ERROR_END_OUTER(); + return false; + } + SCOPE_END; + } + + if (success && statement->for_stmt.incr) + { + // Incr scope start + SCOPE_START + Expr *incr = exprptr(statement->for_stmt.incr); + success = sema_analyse_expr(context, incr); + statement->for_stmt.incr = exprid(context_pop_defers_and_wrap_expr(context, incr)); + // Incr scope end + SCOPE_END; + } + + + // End for body scope context_pop_defers_and_replace_ast(context, statement); - // End for scope SCOPE_OUTER_END; @@ -964,9 +859,10 @@ static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span { Expr *len_call = expr_new(EXPR_CALL, span); len_call->resolve_status = RESOLVE_RUNNING; - len_call->call_expr.func_ref = method_decl; + len_call->call_expr.func_ref = declid(method_decl); len_call->call_expr.arguments = arguments; - len_call->call_expr.body = NULL; + len_call->call_expr.body = 0; + len_call->call_expr.is_func_ref = true; len_call->call_expr.unsplat_last = false; len_call->call_expr.is_type_method = true; bool is_macro = method_decl->decl_kind == DECL_MACRO; @@ -982,10 +878,12 @@ static Expr *sema_insert_method_macro_call(SemaContext *context, SourceSpan span static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statement) { // Pull out the relevant data. - Decl *index = statement->foreach_stmt.index; - Decl *var = statement->foreach_stmt.variable; - Expr *enumerator = statement->foreach_stmt.enumeration; - Ast *body = statement->foreach_stmt.body; + DeclId index_id = statement->foreach_stmt.index; + DeclId var_id = statement->foreach_stmt.variable; + Decl *var = var_id ? declptr(var_id) : NULL; + Decl *index = index_id ? declptr(index_id) : NULL; + Expr *enumerator = exprptr(statement->foreach_stmt.enumeration); + AstId body = statement->foreach_stmt.body; AstId first_stmt = 0; AstId *succ = &first_stmt; Expr **expressions = NULL; @@ -1275,13 +1173,14 @@ static inline bool sema_analyse_foreach_stmt(SemaContext *context, Ast *statemen } var->var.init_expr = subscript; ast_append(&succ, value_declare_ast); - ast_append(&succ, body); - Ast *compound_stmt = new_ast(AST_COMPOUND_STMT, body->span); + Ast *body_ast = astptr(body); + ast_append(&succ, body_ast); + Ast *compound_stmt = new_ast(AST_COMPOUND_STMT, body_ast->span); compound_stmt->compound_stmt.first_stmt = first_stmt; FlowCommon flow = statement->foreach_stmt.flow; - statement->for_stmt = (AstForStmt){ .init = init_expr, - .cond = binary, - .incr = inc, + statement->for_stmt = (AstForStmt){ .init = exprid(init_expr), + .cond = exprid(binary), + .incr = exprid(inc), .flow = flow, .body = astid(compound_stmt) }; @@ -1305,21 +1204,23 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) bool then_jump; bool success; - Expr *cond = statement->if_stmt.cond; + Expr *cond = exprptr(statement->if_stmt.cond); + Ast *then = astptr(statement->if_stmt.then_body); + AstId else_id = statement->if_stmt.else_body; + Ast *else_body = else_id ? astptr(else_id) : NULL; SCOPE_OUTER_START - CondType cond_type = statement->if_stmt.then_body->ast_kind == AST_IF_CATCH_SWITCH_STMT + CondType cond_type = then->ast_kind == AST_IF_CATCH_SWITCH_STMT ? COND_TYPE_UNWRAP : COND_TYPE_UNWRAP_BOOL; success = sema_analyse_cond(context, cond, cond_type); - Ast *then = statement->if_stmt.then_body; if (success && !ast_ok(then)) { - SEMA_ERROR(statement->if_stmt.then_body, + SEMA_ERROR(then, "The 'then' part of a single line if-statement must start on the same line as the 'if' or use '{ }'"); success = false; } - if (success && statement->if_stmt.else_body) + if (success && else_body) { bool then_has_braces = then->ast_kind == AST_COMPOUND_STMT || then->ast_kind == AST_IF_CATCH_SWITCH_STMT; if (!then_has_braces) @@ -1327,10 +1228,10 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) SEMA_ERROR(then, "if-statements with an 'else' must use '{ }' even around a single statement."); success = false; } - if (success && statement->if_stmt.else_body->ast_kind != AST_COMPOUND_STMT && - statement->if_stmt.else_body->ast_kind != AST_IF_STMT) + if (success && else_body->ast_kind != AST_COMPOUND_STMT && + else_body->ast_kind != AST_IF_STMT) { - SEMA_ERROR(statement->if_stmt.else_body, + SEMA_ERROR(else_body, "An 'else' must use '{ }' even around a single statement."); success = false; } @@ -1364,9 +1265,9 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) if (statement->if_stmt.else_body) { SCOPE_START_WITH_LABEL(statement->if_stmt.flow.label); - sema_remove_unwraps_from_try(context, statement->if_stmt.cond); - sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond); - success = success && sema_analyse_statement(context, statement->if_stmt.else_body); + sema_remove_unwraps_from_try(context, cond); + sema_unwrappable_from_catch_in_else(context, cond); + success = success && sema_analyse_statement(context, else_body); else_jump = context->active_scope.jump_end; SCOPE_END; } @@ -1376,7 +1277,7 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) SCOPE_OUTER_END; if (then_jump) { - sema_unwrappable_from_catch_in_else(context, statement->if_stmt.cond); + sema_unwrappable_from_catch_in_else(context, cond); } if (then_jump && else_jump && !statement->flow.has_break) { @@ -1385,10 +1286,6 @@ static inline bool sema_analyse_if_stmt(SemaContext *context, Ast *statement) return success; } - - - - static bool sema_analyse_asm_stmt(SemaContext *context, Ast *stmt) { if (!sema_analyse_expr(context, stmt->asm_stmt.body)) return false; @@ -1451,7 +1348,8 @@ static bool sema_analyse_break_stmt(SemaContext *context, Ast *statement) return false; } - statement->contbreak_stmt.defers.start = context->active_scope.defer_last; + AstId defer_begin; + statement->contbreak_stmt.is_resolved = true; if (statement->contbreak_stmt.label.name) { Decl *target = sema_analyse_label(context, statement); @@ -1459,12 +1357,15 @@ static bool sema_analyse_break_stmt(SemaContext *context, Ast *statement) astptr(target->label.parent)->flow.has_break = true; statement->contbreak_stmt.ast = target->label.parent; - statement->contbreak_stmt.defers.end = target->label.defer; - return true; + defer_begin = target->label.defer; } - statement->contbreak_stmt.defers.end = context->break_defer; - statement->contbreak_stmt.ast = context->break_target; - astptr(context->break_target)->flow.has_break = true; + else + { + defer_begin = context->break_defer; + statement->contbreak_stmt.ast = context->break_target; + astptr(context->break_target)->flow.has_break = true; + } + statement->contbreak_stmt.defers = context_get_defers(context, context->active_scope.defer_last, defer_begin); return true; } @@ -1516,28 +1417,27 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) assert(statement->nextcase_stmt.expr); } - statement->nextcase_stmt.defers.start = context->active_scope.defer_last; - statement->nextcase_stmt.defers.end = parent->switch_stmt.defer; // Plain next. if (!statement->nextcase_stmt.expr) { assert(context->next_target); + statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer); statement->nextcase_stmt.case_switch_stmt = context->next_target; return true; } - Expr *cond = parent->switch_stmt.cond; + Expr *cond = exprptr(parent->switch_stmt.cond); if (statement->nextcase_stmt.expr->expr_kind == EXPR_TYPEINFO) { TypeInfo *type_info = statement->nextcase_stmt.expr->type_expr; if (!sema_resolve_type_info(context, type_info)) return false; Ast **cases; - statement->nextcase_stmt.defers.end = parent->switch_stmt.defer; - if (parent->switch_stmt.cond->type->canonical != type_typeid) + statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer); + if (cond->type->canonical != type_typeid) { SEMA_ERROR(statement, "Unexpected 'type' in as an 'nextcase' destination."); - SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(parent->switch_stmt.cond->type)); + SEMA_PREV(statement, "The 'switch' here uses expected a type '%s'.", type_to_error_string(cond->type)); return false; } cases = parent->switch_stmt.cases; @@ -1574,10 +1474,11 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) if (!sema_analyse_expr_rhs(context, expected_type, target, false)) return false; + statement->nextcase_stmt.defer_id = context_get_defers(context, context->active_scope.defer_last, parent->switch_stmt.defer); + if (target->expr_kind == EXPR_CONST) { Ast *default_stmt = NULL; - statement->nextcase_stmt.defers.end = parent->switch_stmt.defer; VECEACH(parent->switch_stmt.cases, i) { Ast *case_stmt = parent->switch_stmt.cases[i]; @@ -1612,7 +1513,6 @@ static bool sema_analyse_nextcase_stmt(SemaContext *context, Ast *statement) static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement) { context->active_scope.jump_end = true; - statement->contbreak_stmt.defers.start = context->active_scope.defer_last; if (!context->continue_target && !statement->contbreak_stmt.label.name) { @@ -1620,6 +1520,7 @@ static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement) return false; } + AstId defer_bottom; if (statement->contbreak_stmt.label.name) { Decl *target = sema_analyse_label(context, statement); @@ -1628,21 +1529,22 @@ static bool sema_analyse_continue_stmt(SemaContext *context, Ast *statement) switch (parent->ast_kind) { case AST_FOR_STMT: - case AST_WHILE_STMT: - break; - case AST_DO_STMT: - if (parent->do_stmt.expr) break; + // Is this plain "do"? + if (parent->for_stmt.cond || parent->flow.skip_first) break; FALLTHROUGH; default: SEMA_ERROR(statement, "'continue' may only be used with 'for', 'while' and 'do-while' statements."); return false; } statement->contbreak_stmt.ast = target->label.parent; - statement->contbreak_stmt.defers.end = target->label.defer; - return true; + defer_bottom = target->label.defer; } - statement->contbreak_stmt.defers.end = context->continue_defer; - statement->contbreak_stmt.ast = context->continue_target; + else + { + defer_bottom = context->continue_defer; + statement->contbreak_stmt.ast = context->continue_target; + } + statement->contbreak_stmt.defers = context_get_defers(context, context->active_scope.defer_last, defer_bottom); return true; } @@ -1714,16 +1616,18 @@ static inline bool sema_analyse_compound_statement_no_scope(SemaContext *context { bool all_ok = ast_ok(compound_statement); AstId current = compound_statement->compound_stmt.first_stmt; + Ast *ast = NULL; while (current) { - Ast *ast = ast_next(¤t); + ast = ast_next(¤t); if (!sema_analyse_statement(context, ast)) { ast_poison(ast); all_ok = false; } } - context_pop_defers_to(context, &compound_statement->compound_stmt.defer_list); + AstId *next = ast ? &ast->next : &compound_statement->compound_stmt.first_stmt; + context_pop_defers(context, next); return all_ok; } @@ -1929,7 +1833,7 @@ static bool sema_analyse_switch_body(SemaContext *context, Ast *statement, Sourc SCOPE_END; } statement->flow.no_exit = all_jump_end; - statement->switch_stmt.if_chain = if_chain || max_ranged; + statement->switch_stmt.flow.if_chain = if_chain || max_ranged; if (!success) return false; return success; } @@ -2051,7 +1955,7 @@ static bool sema_analyse_ct_switch_stmt(SemaContext *context, Ast *statement) static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement) { - Expr *collection = statement->ct_foreach_stmt.expr; + Expr *collection = exprptr(statement->ct_foreach_stmt.expr); if (!sema_analyse_ct_expr(context, collection)) return false; if (collection->expr_kind != EXPR_INITIALIZER_LIST) { @@ -2083,7 +1987,7 @@ static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement) AstId *current = &start; VECEACH(expression, i) { - Ast *compound_stmt = ast_copy_deep(body); + Ast *compound_stmt = ast_macro_copy(body); value->var.init_expr = expression[i]; if (index) { @@ -2101,7 +2005,6 @@ static bool sema_analyse_ct_foreach_stmt(SemaContext *context, Ast *statement) SCOPE_END; statement->ast_kind = AST_COMPOUND_STMT; statement->compound_stmt.first_stmt = start; - statement->compound_stmt.defer_list = (DeferList) { 0, 0 }; return true; } @@ -2111,7 +2014,7 @@ static bool sema_analyse_switch_stmt(SemaContext *context, Ast *statement) SCOPE_START_WITH_LABEL(statement->switch_stmt.flow.label); - Expr *cond = statement->switch_stmt.cond; + Expr *cond = exprptr(statement->switch_stmt.cond); Type *switch_type; ExprVariantSwitch var_switch; @@ -2259,11 +2162,12 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement // Enter for scope SCOPE_OUTER_START - Expr *init; + ExprId init; if ((init = statement->for_stmt.init)) { - assert(init->expr_kind == EXPR_EXPRESSION_LIST); - Expr **expressions = init->expression_list; + Expr *init_expr = exprptr(init); + assert(init_expr->expr_kind == EXPR_EXPRESSION_LIST); + Expr **expressions = init_expr->expression_list; VECEACH (expressions, i) { Expr *expr = expressions[i]; @@ -2286,15 +2190,15 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement } } } - Expr *condition = statement->for_stmt.cond; - Expr *incr = statement->for_stmt.incr; + ExprId condition = statement->for_stmt.cond; + ExprId incr = statement->for_stmt.incr; Ast *body = astptr(statement->for_stmt.body); AstId start = 0; AstId *current = &start; assert(condition); for (int i = 0; i < MAX_MACRO_ITERATIONS; i++) { - Expr *copy = copy_expr(condition); + Expr *copy = expr_macro_copy(exprptr(condition)); if (!sema_analyse_cond_expr(context, copy)) goto EXIT_ERROR; if (copy->expr_kind != EXPR_CONST) { @@ -2303,17 +2207,17 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement } if (!copy->const_expr.b) break; - Ast *compound_stmt = ast_copy_deep(body); + Ast *compound_stmt = ast_macro_copy(body); if (!sema_analyse_compound_stmt(context, compound_stmt)) goto EXIT_ERROR; *current = astid(compound_stmt); current = &compound_stmt->next; if (incr) { - Expr **exprs = incr->expression_list; + Expr **exprs = exprptr(incr)->expression_list; VECEACH(exprs, j) { - copy = copy_expr(exprs[j]); + copy = expr_macro_copy(exprs[j]); if (!sema_analyse_expr(context, copy)) goto EXIT_ERROR; if (copy->expr_kind != EXPR_CONST) { @@ -2325,7 +2229,6 @@ static inline bool sema_analyse_ct_for_stmt(SemaContext *context, Ast *statement } statement->ast_kind = AST_COMPOUND_STMT; statement->compound_stmt.first_stmt = start; - statement->compound_stmt.defer_list = (DeferList) { 0, 0 }; success = true; EXIT_ERROR: SCOPE_OUTER_END; @@ -2353,7 +2256,6 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state switch (statement->ast_kind) { case AST_POISONED: - case AST_SCOPED_STMT: case AST_IF_CATCH_SWITCH_STMT: UNREACHABLE case AST_ASM_STMT: @@ -2380,8 +2282,6 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state return false; case AST_DEFER_STMT: return sema_analyse_defer_stmt(context, statement); - case AST_DO_STMT: - return sema_analyse_do_stmt(context, statement); case AST_EXPR_STMT: return sema_analyse_expr_stmt(context, statement); case AST_FOREACH_STMT: @@ -2392,14 +2292,14 @@ static inline bool sema_analyse_statement_inner(SemaContext *context, Ast *state return sema_analyse_if_stmt(context, statement); case AST_NOP_STMT: return true; + case AST_BLOCK_EXIT_STMT: + UNREACHABLE case AST_RETURN_STMT: return sema_analyse_return_stmt(context, statement); case AST_SWITCH_STMT: return sema_analyse_switch_stmt(context, statement); case AST_NEXT_STMT: return sema_analyse_nextcase_stmt(context, statement); - case AST_WHILE_STMT: - return sema_analyse_while_stmt(context, statement); case AST_CT_SWITCH_STMT: return sema_analyse_ct_switch_stmt(context, statement); case AST_CT_ELSE_STMT: @@ -2467,7 +2367,7 @@ END: return success; } -static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *directives, AstId **asserts, bool *ensure_found) +static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *directives, AstId **asserts) { if (!directives) return true; VECEACH(directives, i) @@ -2492,7 +2392,7 @@ static bool sema_analyse_contracts(SemaContext *context, AstDocDirective *direct break; case DOC_DIRECTIVE_ENSURE: if (!sema_analyse_ensure(context, directive)) return false; - *ensure_found = true; + context->ensures = true; break; } } @@ -2521,9 +2421,8 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) context->next_target = 0; context->next_switch = 0; context->break_target = 0; - context->return_var = NULL; + context->ensures = false; func->func_decl.annotations = CALLOCS(FuncAnnotations); - bool ensure_found = false; func->func_decl.ret_var = NULL; Ast *body = func->func_decl.body; SCOPE_START @@ -2535,7 +2434,7 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) } AstId assert_first = 0; AstId *next = &assert_first; - if (!sema_analyse_contracts(context, func->docs, &next, &ensure_found)) return false; + if (!sema_analyse_contracts(context, func->docs, &next)) return false; if (func->func_decl.attr_naked) { AstId current = func->func_decl.body->compound_stmt.first_stmt; @@ -2552,15 +2451,11 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) } else { - if (ensure_found) + if (assert_first) { - Decl *ret_val = decl_new_generated_var(context->rtype, - VARDECL_LOCAL, - func->func_decl.function_signature.returntype->span); - ret_val->name = kw_return; - context->return_var = ret_val; - func->func_decl.ret_var = ret_val; - if (!sema_add_local(context, ret_val)) return false; + Ast *ast = new_ast(AST_COMPOUND_STMT, body->span); + ast->compound_stmt.first_stmt = assert_first; + ast_prepend(&func->func_decl.body->compound_stmt.first_stmt, ast); } Type *canonical_rtype = type_no_fail(prototype->rtype)->canonical; // Insert an implicit return @@ -2589,12 +2484,6 @@ bool sema_analyse_function_body(SemaContext *context, Decl *func) return false; } } - if (assert_first) - { - Ast *ast = new_ast(AST_COMPOUND_STMT, body->span); - ast->compound_stmt.first_stmt = assert_first; - ast_prepend(&func->func_decl.body->compound_stmt.first_stmt, ast); - } SCOPE_END; return true; } diff --git a/src/compiler/semantic_analyser.c b/src/compiler/semantic_analyser.c index 1d27073e2..34db34a76 100644 --- a/src/compiler/semantic_analyser.c +++ b/src/compiler/semantic_analyser.c @@ -75,60 +75,79 @@ void context_change_scope_for_label(SemaContext *context, Decl *label) } } - - -void context_pop_defers_to(SemaContext *context, DeferList *list) +AstId context_get_defers(SemaContext *context, AstId defer_top, AstId defer_bottom) { - list->end = context->active_scope.defer_start; - assert(context->active_scope.defer_last < 10000000); - list->start = context->active_scope.defer_last; - context->active_scope.defer_last = list->end; + AstId first = 0; + AstId *next = &first; + while (defer_bottom != defer_top) + { + Ast *defer = astptr(defer_top); + Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body)); + *next = astid(defer_body); + next = &defer_body->next; + defer_top = defer->defer_stmt.prev_defer; + } + return first; } - - +void context_pop_defers(SemaContext *context, AstId *next) +{ + AstId defer_start = context->active_scope.defer_start; + if (next && !context->active_scope.jump_end) + { + AstId defer_current = context->active_scope.defer_last; + while (defer_current != defer_start) + { + Ast *defer = astptr(defer_current); + Ast *defer_body = ast_macro_copy(astptr(defer->defer_stmt.body)); + *next = astid(defer_body); + next = &defer_body->next; + defer_current = defer->defer_stmt.prev_defer; + } + } + context->active_scope.defer_last = defer_start; +} Expr *context_pop_defers_and_wrap_expr(SemaContext *context, Expr *expr) { - DeferList defers = { 0, 0 }; - context_pop_defers_to(context, &defers); - if (defers.end == defers.start) return expr; - Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span); - wrap->type = expr->type; - wrap->resolve_status = RESOLVE_DONE; - wrap->expr_scope.expr = expr; - wrap->expr_scope.defers = defers; + AstId defer_first = 0; + context_pop_defers(context, &defer_first); + if (defer_first) + { + Expr *wrap = expr_new(EXPR_SCOPED_EXPR, expr->span); + wrap->type = expr->type; + wrap->resolve_status = RESOLVE_DONE; + wrap->expr_scope.expr = expr; + wrap->expr_scope.defer_stmts = defer_first; + return wrap; + } return expr; } void context_pop_defers_and_replace_expr(SemaContext *context, Expr *expr) { - DeferList defers = { 0, 0 }; - context_pop_defers_to(context, &defers); - if (defers.end == defers.start) return; - Expr *inner = expr_copy(expr); - expr->expr_kind = EXPR_SCOPED_EXPR; - expr->expr_scope.expr = inner; - expr->expr_scope.defers = defers; + AstId defer_first = 0; + context_pop_defers(context, &defer_first); + if (defer_first) + { + Expr *inner = expr_copy(expr); + expr->expr_kind = EXPR_SCOPED_EXPR; + expr->expr_scope.expr = inner; + expr->expr_scope.defer_stmts = defer_first; + } } void context_pop_defers_and_replace_ast(SemaContext *context, Ast *ast) { - DeferList defers = { 0, 0 }; - context_pop_defers_to(context, &defers); - if (defers.end == defers.start) return; - if (ast->ast_kind == AST_DEFER_STMT) - { - assert(defers.start == astid(ast)); - *ast = *ast->defer_stmt.body; - return; - } + AstId defer_first = 0; + context_pop_defers(context, &defer_first); + if (!defer_first) return; assert(ast->ast_kind != AST_COMPOUND_STMT); Ast *replacement = ast_copy(ast); - ast->ast_kind = AST_SCOPED_STMT; - ast->scoped_stmt.stmt = astid(replacement); - ast->scoped_stmt.defers = defers; + ast->ast_kind = AST_COMPOUND_STMT; + ast->compound_stmt.first_stmt = astid(replacement); + replacement->next = defer_first; } static inline void halt_on_error(void) diff --git a/src/version.h b/src/version.h index 32aa4662f..a9a3c0a98 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define COMPILER_VERSION "PRE.24" \ No newline at end of file +#define COMPILER_VERSION "PRE.25" \ No newline at end of file diff --git a/test/test_suite/contracts/simple_test.c3t b/test/test_suite/contracts/simple_test.c3t index 30fcb97c4..c6c312461 100644 --- a/test/test_suite/contracts/simple_test.c3t +++ b/test/test_suite/contracts/simple_test.c3t @@ -53,30 +53,18 @@ entry: define i32 @simple_test.test2(i32* %0, i32 %1) #0 { entry: - %return = alloca i32, align 4 %gt = icmp sgt i32 %1, 100 call void @llvm.assume(i1 %gt) store i32 444, i32* %0, align 8 - store i32 %1, i32* %return, align 4 - %2 = load i32, i32* %return, align 4 - %lt = icmp slt i32 %2, 200 - call void @llvm.assume(i1 %lt) - %3 = load i32, i32* %return, align 4 - ret i32 %3 + ret i32 %1 } define i32 @simple_test.test3(i32 %0) #0 { entry: - %return = alloca i32, align 4 %gt = icmp sgt i32 %0, 0 call void @llvm.assume(i1 %gt) %add = add i32 %0, 1 - store i32 %add, i32* %return, align 4 - %1 = load i32, i32* %return, align 4 - %gt1 = icmp sgt i32 %1, 0 - call void @llvm.assume(i1 %gt1) - %2 = load i32, i32* %return, align 4 - ret i32 %2 + ret i32 %add } define void @simple_test.main() #0 { diff --git a/test/test_suite/from_docs/examples_defer.c3t b/test/test_suite/from_docs/examples_defer.c3t index 0ca07f8b0..bb615f6a7 100644 --- a/test/test_suite/from_docs/examples_defer.c3t +++ b/test/test_suite/from_docs/examples_defer.c3t @@ -21,7 +21,7 @@ fn void main() test(10); // Prints "B!A" } -// #expect: defer1.ll +/* #expect: defer1.ll define void @defer1.test(i32 %0) #0 { entry: @@ -30,48 +30,24 @@ entry: if.then: ; preds = %entry %1 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str, i32 0, i32 0)) - br label %exit - -exit: ; preds = %if.then %2 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.1, i32 0, i32 0)) #1 - br label %exit1 - -exit1: ; preds = %exit ret void if.exit: ; preds = %entry - %eq2 = icmp eq i32 %0, 0 - br i1 %eq2, label %if.then3, label %if.exit7 + %eq1 = icmp eq i32 %0, 0 + br i1 %eq1, label %if.then2, label %if.exit3 -if.then3: ; preds = %if.exit +if.then2: ; preds = %if.exit %3 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.2, i32 0, i32 0)) - br label %exit4 - -exit4: ; preds = %if.then3 %4 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.3, i32 0, i32 0)) - br label %exit5 - -exit5: ; preds = %exit4 %5 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.4, i32 0, i32 0)) #1 - br label %exit6 - -exit6: ; preds = %exit5 ret void -if.exit7: ; preds = %if.exit +if.exit3: ; preds = %if.exit %6 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.5, i32 0, i32 0)) - br label %exit8 - -exit8: ; preds = %if.exit7 %7 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.6, i32 0, i32 0)) %8 = call i32 @"std::io.print"(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.7, i32 0, i32 0)) - br label %exit9 - -exit9: ; preds = %exit8 %9 = call i32 @"std::io.println"(i8* getelementptr inbounds ([1 x i8], [1 x i8]* @.str.8, i32 0, i32 0)) #1 - br label %exit10 - -exit10: ; preds = %exit9 ret void } diff --git a/test/test_suite/macros/macro_defer_exit.c3t b/test/test_suite/macros/macro_defer_exit.c3t new file mode 100644 index 000000000..521120bcf --- /dev/null +++ b/test/test_suite/macros/macro_defer_exit.c3t @@ -0,0 +1,83 @@ +// #target: x64-darwin +module foo; +extern fn void printf(char*,...); + +macro int abc(x) +{ + defer printf("Out x %d\n", x); + x *= 2; + if (x > 100) return x = x - 100; + printf("Normal end\n"); + return x; +} + +fn void main() +{ + defer printf("On exit\n"); + @abc(123); + @abc(3); +} + +/* #expect: foo.ll + +define void @foo.main() #0 { +entry: + %x = alloca i32, align 4 + %blockret = alloca i32, align 4 + %x1 = alloca i32, align 4 + %blockret2 = alloca i32, align 4 + store i32 123, i32* %x, align 4 + %0 = load i32, i32* %x, align 4 + %mul = mul i32 %0, 2 + store i32 %mul, i32* %x, align 4 + %1 = load i32, i32* %x, align 4 + %gt = icmp sgt i32 %1, 100 + br i1 %gt, label %if.then, label %if.exit + +if.then: ; preds = %entry + %2 = load i32, i32* %x, align 4 + %sub = sub i32 %2, 100 + store i32 %sub, i32* %x, align 4 + %3 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i32 %3) + store i32 %sub, i32* %blockret, align 4 + br label %expr_block.exit + +if.exit: ; preds = %entry + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.1, i32 0, i32 0)) + %4 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %4) + %5 = load i32, i32* %x, align 4 + store i32 %5, i32* %blockret, align 4 + br label %expr_block.exit + +expr_block.exit: ; preds = %if.exit, %if.then + store i32 3, i32* %x1, align 4 + %6 = load i32, i32* %x1, align 4 + %mul3 = mul i32 %6, 2 + store i32 %mul3, i32* %x1, align 4 + %7 = load i32, i32* %x1, align 4 + %gt4 = icmp sgt i32 %7, 100 + br i1 %gt4, label %if.then5, label %if.exit7 + +if.then5: ; preds = %expr_block.exit + %8 = load i32, i32* %x1, align 4 + %sub6 = sub i32 %8, 100 + store i32 %sub6, i32* %x1, align 4 + %9 = load i32, i32* %x1, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0), i32 %9) + store i32 %sub6, i32* %blockret2, align 4 + br label %expr_block.exit8 + +if.exit7: ; preds = %expr_block.exit + call void (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str.4, i32 0, i32 0)) + %10 = load i32, i32* %x1, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 %10) + %11 = load i32, i32* %x1, align 4 + store i32 %11, i32* %blockret2, align 4 + br label %expr_block.exit8 + +expr_block.exit8: ; preds = %if.exit7, %if.then5 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str.6, i32 0, i32 0)) + ret void +} diff --git a/test/test_suite/macros/macro_defer_noscope.c3t b/test/test_suite/macros/macro_defer_noscope.c3t index 2996962aa..4b87726b1 100644 --- a/test/test_suite/macros/macro_defer_noscope.c3t +++ b/test/test_suite/macros/macro_defer_noscope.c3t @@ -45,12 +45,6 @@ entry: call void @foo.foo1() call void (i8*, ...) @printf(i8* getelementptr inbounds ([9 x i8], [9 x i8]* @.str, i32 0, i32 0), i32 3) call void @foo2.foo2() - br label %exit - -exit: ; preds = %entry call void @foo2.foo2() - br label %exit1 - -exit1: ; preds = %exit ret void } diff --git a/test/test_suite/macros/macro_defer_scope.c3t b/test/test_suite/macros/macro_defer_scope.c3t index 5c3f7d35d..1b4ce5ea0 100644 --- a/test/test_suite/macros/macro_defer_scope.c3t +++ b/test/test_suite/macros/macro_defer_scope.c3t @@ -21,6 +21,7 @@ fn void main() define void @foo.main() #0 { entry: %x = alloca i32, align 4 + %blockret = alloca i32, align 4 %x1 = alloca i32, align 4 store i32 0, i32* %x, align 4 store i32 0, i32* %x1, align 4 @@ -32,9 +33,10 @@ entry: store i32 %add2, i32* %x, align 4 %add3 = add i32 %add, %add2 %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0)) - br label %exit + store i32 %add3, i32* %blockret, align 4 + br label %expr_block.exit -exit: ; preds = %entry +expr_block.exit: ; preds = %entry %3 = load i32, i32* %x, align 4 %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %3) ret void diff --git a/test/test_suite/macros/macro_defer_with_body.c3t b/test/test_suite/macros/macro_defer_with_body.c3t index 8a2d87ba5..abec94d23 100644 --- a/test/test_suite/macros/macro_defer_with_body.c3t +++ b/test/test_suite/macros/macro_defer_with_body.c3t @@ -38,9 +38,6 @@ entry: %add1 = add i32 %3, 1 store i32 %add1, i32* %x, align 4 %4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i32 %3) - br label %exit - -exit: ; preds = %entry %5 = load i32, i32* %a, align 4 store i32 %5, i32* %y, align 4 %6 = load i32, i32* %x, align 4 @@ -51,9 +48,6 @@ exit: ; preds = %entry %add3 = add i32 %8, 1 store i32 %add3, i32* %x, align 4 %9 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.3, i32 0, i32 0), i32 %8) - br label %exit4 - -exit4: ; preds = %exit %10 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.4, i32 0, i32 0)) ret void } diff --git a/test/test_suite/macros/userland_bitcast.c3t b/test/test_suite/macros/userland_bitcast.c3t index c224696f7..df1bb0d96 100644 --- a/test/test_suite/macros/userland_bitcast.c3t +++ b/test/test_suite/macros/userland_bitcast.c3t @@ -81,7 +81,6 @@ fn void main() @.str = private unnamed_addr constant [16 x i8] c"%f => %d => %f\0A\00", align 1 @.str.1 = private unnamed_addr constant [18 x i8] c"%e => %llu => %e\0A\00", align 1 -; Function Attrs: nounwind define i64 @userland_bitcast.testFoo(i16 signext %0) #0 { entry: %z = alloca %Foo, align 2 @@ -104,6 +103,7 @@ entry: store i16 %0, i16* %6, align 2 %7 = load %Foo, %Foo* %z, align 2 store %Foo %7, %Foo* %expr, align 2 + store i64 0, i64* %x, align 8 %ptrptr = bitcast %Foo* %expr to i16* store i16* %ptrptr, i16** %b, align 8 %ptrptr1 = bitcast i64* %x to i16* @@ -144,6 +144,14 @@ entry: %i = alloca i64, align 8 %tempcoerce = alloca i32, align 4 store float %0, float* %expr, align 4 + %1 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 0 + store i8 0, i8* %1, align 1 + %2 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 1 + store i8 0, i8* %2, align 1 + %3 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 2 + store i8 0, i8* %3, align 1 + %4 = getelementptr inbounds [4 x i8], [4 x i8]* %x, i64 0, i64 3 + store i8 0, i8* %4, align 1 %ptrptr = bitcast float* %expr to i8* store i8* %ptrptr, i8** %b, align 8 %ptrptr1 = bitcast [4 x i8]* %x to i8* @@ -152,30 +160,30 @@ entry: br label %loop.cond loop.cond: ; preds = %loop.body, %entry - %1 = load i64, i64* %i, align 8 - %lt = icmp ult i64 %1, 4 + %5 = load i64, i64* %i, align 8 + %lt = icmp ult i64 %5, 4 br i1 %lt, label %loop.body, label %loop.exit loop.body: ; preds = %loop.cond - %2 = load i8*, i8** %to, align 8 - %3 = load i64, i64* %i, align 8 - %ptroffset = getelementptr inbounds i8, i8* %2, i64 %3 - %4 = load i8*, i8** %b, align 8 - %5 = load i64, i64* %i, align 8 - %ptroffset2 = getelementptr inbounds i8, i8* %4, i64 %5 - %6 = load i8, i8* %ptroffset2, align 1 - store i8 %6, i8* %ptroffset, align 1 + %6 = load i8*, i8** %to, align 8 %7 = load i64, i64* %i, align 8 - %add = add i64 %7, 1 + %ptroffset = getelementptr inbounds i8, i8* %6, i64 %7 + %8 = load i8*, i8** %b, align 8 + %9 = load i64, i64* %i, align 8 + %ptroffset2 = getelementptr inbounds i8, i8* %8, i64 %9 + %10 = load i8, i8* %ptroffset2, align 1 + store i8 %10, i8* %ptroffset, align 1 + %11 = load i64, i64* %i, align 8 + %add = add i64 %11, 1 store i64 %add, i64* %i, align 8 br label %loop.cond loop.exit: ; preds = %loop.cond - %8 = bitcast i32* %tempcoerce to i8* - %9 = bitcast [4 x i8]* %x to i8* - call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %8, i8* align 1 %9, i32 4, i1 false) - %10 = load i32, i32* %tempcoerce, align 4 - ret i32 %10 + %12 = bitcast i32* %tempcoerce to i8* + %13 = bitcast [4 x i8]* %x to i8* + call void @llvm.memcpy.p0i8.p0i8.i32(i8* align 4 %12, i8* align 1 %13, i32 4, i1 false) + %14 = load i32, i32* %tempcoerce, align 4 + ret i32 %14 } define void @userland_bitcast.main() #0 { @@ -209,6 +217,7 @@ entry: store float 0x4028B4BC60000000, float* %f, align 4 %0 = load float, float* %f, align 4 store float %0, float* %expr, align 4 + store i32 0, i32* %x, align 4 %ptrptr = bitcast float* %expr to i32* store i32* %ptrptr, i32** %b, align 8 store i32* %x, i32** %to, align 8 @@ -239,6 +248,7 @@ loop.exit: ; preds = %loop.cond store i32 %8, i32* %i, align 4 %9 = load i32, i32* %i, align 4 store i32 %9, i32* %expr3, align 4 + store float 0.000000e+00, float* %x4, align 4 store i32* %expr3, i32** %b5, align 8 %ptrptr7 = bitcast float* %x4 to i32* store i32* %ptrptr7, i32** %to6, align 8 @@ -276,6 +286,7 @@ loop.exit15: ; preds = %loop.cond9 store double 1.235300e+268, double* %d, align 8 %21 = load double, double* %d, align 8 store double %21, double* %expr17, align 8 + store i64 0, i64* %x18, align 8 %ptrptr20 = bitcast double* %expr17 to i64* store i64* %ptrptr20, i64** %b19, align 8 store i64* %x18, i64** %to21, align 8 @@ -306,6 +317,7 @@ loop.exit29: ; preds = %loop.cond23 store i64 %29, i64* %l, align 8 %30 = load double, double* %d, align 8 store double %30, double* %expr30, align 8 + store double 0.000000e+00, double* %x31, align 8 %ptrptr33 = bitcast double* %expr30 to i64* store i64* %ptrptr33, i64** %b32, align 8 %ptrptr35 = bitcast double* %x31 to i64* @@ -340,4 +352,5 @@ loop.exit43: ; preds = %loop.cond37 %41 = load double, double* %d2, align 8 call void (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.1, i32 0, i32 0), double %39, i64 %40, double %41) ret void -} \ No newline at end of file +} + diff --git a/test/test_suite/statements/defer_break.c3t b/test/test_suite/statements/defer_break.c3t index 1e66213f2..b8dc8b0e1 100644 --- a/test/test_suite/statements/defer_break.c3t +++ b/test/test_suite/statements/defer_break.c3t @@ -18,11 +18,10 @@ fn int main(int argc, char** argv) { int a = 0; { - defer - { + defer do { if (a == 1) break; defer1(); - } + } while(0); defer2(); } defer defer3(); @@ -58,82 +57,58 @@ entry: br i1 %eq, label %if.then, label %if.exit if.then: ; preds = %entry - br label %exit + br label %loop.exit if.exit: ; preds = %entry call void @foo.defer1() - br label %exit + br label %loop.exit -exit: ; preds = %if.exit, %if.then +loop.exit: ; preds = %if.exit, %if.then br label %loop.cond -loop.cond: ; preds = %exit6, %exit +loop.cond: ; preds = %if.exit3, %loop.exit %3 = load i32, i32* %a, align 4 %intbool = icmp ne i32 %3, 0 - br i1 %intbool, label %loop.body, label %loop.exit + br i1 %intbool, label %loop.body, label %loop.exit4 loop.body: ; preds = %loop.cond %eq1 = icmp eq i32 %0, 1 - br i1 %eq1, label %if.then2, label %if.exit4 + br i1 %eq1, label %if.then2, label %if.exit3 if.then2: ; preds = %loop.body call void @foo.defer4() - br label %exit3 + br label %loop.exit4 -exit3: ; preds = %if.then2 - br label %loop.exit - -if.exit4: ; preds = %loop.body +if.exit3: ; preds = %loop.body call void @foo.defer6() call void @foo.defer5() - br label %exit5 - -exit5: ; preds = %if.exit4 call void @foo.defer4() - br label %exit6 - -exit6: ; preds = %exit5 br label %loop.cond -loop.exit: ; preds = %exit3, %loop.cond - br label %loop.cond7 +loop.exit4: ; preds = %if.then2, %loop.cond + br label %loop.cond5 -loop.cond7: ; preds = %loop.exit +loop.cond5: ; preds = %loop.exit4 %4 = load i32, i32* %a, align 4 - %intbool8 = icmp ne i32 %4, 0 - br i1 %intbool8, label %loop.body9, label %loop.exit18 + %intbool6 = icmp ne i32 %4, 0 + br i1 %intbool6, label %loop.body7, label %loop.exit11 -loop.body9: ; preds = %loop.cond7 - %eq10 = icmp eq i32 %0, 1 - br i1 %eq10, label %if.then11, label %if.exit13 +loop.body7: ; preds = %loop.cond5 + %eq8 = icmp eq i32 %0, 1 + br i1 %eq8, label %if.then9, label %if.exit10 -if.then11: ; preds = %loop.body9 +if.then9: ; preds = %loop.body7 call void @foo.defer8() - br label %exit12 + br label %loop.exit11 -exit12: ; preds = %if.then11 - br label %loop.exit18 - -if.exit13: ; preds = %loop.body9 +if.exit10: ; preds = %loop.body7 call void @foo.defer10() call void @foo.defer9() - br label %exit14 - -exit14: ; preds = %if.exit13 call void @foo.defer8() - br label %exit15 + br label %loop.exit11 -exit15: ; preds = %exit14 - br label %loop.exit18 - -loop.exit18: ; preds = %exit15, %exit12, %loop.cond7 +loop.exit11: ; preds = %if.exit10, %if.then9, %loop.cond5 call void @foo.defer7() - br label %exit19 - -exit19: ; preds = %loop.exit18 call void @foo.defer3() - br label %exit20 - -exit20: ; preds = %exit19 ret i32 0 } \ No newline at end of file diff --git a/test/test_suite/statements/defer_break_simple.c3t b/test/test_suite/statements/defer_break_simple.c3t index e9d971445..0540f3082 100644 --- a/test/test_suite/statements/defer_break_simple.c3t +++ b/test/test_suite/statements/defer_break_simple.c3t @@ -23,7 +23,8 @@ fn int main(int argc, char** argv) return 0; } -// #expect: test.ll +/* #expect: test.ll + define i32 @main(i32 %0, i8** %1) #0 { @@ -32,7 +33,7 @@ entry: store i32 0, i32* %a, align 4 br label %loop.cond -loop.cond: ; preds = %exit3, %entry +loop.cond: ; preds = %if.exit, %entry %2 = load i32, i32* %a, align 4 %intbool = icmp ne i32 %2, 0 br i1 %intbool, label %loop.body, label %loop.exit @@ -44,28 +45,16 @@ loop.body: ; preds = %loop.cond if.then: ; preds = %loop.body call void @test.testA() call void @test.testB() - br label %exit - -exit: ; preds = %if.then call void @test.test2() - br label %exit1 - -exit1: ; preds = %exit br label %loop.exit if.exit: ; preds = %loop.body call void @test.test3() call void @test.testA() call void @test.testB() - br label %exit2 - -exit2: ; preds = %if.exit call void @test.test2() - br label %exit3 - -exit3: ; preds = %exit2 br label %loop.cond -loop.exit: ; preds = %exit1, %loop.cond +loop.exit: ; preds = %if.then, %loop.cond ret i32 0 } diff --git a/test/test_suite/statements/defer_break_switch.c3t b/test/test_suite/statements/defer_break_switch.c3t index de74c2eba..c882244a7 100644 --- a/test/test_suite/statements/defer_break_switch.c3t +++ b/test/test_suite/statements/defer_break_switch.c3t @@ -19,7 +19,7 @@ fn void test(int i) } } -// #expect: defer_break_switch.ll +/* #expect: defer_break_switch.ll define void @defer_break_switch.test(i32 %0) #0 { entry: @@ -33,7 +33,7 @@ switch.entry: ; preds = %entry %1 = load i32, i32* %switch, align 4 switch i32 %1, label %switch.exit [ i32 1, label %switch.case - i32 2, label %switch.case2 + i32 2, label %switch.case1 ] switch.case: ; preds = %switch.entry @@ -43,23 +43,17 @@ switch.case: ; preds = %switch.entry if.then: ; preds = %switch.case call void @defer_break_switch.test2() - br label %exit - -exit: ; preds = %if.then br label %switch.exit if.exit: ; preds = %switch.case call void @defer_break_switch.test1() call void @defer_break_switch.test2() - br label %exit1 - -exit1: ; preds = %if.exit br label %switch.exit -switch.case2: ; preds = %switch.entry +switch.case1: ; preds = %switch.entry call void @defer_break_switch.test1() br label %switch.exit -switch.exit: ; preds = %switch.case2, %exit1, %exit, %switch.entry +switch.exit: ; preds = %switch.case1, %if.exit, %if.then, %switch.entry ret void } diff --git a/test/test_suite/statements/defer_do_while.c3t b/test/test_suite/statements/defer_do_while.c3t new file mode 100644 index 000000000..7c835cb19 --- /dev/null +++ b/test/test_suite/statements/defer_do_while.c3t @@ -0,0 +1,38 @@ +// #target: x64-darwin +module foo; + +fn void test() +{ + int a; + do + { + a++; + defer a++; + } while(a < 10); +} + +/* #expect: foo.ll + +define void @foo.test() #0 { +entry: + %a = alloca i32, align 4 + store i32 0, i32* %a, align 4 + br label %loop.body + +loop.cond: ; preds = %loop.body + %0 = load i32, i32* %a, align 4 + %lt = icmp slt i32 %0, 10 + br i1 %lt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond, %entry + %1 = load i32, i32* %a, align 4 + %add = add i32 %1, 1 + store i32 %add, i32* %a, align 4 + %2 = load i32, i32* %a, align 4 + %add1 = add i32 %2, 1 + store i32 %add1, i32* %a, align 4 + br label %loop.cond + +loop.exit: ; preds = %loop.cond + ret void +} \ No newline at end of file diff --git a/test/test_suite/statements/defer_in_block.c3t b/test/test_suite/statements/defer_in_block.c3t new file mode 100644 index 000000000..6e6d5f924 --- /dev/null +++ b/test/test_suite/statements/defer_in_block.c3t @@ -0,0 +1,71 @@ +// #target: x64-darwin +module foo; +extern fn void printf(char*,...); + +fn void test(int x) +{ + defer printf("---\n"); + {| + defer printf("Hello %d\n", x); + x *= 2; + if (x < 100) return; + x *= 10000; + |}; + printf("+++\n"); + if (x == 0) + { + printf("0x\n"); + return; + } + if (x == 1) return; +} + +fn void main() +{ + test(123); + test(1); + test(0); +} +/* #expect: foo.ll + +define void @foo.test(i32 %0) #0 { +entry: + %x = alloca i32, align 4 + store i32 %0, i32* %x, align 4 + %1 = load i32, i32* %x, align 4 + %mul = mul i32 %1, 2 + store i32 %mul, i32* %x, align 4 + %2 = load i32, i32* %x, align 4 + %lt = icmp slt i32 %2, 100 + br i1 %lt, label %if.then, label %if.exit +if.then: ; preds = %entry + %3 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i32 %3) + br label %expr_block.exit +if.exit: ; preds = %entry + %4 = load i32, i32* %x, align 4 + %mul1 = mul i32 %4, 10000 + store i32 %mul1, i32* %x, align 4 + %5 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i32 0, i32 0), i32 %5) + br label %expr_block.exit +expr_block.exit: ; preds = %if.exit, %if.then + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.2, i32 0, i32 0)) + %6 = load i32, i32* %x, align 4 + %eq = icmp eq i32 %6, 0 + br i1 %eq, label %if.then2, label %if.exit3 +if.then2: ; preds = %expr_block.exit + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0)) + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.4, i32 0, i32 0)) + ret void +if.exit3: ; preds = %expr_block.exit + %7 = load i32, i32* %x, align 4 + %eq4 = icmp eq i32 %7, 1 + br i1 %eq4, label %if.then5, label %if.exit6 +if.then5: ; preds = %if.exit3 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.5, i32 0, i32 0)) + ret void +if.exit6: ; preds = %if.exit3 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.6, i32 0, i32 0)) + ret void +} diff --git a/test/test_suite/statements/defer_in_defer.c3t b/test/test_suite/statements/defer_in_defer.c3t index 10f04d6d9..4e7d3aa01 100644 --- a/test/test_suite/statements/defer_in_defer.c3t +++ b/test/test_suite/statements/defer_in_defer.c3t @@ -22,15 +22,17 @@ fn void test_line() // #expect: defer_in_defer.ll +define void @defer_in_defer.test() #0 { entry: call void @defer_in_defer.test4() call void @defer_in_defer.test2() call void @defer_in_defer.test3() - br label %exit - -exit: call void @defer_in_defer.test1() + ret void +} +define void @defer_in_defer.test_line() #0 { entry: call void @defer_in_defer.test1() - br label %exit \ No newline at end of file + ret void +} diff --git a/test/test_suite/statements/defer_in_defer2.c3t b/test/test_suite/statements/defer_in_defer2.c3t new file mode 100644 index 000000000..938919532 --- /dev/null +++ b/test/test_suite/statements/defer_in_defer2.c3t @@ -0,0 +1,120 @@ +// #target: x64-darwin + +module test; +extern fn void printf(char*,...); + +fn void test(int x) +{ + defer + { + do + { + defer printf("Hello %d\n", x); + x *= 2; + if (x < 100) break; + x *= 10000; + }; + } + if (x == 1) + { + printf("1x\n"); + return; + } + if (x == 0) return; +} + +fn void main() +{ + test(123); + test(1); + test(0); +} + +/* #expect: test.ll + +define void @test.test(i32 %0) #0 { +entry: + %x = alloca i32, align 4 + store i32 %0, i32* %x, align 4 + %1 = load i32, i32* %x, align 4 + %eq = icmp eq i32 %1, 1 + br i1 %eq, label %if.then, label %if.exit3 + +if.then: ; preds = %entry + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0)) + %2 = load i32, i32* %x, align 4 + %mul = mul i32 %2, 2 + store i32 %mul, i32* %x, align 4 + %3 = load i32, i32* %x, align 4 + %lt = icmp slt i32 %3, 100 + br i1 %lt, label %if.then1, label %if.exit + +if.then1: ; preds = %if.then + %4 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.1, i32 0, i32 0), i32 %4) + br label %loop.exit + +if.exit: ; preds = %if.then + %5 = load i32, i32* %x, align 4 + %mul2 = mul i32 %5, 10000 + store i32 %mul2, i32* %x, align 4 + %6 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i32 %6) + br label %loop.exit + +loop.exit: ; preds = %if.exit, %if.then1 + ret void + +if.exit3: ; preds = %entry + %7 = load i32, i32* %x, align 4 + %eq4 = icmp eq i32 %7, 0 + br i1 %eq4, label %if.then5, label %if.exit12 + +if.then5: ; preds = %if.exit3 + %8 = load i32, i32* %x, align 4 + %mul6 = mul i32 %8, 2 + store i32 %mul6, i32* %x, align 4 + %9 = load i32, i32* %x, align 4 + %lt7 = icmp slt i32 %9, 100 + br i1 %lt7, label %if.then8, label %if.exit9 + +if.then8: ; preds = %if.then5 + %10 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.3, i32 0, i32 0), i32 %10) + br label %loop.exit11 + +if.exit9: ; preds = %if.then5 + %11 = load i32, i32* %x, align 4 + %mul10 = mul i32 %11, 10000 + store i32 %mul10, i32* %x, align 4 + %12 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.4, i32 0, i32 0), i32 %12) + br label %loop.exit11 + +loop.exit11: ; preds = %if.exit9, %if.then8 + ret void + +if.exit12: ; preds = %if.exit3 + %13 = load i32, i32* %x, align 4 + %mul13 = mul i32 %13, 2 + store i32 %mul13, i32* %x, align 4 + %14 = load i32, i32* %x, align 4 + %lt14 = icmp slt i32 %14, 100 + br i1 %lt14, label %if.then15, label %if.exit16 + +if.then15: ; preds = %if.exit12 + %15 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.5, i32 0, i32 0), i32 %15) + br label %loop.exit18 + +if.exit16: ; preds = %if.exit12 + %16 = load i32, i32* %x, align 4 + %mul17 = mul i32 %16, 10000 + store i32 %mul17, i32* %x, align 4 + %17 = load i32, i32* %x, align 4 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i32 %17) + br label %loop.exit18 + +loop.exit18: ; preds = %if.exit16, %if.then15 + ret void +} \ No newline at end of file diff --git a/test/test_suite/statements/defer_next_switch.c3t b/test/test_suite/statements/defer_next_switch.c3t index 20b8ee167..f26388e5f 100644 --- a/test/test_suite/statements/defer_next_switch.c3t +++ b/test/test_suite/statements/defer_next_switch.c3t @@ -19,7 +19,7 @@ fn void test(int i) } } -// #expect: defer_next_switch.ll +/* #expect: defer_next_switch.ll define void @defer_next_switch.test(i32 %0) #0 { entry: @@ -33,7 +33,7 @@ switch.entry: ; preds = %entry %1 = load i32, i32* %switch, align 4 switch i32 %1, label %switch.exit [ i32 1, label %switch.case - i32 2, label %switch.case2 + i32 2, label %switch.case1 ] switch.case: ; preds = %switch.entry @@ -43,23 +43,17 @@ switch.case: ; preds = %switch.entry if.then: ; preds = %switch.case call void @defer_next_switch.test2() - br label %exit - -exit: ; preds = %if.then - br label %switch.case2 + br label %switch.case1 if.exit: ; preds = %switch.case call void @defer_next_switch.test1() call void @defer_next_switch.test2() - br label %exit1 - -exit1: ; preds = %if.exit br label %switch.exit -switch.case2: ; preds = %switch.entry, %exit +switch.case1: ; preds = %switch.entry, %if.then call void @defer_next_switch.test1() br label %switch.exit -switch.exit: ; preds = %switch.case2, %exit1, %switch.entry +switch.exit: ; preds = %switch.case1, %if.exit, %switch.entry ret void } diff --git a/test/test_suite/statements/defer_return.c3t b/test/test_suite/statements/defer_return.c3t index 5494a5a2f..f48f89c17 100644 --- a/test/test_suite/statements/defer_return.c3t +++ b/test/test_suite/statements/defer_return.c3t @@ -42,7 +42,7 @@ entry: store i32 0, i32* %a, align 4 br label %loop.cond -loop.cond: ; preds = %exit3, %entry +loop.cond: ; preds = %if.exit, %entry %2 = load i32, i32* %a, align 4 %intbool = icmp ne i32 %2, 0 br i1 %intbool, label %loop.body, label %loop.exit @@ -55,85 +55,46 @@ if.then: ; preds = %loop.body %3 = load i32, i32* %a, align 4 %add = add i32 %3, %0 call void @test.test2() - br label %exit - -exit: ; preds = %if.then call void @test.test1() - br label %exit1 - -exit1: ; preds = %exit ret i32 %add if.exit: ; preds = %loop.body call void @test.test4() call void @test.test3() - br label %exit2 - -exit2: ; preds = %if.exit call void @test.test2() - br label %exit3 - -exit3: ; preds = %exit2 br label %loop.cond loop.exit: ; preds = %loop.cond - br label %loop.cond4 + br label %loop.cond1 -loop.cond4: ; preds = %loop.exit +loop.cond1: ; preds = %loop.exit %4 = load i32, i32* %a, align 4 - %intbool5 = icmp ne i32 %4, 0 - br i1 %intbool5, label %loop.body6, label %loop.exit21 + %intbool2 = icmp ne i32 %4, 0 + br i1 %intbool2, label %loop.body3, label %loop.exit8 -loop.body6: ; preds = %loop.cond4 - %eq7 = icmp eq i32 %0, 1 - br i1 %eq7, label %if.then8, label %if.exit13 +loop.body3: ; preds = %loop.cond1 + %eq4 = icmp eq i32 %0, 1 + br i1 %eq4, label %if.then5, label %if.exit7 -if.then8: ; preds = %loop.body6 +if.then5: ; preds = %loop.body3 %5 = load i32, i32* %a, align 4 - %add9 = add i32 %5, 2 + %add6 = add i32 %5, 2 call void @test.test6() - br label %exit10 - -exit10: ; preds = %if.then8 call void @test.test5() - br label %exit11 - -exit11: ; preds = %exit10 call void @test.test1() - br label %exit12 + ret i32 %add6 -exit12: ; preds = %exit11 - ret i32 %add9 - -if.exit13: ; preds = %loop.body6 +if.exit7: ; preds = %loop.body3 call void @test.test8() call void @test.test7() - br label %exit14 - -exit14: ; preds = %if.exit13 call void @test.test6() - br label %exit15 - -exit15: ; preds = %exit14 call void @test.test5() - br label %exit16 - -exit16: ; preds = %exit15 call void @test.test1() - br label %exit17 - -exit17: ; preds = %exit16 ret i32 4 -loop.exit21: ; preds = %loop.cond4 - %add22 = add i32 0, %0 +loop.exit8: ; preds = %loop.cond1 + %add9 = add i32 0, %0 call void @test.test5() - br label %exit23 - -exit23: ; preds = %loop.exit21 call void @test.test1() - br label %exit24 - -exit24: ; preds = %exit23 - ret i32 %add22 -} + ret i32 %add9 +} \ No newline at end of file diff --git a/test/test_suite/statements/defer_test.c3 b/test/test_suite/statements/defer_test.c3 index 6d240f8f9..81b9bf3e9 100644 --- a/test/test_suite/statements/defer_test.c3 +++ b/test/test_suite/statements/defer_test.c3 @@ -4,7 +4,6 @@ fn void test() defer { i = i + 1; - break; } return; } \ No newline at end of file diff --git a/test/test_suite/statements/defer_with_loop.c3t b/test/test_suite/statements/defer_with_loop.c3t new file mode 100644 index 000000000..e44aae8b7 --- /dev/null +++ b/test/test_suite/statements/defer_with_loop.c3t @@ -0,0 +1,108 @@ +// #target: x64-darwin +module test; + +extern fn void printf(char*,...); + +fn void test(int x) +{ + defer + { + for (int i = 0; i < 3; i++) + { + printf("%d\n", x + i); + } + } + if (x == 1) + { + printf("1x\n"); + return; + } + if (x == 0) return; +} + +fn void main() +{ + test(123); + test(1); + test(0); +} + +/* #expect: test.ll + +define void @test.test(i32 %0) #0 { +entry: + %i = alloca i32, align 4 + %i4 = alloca i32, align 4 + %i12 = alloca i32, align 4 + %eq = icmp eq i32 %0, 1 + br i1 %eq, label %if.then, label %if.exit + +if.then: ; preds = %entry + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0)) + store i32 0, i32* %i, align 4 + br label %loop.cond + +loop.cond: ; preds = %loop.body, %if.then + %1 = load i32, i32* %i, align 4 + %lt = icmp slt i32 %1, 3 + br i1 %lt, label %loop.body, label %loop.exit + +loop.body: ; preds = %loop.cond + %2 = load i32, i32* %i, align 4 + %add = add i32 %0, %2 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %add) + %3 = load i32, i32* %i, align 4 + %add1 = add i32 %3, 1 + store i32 %add1, i32* %i, align 4 + br label %loop.cond + +loop.exit: ; preds = %loop.cond + ret void + +if.exit: ; preds = %entry + %eq2 = icmp eq i32 %0, 0 + br i1 %eq2, label %if.then3, label %if.exit11 + +if.then3: ; preds = %if.exit + store i32 0, i32* %i4, align 4 + br label %loop.cond5 + +loop.cond5: ; preds = %loop.body7, %if.then3 + %4 = load i32, i32* %i4, align 4 + %lt6 = icmp slt i32 %4, 3 + br i1 %lt6, label %loop.body7, label %loop.exit10 + +loop.body7: ; preds = %loop.cond5 + %5 = load i32, i32* %i4, align 4 + %add8 = add i32 %0, %5 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i32 0, i32 0), i32 %add8) + %6 = load i32, i32* %i4, align 4 + %add9 = add i32 %6, 1 + store i32 %add9, i32* %i4, align 4 + br label %loop.cond5 + +loop.exit10: ; preds = %loop.cond5 + ret void + +if.exit11: ; preds = %if.exit + store i32 0, i32* %i12, align 4 + br label %loop.cond13 + +loop.cond13: ; preds = %loop.body15, %if.exit11 + %7 = load i32, i32* %i12, align 4 + %lt14 = icmp slt i32 %7, 3 + br i1 %lt14, label %loop.body15, label %loop.exit18 + +loop.body15: ; preds = %loop.cond13 + %8 = load i32, i32* %i12, align 4 + %add16 = add i32 %0, %8 + call void (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.3, i32 0, i32 0), i32 %add16) + %9 = load i32, i32* %i12, align 4 + %add17 = add i32 %9, 1 + store i32 %add17, i32* %i12, align 4 + br label %loop.cond13 + +loop.exit18: ; preds = %loop.cond13 + ret void +} + diff --git a/test/test_suite/statements/if_tests.c3t b/test/test_suite/statements/if_tests.c3t index 2ff7a0b03..823c81db3 100644 --- a/test/test_suite/statements/if_tests.c3t +++ b/test/test_suite/statements/if_tests.c3t @@ -40,12 +40,9 @@ if.then: ; preds = %entry %2 = load i32, i32* %x, align 4 %add = add i32 %2, 1 store i32 %add, i32* %x, align 4 - br label %exit - -exit: ; preds = %if.then br label %if.exit -if.exit: ; preds = %exit, %entry +if.exit: ; preds = %if.then, %entry ret void } diff --git a/test/test_suite/statements/label_errors.c3 b/test/test_suite/statements/label_errors.c3 index 61b579f3b..b02854bea 100644 --- a/test/test_suite/statements/label_errors.c3 +++ b/test/test_suite/statements/label_errors.c3 @@ -7,7 +7,7 @@ fn int main() { return 1; } - } + }; return 0; } @@ -20,5 +20,5 @@ fn void test1() { break BAR; // #error: Cannot find a labelled statement with the name 'BAR' } - } + }; } \ No newline at end of file diff --git a/test/test_suite/symbols/various.c3 b/test/test_suite/symbols/various.c3 index 412b6e473..0fc59b0b2 100644 --- a/test/test_suite/symbols/various.c3 +++ b/test/test_suite/symbols/various.c3 @@ -185,15 +185,5 @@ fn void test24() int a = b123; // #error: 'int[2][3]' into 'int' } -fn void test25() -{ - const A = void; // #error: Constants cannot be undefined. -} - -fn void test26() -{ - const int A = void; // #error: Constants cannot be undefined. -} -