aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-11-23 19:38:38 +0100
committerlemon <lsof@mailbox.org>2025-11-23 19:38:38 +0100
commit0b77ae0eda8d3abca659f816040021a82a456e81 (patch)
treede72d56c0d0f3efb88faba88129d7825973bace8
parenta86bbfc553433e377e48f9e26c90bcc5b4fe0263 (diff)
c: check actual reachability for non-void func may not return value
-rw-r--r--c/c.c8
-rw-r--r--ir/ir.c21
-rw-r--r--ir/ir.h1
3 files changed, 28 insertions, 2 deletions
diff --git a/c/c.c b/c/c.c
index c2c0537..d609cd0 100644
--- a/c/c.c
+++ b/c/c.c
@@ -4201,11 +4201,15 @@ function(struct comp *cm, struct function *fn, const char **pnames, const struct
}
if (fn->curblk) {
if (!strcmp(fn->name, "main") && fn->retty.t == TYINT) {
- /* implicit return 0 for main function */
+ /* implicit return 0 for main function (ISO C standard behavior) */
putreturn(fn, ZEROREF, NOREF);
} else {
if (fn->retty.t != TYVOID && !nerror) {
- warn(&cm->fnblkspan, "non-void function may not return a value");
+ /* it may not actually be reachable after constant-folding
+ * peephole optimizations (from code like assert(0 && "x")) */
+ if (blkreachable(fn, fn->curblk)) {
+ warn(&cm->fnblkspan, "non-void function may not return a value");
+ }
}
putreturn(fn, NOREF, NOREF);
}
diff --git a/ir/ir.c b/ir/ir.c
index 412d0f9..4a092b3 100644
--- a/ir/ir.c
+++ b/ir/ir.c
@@ -451,6 +451,27 @@ numberinstrs(struct function *fn)
} while ((blk = blk->lnext) != fn->entry);
}
+static bool
+reachablerec(struct function *fn, struct block *blk)
+{
+ if (blk == fn->entry) return 1;
+ markvisited(blk);
+ if (blk->npred == 1 && !wasvisited(blkpred(blk, 0)))
+ return reachablerec(fn, blkpred(blk, 0));
+ else for (int i = 0; i < blk->npred; ++i) {
+ struct block *p = blkpred(blk, i);
+ if (!wasvisited(p) && reachablerec(fn, p)) return 1;
+ }
+ return 0;
+}
+
+bool
+blkreachable(struct function *fn, struct block *blk)
+{
+ startbbvisit();
+ return reachablerec(fn, blk);
+}
+
/* require use */
void
replcuses(union ref from, union ref to)
diff --git a/ir/ir.h b/ir/ir.h
index 77f25d4..9047233 100644
--- a/ir/ir.h
+++ b/ir/ir.h
@@ -277,6 +277,7 @@ void fillblkids(struct function *);
#define wasvisited(blk) ((blk)->visit == visitmark)
#define markvisited(blk) ((blk)->visit = visitmark)
void numberinstrs(struct function *);
+bool blkreachable(struct function *fn, struct block *blk);
/** builder.c **/
union ref irbinop(struct function *, enum op, enum irclass, union ref lhs, union ref rhs);