summaryrefslogtreecommitdiff
path: root/ir.c
diff options
context:
space:
mode:
Diffstat (limited to 'ir.c')
-rw-r--r--ir.c53
1 files changed, 46 insertions, 7 deletions
diff --git a/ir.c b/ir.c
index 125e882..b0b90f5 100644
--- a/ir.c
+++ b/ir.c
@@ -4,8 +4,6 @@
#include "ir.h"
#include "strio.h"
-extern int no_opt;
-
/* nodes */
const char *node_type_name(NodeType t) {
@@ -361,13 +359,54 @@ static int type_ok(Node *n) {
}
}
-void type_check(Node *n, Lexer *l) {
+/* TODO: make it so
+ * func foo(a, b i64) i64 {
+ * let x i64
+ * if a < b {
+ * return 0
+ * } else {
+ * x := 3
+ * }
+ * return x
+ * }
+ * doesn't throw warnings (e.g. don't generate phi nodes if one scope is
+ * guaranteed to return early)
+ */
+
+int node_uninit(Node *n) {
+ return n->op == N_UNINIT;
+}
+
+int node_maybe_uninit(Node *n) {
+ if (node_uninit(n)) return 1;
for (int i = 0; i < n->in.len; i++) {
- if (IN(n,i) && IN(n,i)->op == N_UNINIT) {
- lex_error_at(l, n->src_pos, LE_ERROR,
- str_fmt(&l->arena, "attempt to use uninitialized %S value",
- type_desc(&IN(n,i)->type, &l->arena)));
+ if (IN(n,i) && node_maybe_uninit(IN(n,i))) {
+ return 1;
}
}
+ return 0;
+}
+
+void uninit_check(Node *n, Lexer *l) {
+ if (NMASK(n->op) & ~NM_PHI) {
+ for (int i = 0; i < n->in.len; i++) {
+ Node *o = IN(n, i);
+ if (!o) continue;
+ if (node_uninit(o)) {
+ fprintf(stderr, "%s\n", node_type_name(n->op));
+ lex_error_at(l, o->src_pos, LE_WARN,
+ str_fmt(&l->arena, "uninitialized %S",
+ type_desc(&IN(n,i)->type, &l->arena)));
+ } else if (node_maybe_uninit(o)) {
+ lex_error_at(l, o->src_pos, LE_WARN,
+ str_fmt(&l->arena, "possibly uninitialized %S",
+ type_desc(&o->type, &l->arena)));
+ }
+ }
+ }
+}
+
+void type_check(Node *n, Lexer *l) {
+ uninit_check(n, l);
if (!type_ok(n)) type_err(n, l);
}