aboutsummaryrefslogtreecommitdiff
path: root/src/check_stmt.cpp
diff options
context:
space:
mode:
authorBenoit Jacquier <benoit.jacquier@gmail.com>2022-08-27 16:22:37 +0200
committerBenoit Jacquier <benoit.jacquier@gmail.com>2022-08-27 16:22:37 +0200
commit4e5337412a4e46fb26250f8adf1d019ddd8366c7 (patch)
treea49c22bd4c894a26ddf8da92c10894fb8e03383f /src/check_stmt.cpp
parent00f2e911a73e99b1283306272ff433984d90486c (diff)
parentc82d7d3d87c2dc77ce942b1cc450734baca3da14 (diff)
Merge remote-tracking branch 'origin/master'
Diffstat (limited to 'src/check_stmt.cpp')
-rw-r--r--src/check_stmt.cpp59
1 files changed, 54 insertions, 5 deletions
diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp
index a6f6f1a7d..d741ceabf 100644
--- a/src/check_stmt.cpp
+++ b/src/check_stmt.cpp
@@ -1,8 +1,5 @@
-bool is_diverging_stmt(Ast *stmt) {
- if (stmt->kind != Ast_ExprStmt) {
- return false;
- }
- Ast *expr = unparen_expr(stmt->ExprStmt.expr);
+bool is_diverging_expr(Ast *expr) {
+ expr = unparen_expr(expr);
if (expr->kind != Ast_CallExpr) {
return false;
}
@@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) {
t = base_type(t);
return t != nullptr && t->kind == Type_Proc && t->Proc.diverging;
}
+bool is_diverging_stmt(Ast *stmt) {
+ if (stmt->kind != Ast_ExprStmt) {
+ return false;
+ }
+ return is_diverging_expr(stmt->ExprStmt.expr);
+}
bool contains_deferred_call(Ast *node) {
if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
@@ -1393,6 +1396,23 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) {
return id != BuiltinProc_Invalid;
}
+bool check_expr_is_stack_variable(Ast *expr) {
+ expr = unparen_expr(expr);
+ Entity *e = entity_of_node(expr);
+ if (e && e->kind == Entity_Variable) {
+ if (e->flags & (EntityFlag_Static|EntityFlag_Using)) {
+ // okay
+ } else if (e->Variable.thread_local_model.len != 0) {
+ // okay
+ } else if (e->scope) {
+ if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Type)) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -1444,6 +1464,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
AstSelectorCallExpr *se = &expr->SelectorCallExpr;
ast_node(ce, CallExpr, se->call);
Type *t = base_type(type_of_expr(ce->proc));
+ if (t == nullptr) {
+ gbString expr_str = expr_to_string(ce->proc);
+ error(node, "'%s' is not a value field nor procedure", expr_str);
+ gb_string_free(expr_str);
+ return;
+ }
if (t->kind == Type_Proc) {
do_require = t->Proc.require_results;
} else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) {
@@ -1675,6 +1701,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (is_type_untyped(o->type)) {
update_untyped_expr_type(ctx, o->expr, e->type, true);
}
+
+
+ // 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
+ Ast *expr = unparen_expr(o->expr);
+ if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
+ Ast *x = unparen_expr(expr->UnaryExpr.expr);
+ if (x->kind == Ast_CompoundLit) {
+ error(expr, "Cannot return the address to a stack value from a procedure");
+ } else if (x->kind == Ast_IndexExpr) {
+ Ast *array = x->IndexExpr.expr;
+ if (is_type_array_like(type_of_expr(array)) && check_expr_is_stack_variable(array)) {
+ gbString t = type_to_string(type_of_expr(array));
+ error(expr, "Cannot return the address to an element of stack variable from a procedure, of type %s", t);
+ gb_string_free(t);
+ }
+ } else {
+ if (check_expr_is_stack_variable(x)) {
+ error(expr, "Cannot return the address to a stack variable from a procedure");
+ }
+ }
+ }
}
}
case_end;