Skip to content

Fix #15084 Wrong varid for lambda in constructor initializer list - #8917

Open
autoantwort wants to merge 2 commits into
cppcheck-opensource:mainfrom
autoantwort:fix-varid-initlist-lambda
Open

autoantwort wants to merge 2 commits into
cppcheck-opensource:mainfrom
autoantwort:fix-varid-initlist-lambda

Conversation

@autoantwort

@autoantwort autoantwort commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

https://trac.cppcheck.net/ticket/15084

In setVarIdPass1() the body of a lambda in a constructor initializer list was taken as the start of the constructor body, so the following members got the parameter's varid, lambda parameters leaked into the rest of the initializer list and the parameter varid leaked into later functions (FP uninitMemberVar, selfInitialization, functionStatic, unusedStructMember, constParameterPointer):

struct S {
    int* p;
    int x;
    S(int* p) : x([p] { return *p; }()), p(p) {}
};
struct T { int* p; int g(); };
int T::g() { return *p; }

A lambda in an initializer list (detected with findLambdaEndScope()) is now parsed like a lambda in executable code in its own scope, and the initializer list continues after it. Array sizes of new expressions (new T[n]{...}, new T*[n]{...}, new (p) T*[n]{...}) are not taken as lambda captures.

Covered: plain lambdas, parameters (also shadowing a constructor parameter), mutable, noexcept, trailing return types, [&]/[=], nested lambdas, braced member initializers.

Not handled (unchanged behaviour, to keep this PR small):

  • template lambdas and trailing return types with template arguments (-> std::vector<int>), findLambdaEndScope() can't find their end before createLinks2()
  • lambdas directly after ) or > ((int)[p]{...}(), a > [p]{...}()), as they can't be told apart from a subscript here
  • lambdas after a braced temporary in the same initializer (std::string{"a"}.size() + [p]{...}()), the { of the temporary already ends the initializer list handling

Follow-up of the review of #8885.

This PR was created by Claude Code (an AI coding agent) on behalf of @autoantwort.

🤖 Generated with Claude Code

autoantwort and others added 2 commits October 3, 2026 20:14
The lambda body in an initializer list was taken as the start of the
constructor body, so following members got the parameter varid, lambda
parameters leaked into the rest of the initializer list and the parameter
varid leaked into later functions (FP uninitMemberVar, selfInitialization,
functionStatic, constParameterPointer).

The lambda is now parsed like a lambda in executable code. findTypeEnd() also
finds the end of unlinked template brackets so that findLambdaEndScope() works
for trailing return types like std::vector<int> before createLinks2().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hanged

`new (p) T*[n]{...}` and `new decltype(x)*[n]{...}` in an initializer list
were taken as lambdas. Revert the findTypeEnd() change to keep the PR small,
lambdas with templates in the trailing return type keep the old behaviour.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant