-
Notifications
You must be signed in to change notification settings - Fork 14.6k
Open
Labels
Description
This is allowed in C++20 by P1091R3 and implemented since #54300 however in every case I've found using these constructs clang-tidy emits uninitialized variable warnings.
code example:
#include <functional>
#include <list>
#include <map>
#include <string>
void maybe_consume(std::string const&, std::list<std::string>&);
void example()
{
auto var = std::map<std::string, std::list<std::string>>{};
for (auto i = var.begin(); i != var.end();) {
auto& [key, value] = *i;
auto p1091r3 = [&] { maybe_consume(key, value); };
std::invoke(p1091r3);
if (value.empty()) {
i = var.erase(i);
} else {
++i;
}
}
}
compiler output: https://godbolt.org/z/ns7Yc7GT8
clang-tidy command line: clang-tidy --checks="clang-analyzer-*" --extra-arg="-std=c++20"
clang-tidy output:
1 warning generated.
/home/user/src/examples/clang-analyzer-p1091r3.cpp:14:30: warning: 1st function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage]
14 | auto p1091r3 = [&] { maybe_consume(key, value); };
| ^
/home/user/src/examples/clang-analyzer-p1091r3.cpp:12:5: note: Loop condition is true. Entering loop body
12 | for (auto i = var.begin(); i != var.end();) {
| ^
/home/user/src/examples/clang-analyzer-p1091r3.cpp:15:9: note: Calling 'invoke<(lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
15 | std::invoke(p1091r3);
| ^~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/functional:122:14: note: Calling '__invoke<(lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
122 | return std::__invoke(std::forward<_Callable>(__fn),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/bits/invoke.h:98:14: note: Calling '__invoke_impl<void, (lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
98 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/bits/invoke.h:63:14: note: Calling 'operator()'
63 | { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/src/examples/clang-analyzer-p1091r3.cpp:14:30: note: 1st function call argument is an uninitialized value
14 | auto p1091r3 = [&] { maybe_consume(key, value); };
| ^ ~~~
Switching from default capture to named capture does not help:
1 warning generated.
/home/user/src/examples/clang-analyzer-p1091r3.cpp:14:41: warning: 1st function call argument is an uninitialized value [clang-analyzer-core.CallAndMessage]
14 | auto p1091r3 = [&key, &value] { maybe_consume(key, value); };
| ^
/home/user/src/examples/clang-analyzer-p1091r3.cpp:12:5: note: Loop condition is true. Entering loop body
12 | for (auto i = var.begin(); i != var.end();) {
| ^
/home/user/src/examples/clang-analyzer-p1091r3.cpp:15:9: note: Calling 'invoke<(lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
15 | std::invoke(p1091r3);
| ^~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/functional:122:14: note: Calling '__invoke<(lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
122 | return std::__invoke(std::forward<_Callable>(__fn),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
123 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/bits/invoke.h:98:14: note: Calling '__invoke_impl<void, (lambda at /home/user/src/examples/clang-analyzer-p1091r3.cpp:14:24) &, >'
98 | return std::__invoke_impl<__type>(__tag{}, std::forward<_Callable>(__fn),
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99 | std::forward<_Args>(__args)...);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/lib/gcc/powerpc64le-unknown-linux-gnu/15/include/g++-v15/bits/invoke.h:63:14: note: Calling 'operator()'
63 | { return std::forward<_Fn>(__f)(std::forward<_Args>(__args)...); }
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/user/src/examples/clang-analyzer-p1091r3.cpp:14:41: note: 1st function call argument is an uninitialized value
14 | auto p1091r3 = [&key, &value] { maybe_consume(key, value); };
| ^ ~~~
Metadata
Metadata
Assignees
Labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
llvmbot commentedon May 31, 2025
@llvm/issue-subscribers-clang-tidy
Author: Justus Ranvier (justusranvier)
code example:
compiler output: https://godbolt.org/z/ns7Yc7GT8
clang-tidy command line:
clang-tidy --checks="clang-analyzer-*" --extra-arg="-std=c++20"
clang-tidy output:
Switching from default capture to named capture does not help:
llvmbot commentedon May 31, 2025
@llvm/issue-subscribers-clang-static-analyzer
Author: Justus Ranvier (justusranvier)
code example:
compiler output: https://godbolt.org/z/ns7Yc7GT8
clang-tidy command line:
clang-tidy --checks="clang-analyzer-*" --extra-arg="-std=c++20"
clang-tidy output:
Switching from default capture to named capture does not help:
steakhal commentedon Jun 1, 2025
Could you reproduce it on Godbolt using the trunk clang tidy?
I think we may have fixed this already in b55dd8f, which should be available on main.
justusranvier commentedon Jun 1, 2025
If it's possible to run clang static analyzer on Compiler Explorer I don't know how to so, but it does seem likely this issue is a duplicate of #91835.
I'll test again the next time I get a chance to build LLVM from source or when version 21 is released, whichever comes first.
steakhal commentedon Jun 1, 2025
I think it's that issue. It's because prior to that patch, lambdas could not capture decomposed decls (aka. structured bindings), hence they remained associated with the default, uninitialized state, hence the report of
1st function call argument is an uninitialized value
when it tries to read the decomposed declkey
.Here is an example configuration: https://godbolt.org/z/E3Eh8PKzG