root/tests/usr.bin/xlint/lint1/msg_129.c
/*      $NetBSD: msg_129.c,v 1.11 2025/09/17 19:25:23 rillig Exp $      */
# 3 "msg_129.c"

// Test for message: expression has null effect [129]

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

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

_Bool side_effect(void);

/*
 * Before tree.c 1.198 from 2021-01-30, the nested comma operators were
 * wrongly reported as having no side effect.
 *
 * The bug was that has_side_effect did not properly examine the sub-nodes.
 * The ',' operator itself has m_has_side_effect == false since it depends
 * on its operands whether the ',' actually has side effects.  For nested ','
 * operators, the function did not evaluate the operands deeply but only did
 * a quick shallow test on the m_has_side_effect property.  Since that is
 * false, lint thought that the whole expression would have no side effect.
 */
void
uint8_buffer_write_uint32(uint8_t *c, uint32_t l)
{
        (*(c++) = (uint8_t)(l & 0xff),
            *(c++) = (uint8_t)((l >> 8L) & 0xff),
            *(c++) = (uint8_t)((l >> 16L) & 0xff),
            *(c++) = (uint8_t)((l >> 24L) & 0xff));
}

void
operator_and(_Bool cond)
{
        cond && side_effect();
        // ... is an abbreviation for ...
        if (cond)
                side_effect();
        // This pattern is much more common in shell or Perl than in C.

        /* expect+1: warning: expression has null effect [129] */
        side_effect() && cond;
}

void
operator_or(_Bool cond)
{
        cond || side_effect();
        // ... is an abbreviation for ...
        if (!cond)
                side_effect();
        // This pattern is much more common in shell or Perl than in C.

        /* expect+1: warning: expression has null effect [129] */
        side_effect() || cond;
}

void
operator_quest_colon(void)
{
        side_effect() ? side_effect() : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        side_effect() ? side_effect() : 0;

        /* expect+1: warning: expression has null effect [129] */
        side_effect() ? 0 : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        side_effect() ? 0 : 1;

        0 ? side_effect() : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        0 ? side_effect() : 0;

        /* expect+1: warning: expression has null effect [129] */
        0 ? 0 : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        0 ? 0 : 1;

        1 ? side_effect() : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        1 ? side_effect() : 0;

        /* expect+1: warning: expression has null effect [129] */
        1 ? 0 : side_effect();

        /* expect+1: warning: expression has null effect [129] */
        1 ? 1 : 0;

        0 ? (void)1 : (void)0;
}

void
operator_comma(void)
{
        side_effect(), 0;               /* the 0 is redundant */
        /* expect+1: warning: expression has null effect [129] */
        0, side_effect();

        if (side_effect(), 0)           /* the 0 controls the 'if' */
                return;
        /* expect+1: warning: expression has null effect [129] */
        if (0, side_effect())
                return;
}

void
legitimate_use_cases(int arg)
{
        int local = 3;

        /*
         * This expression is commonly used to mark the parameter as
         * deliberately unused.
         */
        (void)arg;

        /*
         * This expression is commonly used to mark the local variable as
         * deliberately unused.  This situation occurs when the local
         * variable is only used in some but not all compile-time selectable
         * variants of the code, such as in debugging mode, and writing down
         * the exact conditions would complicate the code unnecessarily.
         */
        (void)local;

        /* This is a shorthand notation for a do-nothing command. */
        (void)0;

        /*
         * At the point where lint checks for expressions having a null
         * effect, constants have been folded, therefore the following
         * expression is considered safe as well.  It does not appear in
         * practice though.
         */
        (void)(3 - 3);

        /*
         * This variant of the do-nothing command is commonly used in
         * preprocessor macros since it works nicely with if-else and if-then
         * statements.  It is longer than the above variant, and it is not
         * embeddable into an expression.
         */
        do {
        } while (0);

        /*
         * Only the expression '(void)0' is common, other expressions are
         * unusual enough to warrant a warning.
         */
        /* expect+1: warning: expression has null effect [129] */
        (void)13;

        /* Double casts are unusual enough to warrant a warning. */
        /* expect+1: warning: expression has null effect [129] */
        (void)(void)0;
}

int
return_statement_expression(int arg)
{
        ({
                int local = arg;
                local + 4;
        /* expect+1: warning: expression has null effect [129] */
        });

        if (arg == 1)
                return ({
                        int local = arg;
                        // Before cgram.y 1.513 from 2024-10-29, lint wrongly
                        // warned that this expression would have a null effect.
                        local;
                });

        if (arg == 2)
                return ({
                        int local = arg;
                        // Before cgram.y 1.513 from 2024-10-29, lint wrongly
                        // warned that this expression would have a null effect.
                        local + 4;
                });

        return 0;
}