root/tests/usr.bin/xlint/lint1/msg_193.c
/*      $NetBSD: msg_193.c,v 1.23 2026/03/14 20:27:12 rillig Exp $      */
# 3 "msg_193.c"

// Test for message: '%s' statement not reached [193]

/* lint1-extra-flags: -X 351 -h */

/*
 * Test the reachability of statements in a function.
 *
 *      if
 *      if-else
 *      if-else-if-else
 *      for
 *      while
 *      do-while
 *      switch
 *      break
 *      continue
 *      goto
 *      return
 *
 *      constant expression
 *      system-dependent constant expression
 */

extern void reachable(void);
extern void unreachable(void);
extern _Bool maybe(void);


void
test_statement(void)
{
        reachable();
        reachable();
}

void
test_compound_statement(void)
{
        reachable();
        {
                reachable();
                reachable();
        }
        reachable();
}

void
test_if_statement(void)
{
        if (1)
                reachable();
        reachable();
        if (0)
                unreachable();          /* expect+0: ... [193] */
        reachable();
}

void
test_if_compound_statement(void)
{
        if (1) {
                reachable();
        }
        if (1) {
                {
                        {
                                reachable();
                        }
                }
        }

        if (0) {
                unreachable();          /* expect+0: ... [193] */
        }
        if (0) {
                {
                        {
                                unreachable();  /* expect+0: ... [193] */
                        }
                }
        }
}

void
test_if_without_else(void)
{
        if (1)
                reachable();
        reachable();

        if (0)
                unreachable();          /* expect+0: ... [193] */
        reachable();
}

void
test_if_with_else(void)
{
        if (1)
                reachable();
        else
                unreachable();          /* expect+0: ... [193] */
        reachable();

        if (0)
                unreachable();          /* expect+0: ... [193] */
        else
                reachable();
        reachable();
}

void
test_if_else_if_else(void)
{
        if (1)
                reachable();
        else if (1)                     /* expect+0: ... [193] */
                unreachable();
        else
                unreachable();          /* expect+0: ... [193] */

        if (0)
                unreachable();          /* expect+0: ... [193] */
        else if (1)
                reachable();
        else
                unreachable();          /* expect+0: ... [193] */

        if (0)
                unreachable();          /* expect+0: ... [193] */
        else if (0)
                unreachable();          /* expect+0: ... [193] */
        else
                reachable();
}

void
test_if_return(void)
{
        if (1)
                return;
        unreachable();                  /* expect+0: ... [193] */
}

void
test_if_else_return(void)
{
        if (1)
                reachable();
        else
                return;                 /* expect+0: ... [193] */
        reachable();
}

void
test_for_forever(void)
{
        for (;;)
                reachable();
        unreachable();                  /* expect+0: ... [193] */
}

void
test_for_true(void)
{
        for (; 1;)
                reachable();
        unreachable();                  /* expect+0: ... [193] */
}

void
test_for_false(void)
{
        for (; 0;)
                unreachable();          /* expect+0: ... [193] */
        reachable();
}

void
test_for_break(void)
{
        for (;;) {
                reachable();
                break;
                unreachable();          /* expect+0: ... [193] */
        }
        reachable();
}

void
test_for_if_break(void)
{
        for (;;) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        reachable();
}

