Rule A6-5-3 (advisory, implementation, automated)

Do statements should not be used.

Rationale

Do-statements are bug-prone, as the termination condition is checked at the end and can be overlooked.

Exception

A do-statement may be used in a function-like macro to ensure that its invocation behaves like an expression statement consisting of a function call (see http://cfaq.com/cpp/multistmt.html). Note: Rule A16-0-1 forbids function-like macros. This exception is kept in case rule A16-0-1 is disabled in a project.

Example

// $Id: A6-5-3.cpp 291350 2017-10-17 14:31:34Z jan.babst $

#include <cstdint>

// Compliant by exception
#define SWAP(a, b)         \
do                         \
{                          \
    decltype(a) tmp = (a); \
    (a) = (b);             \
    (b) = tmp;             \
} while (0)

// Non-compliant
#define SWAP2(a, b)    \
decltype(a) tmp = (a); \
(a) = (b);             \
(b) = tmp;             \

int main(void)
{
    uint8_t a = 24;
    uint8_t b = 12;

    if (a > 12)
        SWAP(a, b);

    // if (a > 12)
    //SWAP2(a, b);
    // Does not compile, because only the first line is used in the body of the
    // if-statement. In other cases this may even cause a run-time error.
    // The expansion contain two semicolons in a row, which may be flagged by
    // compiler warnings.

    // Expands to:
    // if (a > 12)
    //decltype(a) tmp = (a);
    // (a) = (b);
    // (b) = tmp;;

    return 0;
}

See also

C++ Core Guidelines [11]: ES.75: Avoid do-statements.