Open 73dc6587-d003-4d5d-9fd0-2c50994fb6f3 opened 3 years ago
This is static analyser issues, clang-analyzer-core.UndefinedBinaryOperatorResult
/fpwork/llvm-project3/1.cpp:59:23: warning: The left operand of '==' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult]
return t.get<1>() == 'c';
~~~~~~~~~~ ^
/fpwork/llvm-project3/1.cpp:58:33: note: Calling constructor for 'tuple<int, char, float>'
tuple<int, char, float> t = { 1, 'c', 2.0f };
^~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:42:9: note: Calling constructor for 'tuple_storage<std::integer_sequence<unsigned long, 0, 1, 2>, int, char, float>'
: storage(args...)
^~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:29:5: note: Returning without writing to 'this->value'
{}
^
/fpwork/llvm-project3/1.cpp:42:9: note: Returning from constructor for 'tuple_storage<std::integer_sequence<unsigned long, 0, 1, 2>, int, char, float>'
: storage(args...)
^~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:43:6: note: Returning without writing to 'this->storage.value'
{}
^
/fpwork/llvm-project3/1.cpp:58:33: note: Returning from constructor for 'tuple<int, char, float>'
tuple<int, char, float> t = { 1, 'c', 2.0f };
^~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:59:12: note: Calling 'tuple::get'
return t.get<1>() == 'c';
^~~~~~~~~~
/fpwork/llvm-project3/1.cpp:48:16: note: Calling 'tuple_storage::get'
return storage_t::template get<N>(storage);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:34:7: note: Returning without writing to 'base.value'
return base.value;
^
/fpwork/llvm-project3/1.cpp:34:7: note: Returning pointer (reference to 't.storage.value')
return base.value;
^~~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:48:16: note: Returning from 'tuple_storage::get'
return storage_t::template get<N>(storage);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:48:9: note: Returning pointer (reference to 't.storage.value')
return storage_t::template get<N>(storage);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/fpwork/llvm-project3/1.cpp:59:12: note: Returning from 'tuple::get'
return t.get<1>() == 'c';
^~~~~~~~~~
/fpwork/llvm-project3/1.cpp:59:23: note: The left operand of '==' is a garbage value
return t.get<1>() == 'c';
~~~~~~~~~~ ^
@llvm/issue-subscribers-clang-static-analyzer
Reproduced: https://godbolt.org/z/PvqcaG9Mr
<source>:41:35: note: Calling constructor for 'tuple_storage<std::integer_sequence<unsigned long, 0, 1, 2>, int, char, float>'
constexpr tuple(Ts... args) : storage(args...) {}
^~~~~~~~~~~~~~~~
<source>:29:6: note: Returning without writing to 'this->value'
{}
^
This is definitely wrong and surprising, I wouldn't expect basic constructors to act up this way. (And they're really basic given that we see through templates transparently.) Need to take a closer look.
#ifdef CLANG_TIDY_WORKAROUND
Note that you can use #ifdef __clang_analyzer__
to find out if clang analyzer is running, this may help you automate your workarounds!
Here is a smaller example with clang-17
Extended Description
Following snippet reproduces the bug
tuple_storage variadic constructor correctly performs aggregate initialization of all its base classes, but clang-tidy complains that they are not initialized.
include
include
template <size_t N, typename T> struct indexed_elem_storage {
ifdef CLANG_TIDY_WORKAROUND
indexed_elem_storage() = default;
constexpr indexed_elem_storage(T val) : value(val) {}
endif
T value{}; };
template <typename ...Ts> struct tuple_storage;
template <size_t ...Ints, typename ...Ts> struct tuple_storage<std::index_sequence, Ts...>
: indexed_elem_storage<Ints, Ts>...
{
tuple_storage() = default;
constexpr tuple_storage(Ts ...args) : indexed_elem_storage<Ints, Ts>{args}... {}
template <size_t N, typename T> static constexpr T& get(indexed_elem_storage<N, T>& base) { return base.value; } };
template <typename ...Ts> struct tuple { constexpr tuple(Ts... args) : storage(args...) {}
private: using storage_t = tuple_storage<std::index_sequence_for, Ts...>;
storage_t storage;
};
constexpr bool test() { tuple<int, char, float> t = { 1, 'c', 2.0f }; return t.get<1>() == 'c'; }
int main() { static_assert(test(), ""); }