Adds fix-its when users forget to explicitly capture variables or this in lambdas
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
Remove default capture by value fixit if 'this' is explicitly captured pre c++20.
Fix default capture insertion loc to be at the start of the capture list.
clang/lib/Sema/SemaExprCXX.cpp | ||
---|---|---|
1229–1235 | Could we just attach this fix directly to the warning? |
Restrict availability of default capture fixit based on init captures already specified.
[=, A]() {} and [&, &A]() {} are both invalid as explicit captures can't be specified with the same type as default capture.
So we shouldn't offer '=' fixit if any init captures are by value and '&' if any by ref.
clang/include/clang/Basic/DiagnosticSemaKinds.td | ||
---|---|---|
7459–7460 | Does the variable name need attaching to the note, given the note is attached to a fix-it containing the name of the variable already? |
Hi Nathan! Thanks again for this patch and sorry for not taking time to review it yet. It is a busy week for me and my team, so I wasn't able to do much coding/reviewing, apologies for that. I expect to get some time for this in the upcoming days and I do think it's an important thing to dedicate time for.
Thanks! The code looks right, my comments are mostly for the comments around to validate my mental model of the code structure and behavior.
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17413 | Would be useful to have high-level comments for all three cases you have here. This one is for individual variables, right? | |
17422 | Not having return; after this one or the other ones throws me off-guard and I came to the realization that what you intend here is: the function can issue all FixItHints - for capturing a variable by value, reference and default captures by value and reference. So, in total there could be 4 FixItHint so that the user could choose between all of those and chose the one they want. Is that correct? I think this is something worth documenting. | |
17425 | This comment seems a bit off to me? Could you please expand? (I also don't understand how this relates to the next line). | |
17610 | now there are 3 cast<LambdaScopeInfo>, maybe introduce a variable? would've been much better with C++ init + condition but still |
clang/include/clang/Basic/DiagnosticSemaKinds.td | ||
---|---|---|
7462 | also, "capture all" is a little confusing to me but I don't know what would be better. "capture everything"/"capture all variables/objects"? don't know if it's better. |
LGTM, thanks for implementing this and apologies for the review delay (was a tough week for me & my team).
The code is very easy to follow now and the only suggestions are stylistic nits.
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17414 | This code heavily relies on not having any default captures and I can see that all of the code paths are correct (this condition is checked before calling the function), but I think it's better to explicitly check this with an assert. | |
17422 | ||
17428 | nit: the style seems to be omitting {} for single-line sequences of if/for/whiles, probably remove in this case? | |
17429 | nit: CT -> Ctor? CT looks a little unexpected. | |
17470 | also allows removing enclosing {} | |
17478 | maybe just pull the outside if into the inner one? does not seem to hurt readability and reduces the indentation + LOC number. |
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17430 | (braces are not needed here, too) |
Nice fixes! A few drive-by comments from me, up to you though.
clang/include/clang/Basic/DiagnosticSemaKinds.td | ||
---|---|---|
7459–7460 | perhaps not, but I don't think it hurts | |
clang/lib/Sema/SemaExpr.cpp | ||
17418 | this lambda looks like it could/should be a standalone function | |
17427 | I suspect you need to handle the case where RD is incomplete | |
17436 | POD is rarely precisely the right concept (and deprecated for that reason). | |
17440 | This logic assumes there's no default capture, whic his reasonable but not locally obvious - add an assert? | |
17472 | While it's technically possible to transform [&a, &b] to [=, &a, &b], it seems very unlikely the user actually wants this: we should capture the new variable by copy and make that the default, even though so far we've been listing captures explicitly and by reference. On the other hand, transforming [a, b] to [=] seems more useful, but isn't supported. I'd suggest just leaving both cases out - only offer a default capture if there are no explicit captures already. |
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17440 | I think this is the same as https://reviews.llvm.org/D96975#inline-920917 (which is done), am I wrong? |
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17436 | Also, maybe if (T->isTriviallyCopyableType(Sema.getASTContext())) return true; at the top and just return false; here? This saves us the necessity to iterate through the ctors. |
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17427 | I thought that could be skipped, but yeah you're right you could have a lambda parameter be an incomplete type if you're only referencing it. | |
17472 | Transforming [a, b] to [=] is not a good idea imo. We would be replacing perfectly legal, non ambiguous code. The reason default capture fix-its are emitted last is because more often than not they wont be the users intentions, however It's still nice to show that it is a possibility. |
clang/lib/Sema/SemaExpr.cpp | ||
---|---|---|
17472 | I don't think fixits are for surfacing code transformations that are unlikely to be what the user wants. |
Prevent explicit 'this' capture fix-it if default capture mode is '=' and not in c++20 mode.
Does the variable name need attaching to the note, given the note is attached to a fix-it containing the name of the variable already?