Отсутствует покрытие llvm-cov при вызове из утверждения
У меня есть следующие файлы заголовков:
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);
}
После компиляции с флагами -fprofile-instr-generate
а также -fcoverage-mapping
в использовании Clang++. Запустив двоичный файл модульного теста, я получаю отчет о том, что каждая из трех строк в main была вызвана, но содержимое функции использовалось только один раз. Это использование от отдельного вызова square(2)
Утверждается, что утверждения не дают правильных отчетов о покрытии.
Если я удалю автономный square(2)
тогда охват не достигает 100%, так как утверждения по какой-то причине пропускают создание покрытия.
Отчет о покрытии гласит:
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|}
Пожалуйста, не могли бы вы помочь мне понять, почему покрытие не сообщается, как я ожидал здесь? Это ошибка в llvm-cov или я не понимаю намерения покрытия?
Компиляция с использованием homebrew's clang 7.0.1 на MacOS. Использование CMake 3.13.2 для системы сборки.
1 ответ
Проблема, с которой вы сталкиваетесь, заключается в том, что ваш компилятор square()
функция для обоих методов assert. Поскольку код встроен, он никогда не вызывает ваш внешний код.
Ваша первая мысль может быть удалить inline
идентификатор, но это не сработает. Это потому, что ваш компилятор, скорее всего, достаточно умен, чтобы признать, что square()
Функция может быть встроена и идет вперед и делает это в любом случае. Конечным результатом является то, что внешний код не вызывается.
Таким образом, вам нужен способ обойти встраивание square()
функция. Вы можете сделать это с помощью указателя на функцию. Смотрите следующую модификацию вашего main
функция:
int main()
{
int (*f_ptr)(const int&); // Ptr to func that takes 'const int&' and returns 'int'
f_ptr = □
static_assert(square(2) == 4); // Cant use 'f_ptr' here
assert(f_ptr(2) == 4);
f_ptr(2);
return (0);
}
В приведенном выше коде мы заменяем явные вызовы square(const int&)
с указателем на функцию, f_ptr
, В результате компилятор не будет автоматически вставлять функции в утверждения, и код будет успешно вызван дважды. Результат:
power.cpp:
4| |template <typename T, typename R>
5| |constexpr inline R square(const T& x_) noexcept
6| 2|{
7| 2| return (x_ * x_);
8| 2|}
power_unit_test.cpp:
5| |int main()
6| 1|{
7| 1| int (*f_ptr)(const int&);
8| 1| f_ptr = □
9| 1|
10| 1| static_assert(square(2) == 4);
11| 1| assert(f_ptr(2) == 4);
12| 1| f_ptr(2);
13| 1|
14| 1| return (0);
15| 1|}
Быстрая заметка. поскольку static_assert
по сути, утверждение времени компиляции, мы не можем заменить вызов square()
с нашим указателем на функцию, так как указатели на функции не являются константными выражениями. Но не волнуйтесь, ваш компилятор достаточно умен, чтобы жаловаться, если вы попытаетесь заменить square(2)
с указателем на функцию f_ptr(2)
Вот.