I have the following header files:
power.hpp:
#pragma once
#include <type_traits>
template <typename T, typename R = decltype(std::declval<T>() * std::declval<T>())>
constexpr inline R square(const T& x_) noexcept;
power.inl:
#pragma once
#include "power.hpp"
template <typename T, typename R>
constexpr inline R square(const T& x_) noexcept
{
return (x_ * x_);
}
power_unit_test.cpp:
#include <power.inl>
int main()
{
static_assert(square(2) == 4);
assert(square(2) == 4);
square(2);
return (0);
}
After compiling with the flags -fprofile-instr-generate
and -fcoverage-mapping
in using clang++. And running the unit test binary, I get a report telling me that each of the three lines in main was called, but the function contents was only used once. This use is from the standalone call to square(2)
, the asserts seem to not produce coverage reports correctly.
If I remove the standalone square(2)
then the coverage does not reach 100%, as the asserts miss producing the coverage for some reason.
The coverage report reads as:
power.inl:
22| | template <typename T, typename R>
23| | constexpr inline R square(const T& x_) noexcept
24| 0| {
25| 0| return (x_ * x_);
26| 0| }
power_unit_test.cpp
29| |int main()
30| 1|{
31| 1| static_assert(arc::math::sq(2) == 4);
32| 1| assert(arc::math::sq(2) == 4);
33| 1| // arc::math::sq(2);
34| 1|
35| 1| return (0);
36| 1|}
Please could you help me understand why the coverage is not being reported as I'd expect here? Is this a bug in llvm-cov or am I not understanding the coverage intent?
Compiling using homebrew's clang 7.0.1 on MacOS. Using CMake 3.13.2 for the build system.
The problem you're encountering is that your compiler is inlining the
square()
function for both of the assert methods. Since the code is inlined, it never makes a call to your external code.Your first thought might be to remove the
inline
identifier, but that wont work. This is because your compiler is most likely smart enough to recognize that thesquare()
function could be inlined and goes ahead and does it anyway. The end result is that the external code does not get called.So you need a way to bypass the inlining of the
square()
function. You can do this with a function pointer. See the following modification to yourmain
function:In the above code, we replace the explicit calls to
square(const int&)
with a pointer to the function,f_ptr
. As a result, the compiler won't automatically inline the functions in the asserts and the code will be successfully called twice. The result:power.cpp:
power_unit_test.cpp:
A quick note. Since
static_assert
is essentially a compile-time assert, we can't replace the call tosquare()
with our function pointer, since function pointers are not constant expressions. But don't worry, your compiler is smart enough to complain if you try to replacesquare(2)
with the function pointerf_ptr(2)
here.