From a9810c2281a2c4fc2265aa8c59fa9bf101e3a3b5 Mon Sep 17 00:00:00 2001 From: WormHeamer Date: Sun, 10 Aug 2025 05:20:40 -0400 Subject: better error reporting around uninitialized values --- main.c | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index fa00bad..1d35ce9 100644 --- a/main.c +++ b/main.c @@ -32,7 +32,7 @@ void unit_free(Unit *u) { /* parsing */ -Node *parse_expr(Lexer *l, Proc *p); +Node *parse_expr(Lexer *l, Proc *p, Type *twant); /* TODO: eliminate unused if-else statements at the end of compilation * they don't get pruned out by peephole optimizations if there are phi @@ -58,7 +58,7 @@ void parse_return(Lexer *l, Proc *p) { if (p->ret_type.t == T_NONE) { n = node_new(p, N_RETURN, p->ctrl); } else { - Node *e = parse_expr(l, p); + Node *e = parse_expr(l, p, NULL); if (!type_base_eql(&e->type, &p->ret_type)) { lex_error_at(l, e->src_pos, LE_ERROR, str_fmt(&p->arena, "incorrect return type (expected %S, got %S)", @@ -116,7 +116,7 @@ recurse: } if (l->tok == TOK_EQL) { lex_next(l); - rhs = parse_expr(l, p); + rhs = parse_expr(l, p, t.t == T_NONE ? NULL : &t); if (t.t != T_NONE) type_expected(&t, rhs, l); } NameBinding *b = scope_bind(&p->scope, name, rhs, pos, p); @@ -154,7 +154,7 @@ void parse_assign(Lexer *l, Proc *p) { if (!b) { lex_error_at(l, pos, LE_ERROR, S("undeclared identifier")); } - Node *e = parse_expr(l, p); + Node *e = parse_expr(l, p, &b->node->type); if (!type_base_eql(&e->type, &b->node->type)) { lex_error_at(l, pos, LE_ERROR, str_fmt(&p->arena, "tried to assign value of type %S to variable of type %S", @@ -256,7 +256,7 @@ void merge_scope(Lexer *l, Proc *p, Node *region, ScopeNameList *before, ScopeNa void parse_if(Lexer *l, Proc *p) { lex_next(l); - Node *cond = parse_expr(l, p); + Node *cond = parse_expr(l, p, &(Type) { .t = T_BOOL }); Node *ctrl_if = NULL, *ctrl_else = NULL; Node *if_node = node_new(p, N_IF_ELSE, p->ctrl, cond); if_node->val = (Value) { @@ -417,7 +417,7 @@ void proc_opt_fwd(Proc *p, Lexer *l, Node *n) { break; case N_IF_ELSE: if (n->out.len < 2) { - lex_error_at(l, n->src_pos, LE_ERROR, S("not all codepaths return")); + //lex_error_at(l, n->src_pos, LE_ERROR, S("not all codepaths return")); } for (int i = 0; i < n->out.len; i++) { Node *r = find_return(n->out.data[i]); @@ -503,13 +503,26 @@ Proc *parse_proc(Lexer *l, Unit *u) { return proc; } -Node *parse_term(Lexer *l, Proc *p) { +void uninit_check(Lexer *l, Proc *p, Node *n, LexSpan pos) { + if (node_uninit(n)) { + lex_error_at(l, pos, LE_ERROR, + str_fmt(&p->arena, "uninitialized %S", + type_desc(&n->type, &p->arena))); + } else if (node_maybe_uninit(n)) { + lex_error_at(l, pos, LE_WARN, + str_fmt(&p->arena, "possibly uninitialized %S", + type_desc(&n->type, &p->arena))); + } +} + +Node *parse_term(Lexer *l, Proc *p, Type *twant) { + (void)twant; /* to be used for .ENUM_TYPE and stuff */ Node *node = NULL; NodeType op_after = N_START; if (TMASK(l->tok) & (TM_MINUS | TM_PLUS | TM_NOT)) { Token t = l->tok; lex_next(l); - node = parse_term(l, p); + node = parse_term(l, p, twant); NodeType post_op = N_START; switch (t) { case TOK_MINUS: post_op = N_OP_NEG; break; @@ -521,7 +534,7 @@ Node *parse_term(Lexer *l, Proc *p) { } if (l->tok == TOK_LPAREN) { lex_next(l); - node = parse_expr(l, p); + node = parse_expr(l, p, NULL); lex_expected(l, TM_RPAREN); lex_next(l); node->src_pos.ofs--; @@ -533,6 +546,7 @@ Node *parse_term(Lexer *l, Proc *p) { } else { lex_error(l, LE_ERROR, S("undeclared identifier")); } + uninit_check(l, p, node, l->pos); lex_next(l); } else if (TMASK(l->tok) & (TM_TRUE | TM_FALSE)) { node = node_new_lit_bool(p, l->tok == TOK_TRUE); @@ -580,9 +594,9 @@ NodeType tok_to_bin_op(Token t) { } /* TODO: operator precedence would be kinda nice actually, sad to say */ -Node *parse_expr(Lexer *l, Proc *p) { +Node *parse_expr(Lexer *l, Proc *p, Type *twant) { LexSpan pos = l->pos; - Node *lhs = parse_term(l, p); + Node *lhs = parse_term(l, p, twant); NodeType nt = tok_to_bin_op(l->tok);; if (lhs->refs <= 0) lex_error(l, LE_ERROR, S("dead lhs")); assert(lhs->refs > 0); @@ -592,11 +606,12 @@ Node *parse_expr(Lexer *l, Proc *p) { * and therefore culled by peephole optimizations */ Node *rhs; NODE_KEEP(p, lhs, { - rhs = parse_expr(l, p); + rhs = parse_expr(l, p, &lhs->type); }); lhs = node_peephole(node_new(p, nt, NULL, lhs, rhs), p, l); } lhs->src_pos = (LexSpan) { pos.ofs, l->pos.ofs - pos.ofs }; + if (twant) type_expected(twant, lhs, l); return lhs; } -- cgit v1.2.3