[PATCH] D130260: [clangd] Make forwarding parameter detection logic resilient
Sam McCall via Phabricator via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 22 03:41:31 PDT 2022
sammccall added a comment.
driveby thoughts, but please don't block on them.
(if this fix is a heuristic that fixes a common crash but isn't completely correct, that may still be worth landing but warrants a fixme)
================
Comment at: clang-tools-extra/clangd/AST.cpp:832
continue;
+ // Check that this expands all the way until the last parameter.
+ auto ParamEnd = It + Parameters.size() - 1;
----------------
The essence of this test seems to be "if we can't rule it out by counting parameters, it must be right" which... doesn't seem very robust? Am I missing something?
AIUI the idea here is that
A) `foo(pack...)` is "expanded all the way" into consecutive arguments
B) `foo(pack)...` is not considered forwarding for our purposes
C) we want to treat `foo(bar(pack)...)` specially if `bar` is "just a cast" like move or forward
The difference between cases A and B aren't about counting arguments though, they're about what operations occur intercede between `pack` and the `...` operator. (i.e. `foo((&pack)...)` is fine for the same reason `forward` is.
This seems like something best handled by:
- finding the `PackExpansionExpr` controlling `pack` in the non-instantiated template AST
- walking down to try to find `pack`
- continue as we walk through e.g. parens or std::forward
- bail out if we walk through something unknown (e.g. another function call)
Does this seem sensible/feasible?
(Walking up from `pack` is nicer but the AST doesn't support walking up well...)
================
Comment at: clang-tools-extra/clangd/AST.cpp:833-837
+ auto ParamEnd = It + Parameters.size() - 1;
+ assert(std::distance(Args.begin(), ParamEnd) <
+ std::distance(Args.begin(), Args.end()) &&
+ "Only functions with greater than or equal number of parameters "
+ "should be checked.");
----------------
upsj wrote:
> I think it would be safer to check this explicitly, since advancing the iterator past its end might be UB (depending on the implementation).
Right, this is definitely UB as written.
FWIW I find this easier to understand in classic bounds-check form:
if ((It - Args.begin()) + Parameters.size() >= Args.size())
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:1468
+ void bar(Args... args) {
+ foo(id($param1[[args]], $param2[[1]])...);
+ }
----------------
(Just so I understand: these are getting hinted due to the "only instantiation" logic, right?)
================
Comment at: clang-tools-extra/clangd/unittests/InlayHintTests.cpp:1471
+ void foo() {
+ bar(1, 2);
+ }
----------------
could reasonably expect this to be `bar(a:1, 2)` or `bar(a:1, a:2)` - leave a comment explaining why?
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D130260/new/
https://reviews.llvm.org/D130260
More information about the cfe-commits
mailing list