LLVM coverage confused by if-constexpr

413 Views Asked by At

I have encountered a weird problem with LLVM coverage when using constant expressions in an if-statement:

template<typename T>
int foo(const T &val)
{
    int idx = 0;

    if constexpr(std::is_trivially_copyable<T>::value && sizeof(T) <= sizeof(int)
    {
        memcpy(&idx, &v, sizeof(T));
    }
    else
    {
        //store val and assign its index to idx
    }

    return idx;
}

The instantiations executed:

int idx1 = foo<int>(10);
int idx2 = foo<long long>(10);
int idx3 = foo<std::string>(std::string("Hello"));
int idx4 = foo<std::vector<int>>(std::vector<int>{1,2,3,4,5});

In none of these is the sizeof(T) <= sizeof(int) ever shown as executed. And yet in the first case instantiation (int) the body of the first if is indeed executed as it should. In none other it is shown as executed.

Relevant part of the compilation command line:

/usr/bin/clang++ -g -O0 -Wall -Wextra -fprofile-instr-generate -fcoverage-mapping -target x86_64-pc-linux-gnu -pipe -fexceptions -fvisibility=default -fPIC -DQT_CORE_LIB -DQT_TESTLIB_LIB -I(...) -std=c++17 -o test.o -c test.cpp

Relevant part of the linker command line:

/usr/bin/clang++ -Wl,-m,elf_x86_64,-rpath,/home/michael/Qt/5.11.2/gcc_64/lib -L/home/michael/Qt/5.11.2/gcc_64/lib -fprofile-instr-generate -fcoverage-mapping -target x86_64-pc-linux-gnu -o testd test.o -lpthread -fuse-ld=lld

When the condition is extracted to its own fucnction both int and long long instantiations are shown correctly in the coverage as executing the sizeof(T) <= sizeof(int) part. What might be causing such behaviour and how to solve it? Is it a bug in the Clang/LLVM cov?

Any ideas?

EDIT: This seems to be a known bug in LLVM (not clear yet if LLVM-cov or Clang though):

https://bugs.llvm.org/show_bug.cgi?id=36086

https://bugs.chromium.org/p/chromium/issues/detail?id=845575

1

There are 1 best solutions below

3
On

First of all, sizeof(T) <= sizeof(int) should be executed at compile-time in your code, so chances are, compilation is not profiled for coverage.

Next, of those three types only long long looks trivially_copyable, but its size is (highly likely) more than that of int, so then-clause is not executed for them, nor even compiled. Since everything happens inside a templated function, the non-executed branch is not compiled.