Reputation: 13398
This code:
void foo(int);
int main() {
const int i = 0;
auto l = [i](){foo(i);};
}
(godbolt)
Will issue a compiler error when compiled by clang with
-std=c++17 -Werror -Wunused-lambda-capture
The error message is error: lambda capture 'i' is not required to be captured for this use
.
The error is correct: i
could be implicitly captured here, explicitly capturing it is not necessary. However, a) the warning is poorly named, since i
is used but the warning is for unused lambda captures, and b) I would just not like this to be an error. I want to error for actually unused lambda captures, but not error for used explicitly captured variables that could have been implicitly captured.
Is there a clang setting that does this? Or do I have to squelch the error using pragma diagnostic push/pop?
Upvotes: 13
Views: 7793
Reputation: 2966
I don't have a good solution for this, but we have implemented a solution.
void foo(int);
int main() {
const int i = 0;
auto l = [LAMBDA_CONSTANTS(&i)](){foo(i);};
}
LAMBDA_CONSTANTS is a macro defined in a LambdaConstants.h, which we include when needed.
The contents of which is:
#ifndef LAMBDA_CONSTANTS_H
#define LAMBDA_CONSTANTS_H
/*
given a lambda that wants to capture two constants
const auto k1 = 1000;
const auto k2 = 2000;
int v = 0;
auto lambda = [&v, &k1, &k2]() {
v = k1 * k2;
}
Then unfortunately clang will correctly warn about unnecessary captures. And MSVC will fail to compile if you don't capture.
https://stackoverflow.com/questions/52416362/unused-lambda-capture-warning-when-capture-is-actually-used
An imperfect solution is to declare the lambda using the LAMBDA_CONSTANTS macro.
auto lambda = [&v
LAMBDA_CONSTANTS(&k1, &k2)
](){
v = k1 * k2;
}
This should work correctly. Most of the time.
NOTE: There is no comma after the final capture variable before the LAMBDA_CONSTANTS macro. The macro is variadic and will work with 1 or more captures.
*/
#ifndef LAMBDA_CONSTANTS
#if _MSC_VER
#define LAMBDA_CONSTANTS(...) ,__VA_ARGS__
#else
#define LAMBDA_CONSTANTS(...)
#endif
#endif
#endif // LAMBDA_CONSTANTS_H
Upvotes: 1
Reputation: 158469
I think you are unfortunately out of luck here. If we examine the review that implemented this feature [Sema] Add warning for unused lambda captures, we can see the discussion of how to silence the warning was extensively discussed. Including the canonical clang method of silencing unused warning, which is cast to void:
I think that expected-warning shouldn't be used here as you have (void)fname in the lambda (I don't get this warning if I test this locally).
Which does work see it live but feels silly for this case.
Using -Wno-unused-lambda-capture
but that is not a favorable option for you:
I think that the patch would be neater if you add "-Wno-unused-lambda-capture" to the options for all of the tests that are modified by this patch in the CXX/ directory. This would avoid redundant (void) uses and ensure that the (void) uses won't interfere with the original intent where things might be only used in the capture list.
Leaving out the variable from the capture since it is not odr-used but as it is pointed out this exposes implementation divergence since MSVC does not do this optimization:
It will compile without any warnings if I remove kDelta from the list of captures:
#include <stdio.h> int main(void) { const int kDelta = 10000001; auto g = [](int i) { printf("%d\n", i % kDelta); }; g(2); }
But then Microsoft C++ compiler will raise the error:
error C3493: 'kDelta' cannot be implicitly captured because no default capture mode has been specified
We can see this case live as well and indeed removing i
from the capture does indeed fix it for clang and gcc but not for MSVC.
The other solution that will work for all implemntation is to explicitly capture [i=i]
but it sounds like that is also not a desirable solution (see it live).
It would be nice if we could apply [[maybe_unused]] here but we can't.
Upvotes: 10