+ case STATEMENT_DO_WHILE:
+ next = stmt->do_while.body;
+ break;
+
+ case STATEMENT_FOR: {
+ for_statement_t *const fors = &stmt->fors;
+
+ if (fors->condition_reachable)
+ return;
+ fors->condition_reachable = true;
+
+ expression_t const *const cond = fors->condition;
+ int const val =
+ cond == NULL ? 1 : determine_truth(cond);
+
+ if (val >= 0)
+ check_reachable(fors->body);
+
+ if (val > 0)
+ return;
+
+ next = stmt->base.next;
+ break;
+ }
+
+ case STATEMENT_MS_TRY:
+ case STATEMENT_LEAVE:
+ panic("unimplemented");
+ }
+
+ while (next == NULL) {
+ next = last->base.parent;
+ if (next == NULL) {
+ noreturn_candidate = false;
+
+ type_t *const type = current_function->type;
+ assert(is_type_function(type));
+ type_t *const ret = skip_typeref(type->function.return_type);
+ if (warning.return_type &&
+ !is_type_atomic(ret, ATOMIC_TYPE_VOID) &&
+ is_type_valid(ret) &&
+ !is_sym_main(current_function->symbol)) {
+ warningf(&stmt->base.source_position,
+ "control reaches end of non-void function");
+ }
+ return;
+ }
+
+ switch (next->kind) {
+ case STATEMENT_INVALID:
+ case STATEMENT_EMPTY:
+ case STATEMENT_DECLARATION:
+ case STATEMENT_EXPRESSION:
+ case STATEMENT_ASM:
+ case STATEMENT_RETURN:
+ case STATEMENT_CONTINUE:
+ case STATEMENT_BREAK:
+ case STATEMENT_GOTO:
+ case STATEMENT_LEAVE:
+ panic("invalid control flow in function");
+
+ case STATEMENT_COMPOUND:
+ case STATEMENT_IF:
+ case STATEMENT_SWITCH:
+ case STATEMENT_LABEL:
+ case STATEMENT_CASE_LABEL:
+ last = next;
+ next = next->base.next;
+ break;
+
+ case STATEMENT_WHILE: {
+continue_while:
+ if (next->base.reachable)
+ return;
+ next->base.reachable = true;
+
+ while_statement_t const *const whiles = &next->whiles;
+ int const val = determine_truth(whiles->condition);
+
+ if (val >= 0)
+ check_reachable(whiles->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_DO_WHILE: {
+continue_do_while:
+ if (next->base.reachable)
+ return;
+ next->base.reachable = true;
+
+ do_while_statement_t const *const dw = &next->do_while;
+ int const val = determine_truth(dw->condition);
+
+ if (val >= 0)
+ check_reachable(dw->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_FOR: {
+continue_for:;
+ for_statement_t *const fors = &next->fors;
+
+ fors->step_reachable = true;
+
+ if (fors->condition_reachable)
+ return;
+ fors->condition_reachable = true;
+
+ expression_t const *const cond = fors->condition;
+ int const val =
+ cond == NULL ? 1 : determine_truth(cond);
+
+ if (val >= 0)
+ check_reachable(fors->body);
+
+ if (val > 0)
+ return;
+
+ last = next;
+ next = next->base.next;
+ break;
+ }
+
+ case STATEMENT_MS_TRY:
+ panic("unimplemented");
+ }
+ }
+
+ if (next == NULL) {
+ next = stmt->base.parent;
+ if (next == NULL) {
+ warningf(&stmt->base.source_position,
+ "control reaches end of non-void function");
+ }
+ }
+
+ check_reachable(next);
+}
+
+static void check_unreachable(statement_t const* const stmt)
+{
+ if (!stmt->base.reachable &&
+ stmt->kind != STATEMENT_COMPOUND &&
+ stmt->kind != STATEMENT_DO_WHILE &&
+ stmt->kind != STATEMENT_FOR) {
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ }
+
+ switch (stmt->kind) {
+ case STATEMENT_INVALID:
+ case STATEMENT_EMPTY:
+ case STATEMENT_RETURN:
+ case STATEMENT_DECLARATION:
+ case STATEMENT_EXPRESSION:
+ case STATEMENT_CONTINUE:
+ case STATEMENT_BREAK:
+ case STATEMENT_GOTO:
+ case STATEMENT_ASM:
+ case STATEMENT_LEAVE:
+ break;
+
+ case STATEMENT_COMPOUND:
+ if (stmt->compound.statements)
+ check_unreachable(stmt->compound.statements);
+ break;
+
+ case STATEMENT_IF:
+ check_unreachable(stmt->ifs.true_statement);
+ if (stmt->ifs.false_statement != NULL)
+ check_unreachable(stmt->ifs.false_statement);
+ break;
+
+ case STATEMENT_SWITCH:
+ check_unreachable(stmt->switchs.body);
+ break;
+
+ case STATEMENT_LABEL:
+ check_unreachable(stmt->label.statement);
+ break;
+
+ case STATEMENT_CASE_LABEL:
+ check_unreachable(stmt->case_label.statement);
+ break;
+
+ case STATEMENT_WHILE:
+ check_unreachable(stmt->whiles.body);
+ break;
+
+ case STATEMENT_DO_WHILE:
+ check_unreachable(stmt->do_while.body);
+ if (!stmt->base.reachable) {
+ expression_t const *const cond = stmt->do_while.condition;
+ if (determine_truth(cond) >= 0) {
+ warningf(&cond->base.source_position,
+ "condition of do-while-loop is unreachable");
+ }
+ }
+ break;
+
+ case STATEMENT_FOR: {
+ for_statement_t const* const fors = &stmt->fors;
+
+ // if init and step are unreachable, cond is unreachable, too
+ if (!stmt->base.reachable && !fors->step_reachable) {
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ } else {
+ if (!stmt->base.reachable && fors->initialisation != NULL) {
+ warningf(&fors->initialisation->base.source_position,
+ "initialisation of for-statement is unreachable");
+ }
+
+ if (!fors->condition_reachable && fors->condition != NULL) {
+ warningf(&fors->condition->base.source_position,
+ "condition of for-statement is unreachable");
+ }
+
+ if (!fors->step_reachable && fors->step != NULL) {
+ warningf(&fors->step->base.source_position,
+ "step of for-statement is unreachable");
+ }
+ }
+
+ check_unreachable(stmt->fors.body);
+ break;
+ }
+
+ case STATEMENT_MS_TRY:
+ panic("unimplemented");
+ }
+
+ if (stmt->base.next)
+ check_unreachable(stmt->base.next);
+}
+
+static void parse_external_declaration(void)
+{
+ /* function-definitions and declarations both start with declaration
+ * specifiers */
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+
+ add_anchor_token(';');
+ parse_declaration_specifiers(&specifiers);
+ rem_anchor_token(';');
+
+ /* must be a declaration */
+ if (token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, append_declaration);
+ return;
+ }
+
+ add_anchor_token(',');
+ add_anchor_token('=');
+ rem_anchor_token(';');
+
+ /* declarator is common to both function-definitions and declarations */
+ declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
+
+ rem_anchor_token(',');
+ rem_anchor_token('=');
+ rem_anchor_token(';');
+
+ /* must be a declaration */
+ switch (token.type) {
+ case ',':
+ case ';':
+ parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
+ return;
+
+ case '=':
+ parse_declaration_rest(ndeclaration, &specifiers, record_definition);
+ return;
+ }
+
+ /* must be a function definition */
+ parse_kr_declaration_list(ndeclaration);
+
+ if (token.type != '{') {