void
test_for_continue(void)
{
        for (;;) {
                reachable();
                continue;
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_for_if_continue(void)
{
        for (;;) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_for_return(void)
{
        for (;;) {
                reachable();
                return;
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_for_if_return(void)
{
        for (;;) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_while_true(void)
{
        while (1)
                reachable();
        unreachable();                  /* expect+0: ... [193] */
}

void
test_while_false(void)
{
        while (0)
                unreachable();          /* expect+0: ... [193] */
        reachable();
}

void
test_while_break(void)
{
        while (1) {
                reachable();
                break;
                unreachable();          /* expect+0: ... [193] */
        }
        reachable();
}

void
test_while_if_break(void)
{
        while (1) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        reachable();
}

void
test_while_continue(void)
{
        while (1) {
                reachable();
                continue;
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_while_if_continue(void)
{
        while (1) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_while_return(void)
{
        while (1) {
                reachable();
                return;
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_while_if_return(void)
{
        while (1) {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        }
        unreachable();                  /* expect+0: ... [193] */
}

void
test_do_while_true(void)
{
        do {
                reachable();
        } while (1);
        unreachable();                  /* expect+0: ... [193] */
}

void
test_do_while_false(void)
{
        do {
                reachable();
        } while (0);
        reachable();
}

void
test_do_while_break(void)
{
        do {
                reachable();
                break;
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        reachable();
}

void
test_do_while_if_break(void)
{
        do {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        break;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        reachable();
}

void
test_do_while_continue(void)
{
        do {
                reachable();
                continue;
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        unreachable();                  /* expect+0: ... [193] */
}

void
test_do_while_if_continue(void)
{
        do {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        continue;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        unreachable();                  /* expect+0: ... [193] */
}

void
test_do_while_return(void)
{
        do {
                reachable();
                return;
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        unreachable();                  /* expect+0: ... [193] */
}

void
test_do_while_if_return(void)
{
        do {
                reachable();
                if (0) {
                        unreachable();  /* expect+0: ... [193] */
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                if (1) {
                        reachable();
                        return;
                        unreachable();  /* expect+0: ... [193] */
                }
                unreachable();          /* expect+0: ... [193] */
        } while (1);
        unreachable();                  /* expect+0: ... [193] */
}

void
test_if_nested(void)
{
        if (0) {
                if (1)                  /* expect+0: ... [193] */
                        unreachable();
                else
                        unreachable();  /* expect+0: ... [193] *//* XXX: redundant */

                if (0)
                        unreachable();  /* expect+0: ... [193] *//* XXX: redundant */
                else
                        unreachable();

                unreachable();
        }
        reachable();

        if (1) {
                if (1)
                        reachable();
                else
                        unreachable();  /* expect+0: ... [193] */

                if (0)
                        unreachable();  /* expect+0: ... [193] */
                else
                        reachable();

                reachable();
        }
        reachable();
}

void
test_if_maybe(void)
{
        if (maybe()) {
                if (0)
                        unreachable();  /* expect+0: ... [193] */
                else
                        reachable();
                reachable();
        }
        reachable();

        if (0) {
                if (maybe())            /* expect+0: ... [193] */
                        unreachable();
                else
                        unreachable();
                unreachable();
        }
        reachable();

        if (1) {
                if (maybe())
                        reachable();
                else
                        reachable();
                reachable();
        }
        reachable();
}

/*
 * To compute the reachability graph of this little monster, lint would have
 * to keep all statements and their relations from the whole function in
 * memory.  It doesn't do that.  Therefore it does not warn about any
 * unreachable statements in this function.
 */
void
test_goto_numbers_alphabetically(void)
{
        goto one;
eight:
        goto nine;
five:
        return;
four:
        goto five;
nine:
        goto ten;
one:
        goto two;
seven:
        goto eight;
six:
        /* expect-1: warning: label 'six' unused in function 'test_goto_numbers_alphabetically' [232] */
        goto seven;
ten:
        return;
three:
        goto four;
two:
        goto three;
}

void
test_while_goto(void)
{
        while (1) {
                goto out;
                break;          /* lint only warns with the -b option */
        }
        unreachable();          /* expect+0: ... [193] */
out:
        reachable();
}

void
test_unreachable_label(void)
{
        if (0)
                goto unreachable;       /* expect+0: ... [193] */
        goto reachable;

        /* named_label assumes that any label is reachable. */
unreachable:
        unreachable();
reachable:
        reachable();
}

void
test_switch_case_default_break(int x)
{
        switch (x) {
        case 1:
                break;
        default:
                break;
        }
        return;
}

void
test_switch_case_default_return(int x)
{
        switch (x) {
        case 1:
                return;
        default:
                return;
        }
        /* expect+1: warning: 'return' statement not reached [193] */
        return;
}

void
test_switch_default_case_break(int x)
{
        switch (x) {
        default:
                break;
        case 1:
                break;
        }
        return;
}

void
test_switch_default_case_return(int x)
{
        switch (x) {
        default:
                return;
        case 1:
                return;
        }
        /* expect+1: warning: 'return' statement not reached [193] */
        return;
}

void
test_switch_default_return_case_break(int x)
{
        switch (x) {
        default:
                return;
        case 1:
                break;
        }
        return;
}

void
test_switch_default_break_case_return(int x)
{
        switch (x) {
        default:
                break;
        case 1:
                return;
        }
        return;
}

void
test_switch_case_return_default_none(int x)
{
        switch (x) {
        case 1:
                return;
        default:
                ;
        }
        return;
}

void
test_switch_default_none_case_return(int x)
{
        switch (x) {
        default:
                ;
        /* expect+1: warning: fallthrough on case statement [220] */
        case 1:
                return;
        }
        /* expect+1: warning: 'return' statement not reached [193] */
        return;
}

enum minimal_enum {
        CONSTANT
};

void
test_switch_enum_exhaustive(enum minimal_enum x)
{
        switch (x) {
        case CONSTANT:
                return;
        }
        // FIXME: lint assumes that this statement is not reachable, which
        //  is wrong since the variable may contain any other int value.
        /* expect+1: warning: 'return' statement not reached [193] */
        return;
}

/* TODO: system-dependent constant expression (see tn_system_dependent) */

void suppressed(void);

void
lint_annotation_NOTREACHED(void)
{
        if (0) {
                /* expect+1: warning: 'call' statement not reached [193] */
                unreachable();
        }

        if (0) {
                /* NOTREACHED */
                suppressed();
        }

        if (0)
                /* NOTREACHED */
                suppressed();

        if (1) {
                reachable();
        }

        if (1) {
                /* NOTREACHED */
                suppressed();
        }

        /*
         * Since the condition in the 'if' statement is constant, lint knows
         * that the branch is unconditionally taken.  The annotation comment
         * marks that branch as not reached, which means that any following
         * statement cannot be reached as well.
         */
        /* expect+1: warning: 'if' statement not reached [193] */
        if (1)
                /* NOTREACHED */
                suppressed();
}

/*
 * Since at least 2002 and before cgram.y 1.379 from 2022-01-16, lint did not
 * detect a double semicolon.  See cgram.y, expression_statement, T_SEMI.
 */
int
test_null_statement(void)
{
        /*
         * The following 2 semicolons are superfluous but lint doesn't warn
         * about them.  Probably it should.  A null statement as part of a
         * block-list has no use.
         */
        ;;

        /*
         * If assertions are disabled with -DNDEBUG and __lint__ is defined,
         * NetBSD's <assert.h> defines assert(x) to nothing, leaving only
         * the trailing semicolon.  If there are several assertions next to
         * each other, without any whitespace in between (very unusual), the
         * GCC preprocessor generates ";;" for them, which makes them
         * indistinguishable from the literal ";;" from the typo above.
         *
         * (echo '#include <assert.h>'; echo 'assert(0);assert(1);') \
         * | gcc -DNDEBUG -E - -D__lint__
         *
         * To actually see the difference, lint would need to look at the
         * code before preprocessing and compare it with the preprocessed
         * code, which would be a lot of work.
         *
         * Apart from the above edge case, detecting extra semicolons would
         * be possible, but lint would have to look at the whitespace between
         * the tokens, and this is something that it doesn't do at all, as of
         * 2022-01-16.
         */

        /*
         * A stand-alone null statement, on the other hand, has its purpose.
         * Without it, the 'for' loop would not be complete.  The NetBSD
         * style is to use 'continue;' instead of a simple ';'.
         */
        for (int i = 0; i < 10; i++)
                ;

        /* expect+1: warning: 'empty' statement not reached [193] */
        return 0;;
}

/*
 * Before func.c 1.149 from 2023-02-21, lint crashed due to a null pointer
 * dereference.
 */
void
invalid_case_expression(void)
{
        switch (4) {
        /* expect+1: error: operand of '~' has invalid type 'double' [108] */
        case ~0.0:
                ;
        }
}