diff options
| -rw-r--r-- | c/c.c | 8 | ||||
| -rw-r--r-- | ir/ir.c | 21 | ||||
| -rw-r--r-- | ir/ir.h | 1 |
3 files changed, 28 insertions, 2 deletions
@@ -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); } @@ -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) @@ -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); |