diff options
Diffstat (limited to 'src/check_stmt.cpp')
| -rw-r--r-- | src/check_stmt.cpp | 151 |
1 files changed, 88 insertions, 63 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index ae88ff333..835f0162a 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -484,7 +484,7 @@ gb_internal Type *check_assignment_variable(CheckerContext *ctx, Operand *lhs, O } if (ident_node != nullptr) { ast_node(i, Ident, ident_node); - e = scope_lookup(ctx->scope, i->token.string); + e = scope_lookup(ctx->scope, i->token.string, i->hash); if (e != nullptr && e->kind == Entity_Variable) { used = (e->flags & EntityFlag_Used) != 0; // NOTE(bill): Make backup just in case } @@ -1812,8 +1812,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "Iteration over a bit_set of an enum is not allowed runtime type information (RTTI) has been disallowed"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->BitSet.elem)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1857,8 +1858,9 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) error(node, "#reverse for is not supported for map types, as maps are unordered"); } if (rs->vals.count == 1 && rs->vals[0] && rs->vals[0]->kind == Ast_Ident) { - String name = rs->vals[0]->Ident.token.string; - Entity *found = scope_lookup(ctx->scope, name); + AstIdent *ident = &rs->vals[0]->Ident; + String name = ident->token.string; + Entity *found = scope_lookup(ctx->scope, name, ident->hash); if (found && are_types_identical(found->type, t->Map.key)) { ERROR_BLOCK(); gbString s = expr_to_string(expr); @@ -1963,7 +1965,7 @@ gb_internal void check_range_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) } auto rhs = slice_from_array(vals); - auto lhs = slice_make<Ast *>(temporary_allocator(), rhs.count); + auto lhs = temporary_slice_make<Ast *>(rhs.count); slice_copy(&lhs, rs->vals); isize addressable_index = cast(isize)is_map; @@ -2539,6 +2541,82 @@ gb_internal void check_if_stmt(CheckerContext *ctx, Ast *node, u32 mod_flags) { check_close_scope(ctx); } +// NOTE(bill): This is very basic escape analysis +// This needs to be improved tremendously, and a lot of it done during the +// middle-end (or LLVM side) to improve checks and error messages +void check_unsafe_return(Operand const &o, Type *type, Ast *expr) { + auto const unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { + gbString s = expr_to_string(o.expr); + if (extra_type) { + gbString t = type_to_string(extra_type); + error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); + gb_string_free(t); + } else { + error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); + } + gb_string_free(s); + }; + + if (type == nullptr || expr == nullptr) { + return; + } + + if (expr->kind == Ast_CompoundLit && is_type_slice(type)) { + ast_node(cl, CompoundLit, expr); + if (cl->elems.count == 0) { + return; + } + unsafe_return_error(o, "a compound literal of a slice"); + } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { + Ast *x = unparen_expr(expr->UnaryExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e)) { + unsafe_return_error(o, "the address of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "the address of a compound literal"); + } else if (x->kind == Ast_IndexExpr) { + Entity *f = entity_of_node(x->IndexExpr.expr); + if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { + if (is_entity_local_variable(f)) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (x->kind == Ast_MatrixIndexExpr) { + Entity *f = entity_of_node(x->MatrixIndexExpr.expr); + if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { + unsafe_return_error(o, "the address of an indexed variable", f->type); + } + } + } else if (expr->kind == Ast_SliceExpr) { + Ast *x = unparen_expr(expr->SliceExpr.expr); + Entity *e = entity_of_node(x); + if (is_entity_local_variable(e) && is_type_array(e->type)) { + unsafe_return_error(o, "a slice of a local variable"); + } else if (x->kind == Ast_CompoundLit) { + unsafe_return_error(o, "a slice of a compound literal"); + } + } else if (o.mode == Addressing_Constant && is_type_slice(type)) { + if (is_load_directive_call(o.expr)) { + return; + } + + ERROR_BLOCK(); + unsafe_return_error(o, "a compound literal of a slice"); + error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); + } else if (expr->kind == Ast_CompoundLit) { + ast_node(cl, CompoundLit, expr); + for (Ast *elem : cl->elems) { + if (elem->kind == Ast_FieldValue) { + ast_node(fv, FieldValue, elem); + Entity *e = entity_of_node(fv->field); + if (e != nullptr) { + check_unsafe_return(o, e->type, fv->value); + } + } + } + } +} + gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { ast_node(rs, ReturnStmt, node); @@ -2567,8 +2645,9 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { result_count = proc_type->Proc.results->Tuple.variables.count; } - auto operands = array_make<Operand>(heap_allocator(), 0, 2*rs->results.count); - defer (array_free(&operands)); + TEMPORARY_ALLOCATOR_GUARD(); + + auto operands = array_make<Operand>(temporary_allocator(), 0, 2*rs->results.count); check_unpack_arguments(ctx, result_entities, result_count, &operands, rs->results, UnpackFlag_AllowOk); @@ -2614,61 +2693,7 @@ gb_internal void check_return_stmt(CheckerContext *ctx, Ast *node) { expr = unparen_expr(arg); } - auto unsafe_return_error = [](Operand const &o, char const *msg, Type *extra_type=nullptr) { - gbString s = expr_to_string(o.expr); - if (extra_type) { - gbString t = type_to_string(extra_type); - error(o.expr, "It is unsafe to return %s ('%s') of type ('%s') from a procedure, as it uses the current stack frame's memory", msg, s, t); - gb_string_free(t); - } else { - error(o.expr, "It is unsafe to return %s ('%s') from a procedure, as it uses the current stack frame's memory", msg, s); - } - gb_string_free(s); - }; - - - // NOTE(bill): This is very basic escape analysis - // This needs to be improved tremendously, and a lot of it done during the - // middle-end (or LLVM side) to improve checks and error messages - if (expr->kind == Ast_CompoundLit && is_type_slice(o.type)) { - ast_node(cl, CompoundLit, expr); - if (cl->elems.count == 0) { - continue; - } - unsafe_return_error(o, "a compound literal of a slice"); - } else if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) { - Ast *x = unparen_expr(expr->UnaryExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e)) { - unsafe_return_error(o, "the address of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "the address of a compound literal"); - } else if (x->kind == Ast_IndexExpr) { - Entity *f = entity_of_node(x->IndexExpr.expr); - if (f && (is_type_array_like(f->type) || is_type_matrix(f->type))) { - if (is_entity_local_variable(f)) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (x->kind == Ast_MatrixIndexExpr) { - Entity *f = entity_of_node(x->MatrixIndexExpr.expr); - if (f && (is_type_matrix(f->type) && is_entity_local_variable(f))) { - unsafe_return_error(o, "the address of an indexed variable", f->type); - } - } - } else if (expr->kind == Ast_SliceExpr) { - Ast *x = unparen_expr(expr->SliceExpr.expr); - Entity *e = entity_of_node(x); - if (is_entity_local_variable(e) && is_type_array(e->type)) { - unsafe_return_error(o, "a slice of a local variable"); - } else if (x->kind == Ast_CompoundLit) { - unsafe_return_error(o, "a slice of a compound literal"); - } - } else if (o.mode == Addressing_Constant && is_type_slice(o.type)) { - ERROR_BLOCK(); - unsafe_return_error(o, "a compound literal of a slice"); - error_line("\tNote: A constant slice value will use the memory of the current stack frame\n"); - } + check_unsafe_return(o, o.type, expr); } } |