llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.56k stars 11.81k forks source link

-Wunused-variable false positive in `if constexpr` and with `assert` #55832

Open Tomaqa opened 2 years ago

Tomaqa commented 2 years ago

Consider following minimal example:

#ifdef DEBUG
constexpr bool _debug_ = true;
#undef NDEBUG
#else
constexpr bool _debug_ = false;
#define NDEBUG
#endif

#include <cassert>

void f()
{
    if constexpr (_debug_) {
        const int cnt = 1;
        assert(cnt == 0);
    }  
}

clang++ -c <file> -std=c++17 -Wunused-variable yields unused variable 'cnt'.

clang++ -c <file> -std=c++17 -Wunused-variable -DDEBUG does not.

I suppose that this is unintended behavior. I expect no warning in both cases.

tbaederr commented 2 years ago

I believe this is just happening because the <cassert> header also uses the NDEBUG define. assert() evaluates to nothing if NDEBUG is set:

/* void assert (int expression);

   If NDEBUG is defined, do nothing.
   If not, and EXPRESSION is zero, print an error message and abort.  */

#ifdef  NDEBUG

# define assert(expr)       (__ASSERT_VOID_CAST (0))

If I remove the lines handling NDEBUG from your reproducer, the warning disappears.

Tomaqa commented 2 years ago

NDEBUG is handled exclusively by <cassert>, and without it, assert commands are being processed even in non-debug mode, which is not what you want in a release mode.

tbaederr commented 2 years ago

So what's your point then? That cnt should be marked used even if assert() doesn't actually end up using it? How is that realted to if constexpr?

That behavior is well known.

Tomaqa commented 2 years ago

The whole if constexpr branch takes effect only in debug mode, when assert takes effect. Otherwise, the block is not used, thus, the variable cnt is not used at all in this case, meaning not even declared.

So there is no point to warn that it is not used, because it was not even intended to be used in this case.

It would work just fine if #ifdef was used instead of if constexpr, but in this case, it should behave the same in both cases.