diff --git a/core/mem/allocators.odin b/core/mem/allocators.odin index 362fb6182..805f5728d 100644 --- a/core/mem/allocators.odin +++ b/core/mem/allocators.odin @@ -280,7 +280,6 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, if !(start <= curr_addr && curr_addr < end) { panic("Out of bounds memory address passed to stack allocator (free)"); - return nil; } if curr_addr >= start+uintptr(s.curr_offset) { @@ -293,7 +292,6 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, if old_offset != int(header.prev_offset) { panic("Out of order stack allocator free"); - return nil; } s.curr_offset = int(old_offset); @@ -317,7 +315,6 @@ stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, curr_addr := uintptr(old_memory); if !(start <= curr_addr && curr_addr < end) { panic("Out of bounds memory address passed to stack allocator (resize)"); - return nil; } if curr_addr >= start+uintptr(s.curr_offset) { @@ -426,7 +423,6 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, if !(start <= curr_addr && curr_addr < end) { panic("Out of bounds memory address passed to stack allocator (free)"); - return nil; } if curr_addr >= start+uintptr(s.offset) { @@ -455,7 +451,6 @@ small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, curr_addr := uintptr(old_memory); if !(start <= curr_addr && curr_addr < end) { panic("Out of bounds memory address passed to stack allocator (resize)"); - return nil; } if curr_addr >= start+uintptr(s.offset) { @@ -511,11 +506,10 @@ dynamic_pool_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode case .Alloc: return dynamic_pool_alloc(pool, size); case .Free: - panic("Allocator_Mode.Free is not supported for a pool"); + // case .Free_All: dynamic_pool_free_all(pool); case .Resize: - panic("Allocator_Mode.Resize is not supported for a pool"); if old_size >= size { return old_memory; } diff --git a/core/sync/atomic.odin b/core/sync/atomic.odin index ba324e96d..3895ac04b 100644 --- a/core/sync/atomic.odin +++ b/core/sync/atomic.odin @@ -53,7 +53,6 @@ atomic_load :: inline proc(dst: ^$T, $order: Ordering) -> T { case .Acquire_Release: panic("there is no such thing as an acquire/release load"); } panic("unknown order"); - return T{}; } atomic_swap :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -65,7 +64,6 @@ atomic_swap :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_xchg(dst, val); } panic("unknown order"); - return T{}; } atomic_compare_exchange :: inline proc(dst: ^$T, old, new: T, $success, $failure: Ordering) -> (val: T, ok: bool) { @@ -146,7 +144,6 @@ atomic_add :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_add(dst, val); } panic("unknown order"); - return T{}; } atomic_sub :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -158,7 +155,6 @@ atomic_sub :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_sub(dst, val); } panic("unknown order"); - return T{}; } atomic_and :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -170,7 +166,6 @@ atomic_and :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_and(dst, val); } panic("unknown order"); - return T{}; } atomic_nand :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -182,7 +177,6 @@ atomic_nand :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_nand(dst, val); } panic("unknown order"); - return T{}; } atomic_or :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -194,7 +188,6 @@ atomic_or :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_or(dst, val); } panic("unknown order"); - return T{}; } atomic_xor :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { @@ -206,6 +199,5 @@ atomic_xor :: inline proc(dst: ^$T, val: T, $order: Ordering) -> T { case .Sequentially_Consistent: return intrinsics.atomic_xor(dst, val); } panic("unknown order"); - return T{}; } diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 5b343c5cb..88e7be316 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1,4 +1,3 @@ -bool check_is_terminating(Ast *node); void check_stmt (CheckerContext *ctx, Ast *node, u32 flags); // NOTE(bill): 'content_name' is for debugging and error messages @@ -1257,7 +1256,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls); if (type->Proc.result_count > 0) { - if (!check_is_terminating(body)) { + if (!check_is_terminating(body, str_lit(""))) { if (token.kind == Token_Ident) { error(bs->close, "Missing return statement at the end of the procedure '%.*s'", LIT(token.string)); } else { diff --git a/src/check_expr.cpp b/src/check_expr.cpp index acfa40b78..21487c231 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -70,8 +70,8 @@ void check_entity_decl (CheckerContext *c, Entity *e, DeclInfo void check_const_decl (CheckerContext *c, Entity *e, Ast *type_expr, Ast *init_expr, Type *named_type); void check_proc_body (CheckerContext *c, Token token, DeclInfo *decl, Type *type, Ast *body); void update_expr_type (CheckerContext *c, Ast *e, Type *type, bool final); -bool check_is_terminating (Ast *node); -bool check_has_break (Ast *stmt, bool implicit); +bool check_is_terminating (Ast *node, String const &label); +bool check_has_break (Ast *stmt, String const &label, bool implicit); void check_stmt (CheckerContext *c, Ast *node, u32 flags); void check_stmt_list (CheckerContext *c, Array const &stmts, u32 flags); void check_init_constant (CheckerContext *c, Entity *e, Operand *operand); diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index e357d366d..bfca0ae8e 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -1,3 +1,16 @@ +bool is_divigering_stmt(Ast *stmt) { + if (stmt->kind != Ast_ExprStmt) { + return false; + } + Ast *expr = unparen_expr(stmt->ExprStmt.expr); + if (expr->kind != Ast_CallExpr) { + return false; + } + Type *t = type_of_expr(expr->CallExpr.proc); + t = base_type(t); + return t->kind == Type_Proc && t->Proc.diverging; +} + void check_stmt_list(CheckerContext *ctx, Array const &stmts, u32 flags) { if (stmts.count == 0) { return; @@ -39,6 +52,8 @@ void check_stmt_list(CheckerContext *ctx, Array const &stmts, u32 flags) new_flags |= Stmt_FallthroughAllowed; } + check_stmt(ctx, n, new_flags); + if (i+1 < max_non_constant_declaration) { switch (n->kind) { case Ast_ReturnStmt: @@ -48,14 +63,18 @@ void check_stmt_list(CheckerContext *ctx, Array const &stmts, u32 flags) case Ast_BranchStmt: error(n, "Statements after this '%.*s' are never executed", LIT(n->BranchStmt.token.string)); break; + + case Ast_ExprStmt: + if (is_divigering_stmt(n)) { + error(n, "Statements after a non-diverging procedure call are never executed"); + } + break; } } - - check_stmt(ctx, n, new_flags); } } -bool check_is_terminating_list(Array const &stmts) { +bool check_is_terminating_list(Array const &stmts, String const &label) { // Iterate backwards for (isize n = stmts.count-1; n >= 0; n--) { Ast *stmt = stmts[n]; @@ -63,18 +82,20 @@ bool check_is_terminating_list(Array const &stmts) { // Okay } else if (stmt->kind == Ast_ValueDecl && !stmt->ValueDecl.is_mutable) { // Okay + } else if (is_divigering_stmt(stmt)) { + return true; } else { - return check_is_terminating(stmt); + return check_is_terminating(stmt, label); } } return false; } -bool check_has_break_list(Array const &stmts, bool implicit) { +bool check_has_break_list(Array const &stmts, String const &label, bool implicit) { for_array(i, stmts) { Ast *stmt = stmts[i]; - if (check_has_break(stmt, implicit)) { + if (check_has_break(stmt, label, implicit)) { return true; } } @@ -82,25 +103,56 @@ bool check_has_break_list(Array const &stmts, bool implicit) { } -bool check_has_break(Ast *stmt, bool implicit) { +bool check_has_break(Ast *stmt, String const &label, bool implicit) { switch (stmt->kind) { case Ast_BranchStmt: if (stmt->BranchStmt.token.kind == Token_break) { - return implicit; + if (stmt->BranchStmt.label == nullptr) { + return implicit; + } + if (stmt->BranchStmt.label->kind == Ast_Ident && + stmt->BranchStmt.label->Ident.token.string == label) { + return true; + } } break; + case Ast_BlockStmt: - return check_has_break_list(stmt->BlockStmt.stmts, implicit); + return check_has_break_list(stmt->BlockStmt.stmts, label, implicit); case Ast_IfStmt: - if (check_has_break(stmt->IfStmt.body, implicit) || - (stmt->IfStmt.else_stmt != nullptr && check_has_break(stmt->IfStmt.else_stmt, implicit))) { + if (check_has_break(stmt->IfStmt.body, label, implicit) || + (stmt->IfStmt.else_stmt != nullptr && check_has_break(stmt->IfStmt.else_stmt, label, implicit))) { return true; } break; case Ast_CaseClause: - return check_has_break_list(stmt->CaseClause.stmts, implicit); + return check_has_break_list(stmt->CaseClause.stmts, label, implicit); + + case Ast_SwitchStmt: + if (label != "" && check_has_break(stmt->SwitchStmt.body, label, false)) { + return true; + } + break; + + case Ast_TypeSwitchStmt: + if (label != "" && check_has_break(stmt->TypeSwitchStmt.body, label, false)) { + return true; + } + break; + + case Ast_ForStmt: + if (label != "" && check_has_break(stmt->ForStmt.body, label, false)) { + return true; + } + break; + + case Ast_RangeStmt: + if (label != "" && check_has_break(stmt->RangeStmt.body, label, false)) { + return true; + } + break; } return false; @@ -110,41 +162,42 @@ bool check_has_break(Ast *stmt, bool implicit) { // NOTE(bill): The last expression has to be a 'return' statement // TODO(bill): This is a mild hack and should be probably handled properly -bool check_is_terminating(Ast *node) { +bool check_is_terminating(Ast *node, String const &label) { switch (node->kind) { case_ast_node(rs, ReturnStmt, node); return true; case_end; case_ast_node(bs, BlockStmt, node); - return check_is_terminating_list(bs->stmts); + return check_is_terminating_list(bs->stmts, label); case_end; case_ast_node(es, ExprStmt, node); - return check_is_terminating(es->expr); + return check_is_terminating(es->expr, label); case_end; case_ast_node(is, IfStmt, node); if (is->else_stmt != nullptr) { - if (check_is_terminating(is->body) && - check_is_terminating(is->else_stmt)) { + if (check_is_terminating(is->body, label) && + check_is_terminating(is->else_stmt, label)) { return true; } } case_end; case_ast_node(ws, WhenStmt, node); + // TODO(bill): Is this logic correct for when statements? if (ws->else_stmt != nullptr) { - if (check_is_terminating(ws->body) && - check_is_terminating(ws->else_stmt)) { + if (check_is_terminating(ws->body, label) && + check_is_terminating(ws->else_stmt, label)) { return true; } } case_end; case_ast_node(fs, ForStmt, node); - if (fs->cond == nullptr && !check_has_break(fs->body, true)) { - return check_is_terminating(fs->body); + if (fs->cond == nullptr && !check_has_break(fs->body, label, true)) { + return true; } case_end; @@ -164,8 +217,8 @@ bool check_is_terminating(Ast *node) { if (cc->list.count == 0) { has_default = true; } - if (!check_is_terminating_list(cc->stmts) || - check_has_break_list(cc->stmts, true)) { + if (!check_is_terminating_list(cc->stmts, label) || + check_has_break_list(cc->stmts, label, true)) { return false; } } @@ -180,8 +233,8 @@ bool check_is_terminating(Ast *node) { if (cc->list.count == 0) { has_default = true; } - if (!check_is_terminating_list(cc->stmts) || - check_has_break_list(cc->stmts, true)) { + if (!check_is_terminating_list(cc->stmts, label) || + check_has_break_list(cc->stmts, label, true)) { return false; } } diff --git a/src/ir.cpp b/src/ir.cpp index 381c24459..04623f65f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3173,6 +3173,10 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, Array const &ar } } + defer (if (pt->Proc.diverging) { + ir_emit_unreachable(p); + }); + irValue *context_ptr = nullptr; if (pt->Proc.calling_convention == ProcCC_Odin) { context_ptr = ir_find_or_generate_context_ptr(p); diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp index 147afcf46..814f79b1b 100644 --- a/src/llvm_backend.cpp +++ b/src/llvm_backend.cpp @@ -6902,6 +6902,10 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array const &args, context_ptr = lb_find_or_generate_context_ptr(p); } + defer (if (pt->Proc.diverging) { + LLVMBuildUnreachable(p->builder); + }); + set_procedure_abi_types(heap_allocator(), pt); bool is_c_vararg = pt->Proc.c_vararg;