2

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

Resurrection
  • 3,916
  • 2
  • 34
  • 56

1 Answers1

1

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.

bipll
  • 11,747
  • 1
  • 18
  • 32
  • The first point is valid. The second is misunderstanding. The `else` is correctly shown as either executed or not, that is not the issue. The issue is second condition of the if statement not showing as executed at all. And `int` also satisfies the condition, not just `long long`. – Resurrection Aug 28 '18 at 21:50
  • Yes, int is the only type that satisfies the RHS operand of && in `if constexpr`'s condition. Can you be more specific in what extracted where and what executed when? – bipll Aug 29 '18 at 05:32
  • The expectation is that `sizeof(T) <= sizeof(int)` condition would be executed for `int` and `long long` yet it does not show as executed for none of the 4 specializations despite the `memcpy(&idx, &v, sizeof(T));` being executed once. I understand that the condition is `contexpr` and thus compile time but LLVM-cov should understand that I would expect (and probably ignore it in the coverage). – Resurrection Aug 29 '18 at 08:08