From fdc769195ac4833e26d99a56e111577bafc72eb4 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Wed, 23 Sep 2026 18:46:31 +0200 Subject: [PATCH 1/3] Fix #15062 Wrong varid for shadowed member in initializer list after braced init list argument (FP uninitMemberVar, selfInitialization, functionStatic) In setVarIdPass1 a '{' inside a constructor initializer list was only recognized as part of an argument if it was preceded by a name, '>', '>>' or '('. A braced init list that is not the first argument, e.g. x(f(0, {0})), or a nested one, e.g. x(f(0, {{1}, 2})), was treated as the start of the constructor body. As a result the parameter scope was not left correctly, so the member in a following p(p) got the varid of the parameter, and the parameter varid leaked into later functions. Co-Authored-By: Claude Opus 5.5 --- lib/tokenize.cpp | 2 +- test/testvarid.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index d67356ad086..f59a4d665d3 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4835,7 +4835,7 @@ void Tokenizer::setVarIdPass1() // parse anonymous namespaces as part of the current scope if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") && - !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(") && Token::Match(startToken->link(), "} ,|{|)|..."))) { + !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(|,|{") && Token::Match(startToken->link(), "} ,|{|)|}|..."))) { if (tok->str() == "{") { bool isExecutable; diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 4186917cc35..96e0bb0fe71 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2715,6 +2715,30 @@ class TestVarID : public TestFixture { "10: D < T ... > d@2 ;\n" "11: } ;\n", tokenize(code13)); + + const char code14[] = "struct S {\n" // #15062 + " int x;\n" + " int* p;\n" + " S(int* p) : x(f(0, {0})), p(p) {}\n" + " S(int* p, int) : x(f(0, {{1}, 2})), p(p) {}\n" + "};\n" + "struct T {\n" + " int* p;\n" + " int g();\n" + "};\n" + "int T::g() { return *p; }\n"; + ASSERT_EQUALS("1: struct S {\n" + "2: int x@1 ;\n" + "3: int * p@2 ;\n" + "4: S ( int * p@3 ) : x@1 ( f ( 0 , { 0 } ) ) , p@2 ( p@3 ) { }\n" + "5: S ( int * p@4 , int ) : x@1 ( f ( 0 , { { 1 } , 2 } ) ) , p@2 ( p@4 ) { }\n" + "6: } ;\n" + "7: struct T {\n" + "8: int * p@5 ;\n" + "9: int g ( ) ;\n" + "10: } ;\n" + "11: int T :: g ( ) { return * p@5 ; }\n", + tokenize(code14)); } void varid_initListWithBaseTemplate() { From b20b47c73611d8243d04b3db5f6e4f9abcfb3fe3 Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 3 Oct 2026 17:41:38 +0200 Subject: [PATCH 2/3] Handle lambda in constructor initializer list in setVarIdPass1 Co-Authored-By: Claude Opus 5.5 --- lib/tokenize.cpp | 11 ++++++++++- test/testvarid.cpp | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f59a4d665d3..ec07d927c9d 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4771,6 +4771,7 @@ void Tokenizer::setVarIdPass1() std::stack functionDeclEndStack; const Token *functionDeclEndToken = nullptr; bool initlist = false; + std::stack initlistLambdaEnds; // ends of lambda bodies in an initializer list bool inlineFunction = false; for (Token *tok = list.front(); tok; tok = tok->next()) { if (tok->isOp()) @@ -4843,6 +4844,7 @@ void Tokenizer::setVarIdPass1() while (Token::Match(prev, "%name%|.")) prev = prev->previous(); const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] ("); + const bool isInitlistLambda = initlist && (isLambda || Token::simpleMatch(prev, "]")); if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) || (initlist && tok->strAt(-1) == "}")) { isExecutable = true; @@ -4852,8 +4854,10 @@ void Tokenizer::setVarIdPass1() if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "=")) variableMap.enterScope(); } - const bool isStructInit = scopeStack.top().isStructInit || tok->strAt(-1) == "=" || (initlist && !Token::Match(tok->tokAt(-1), ")|}|...")); + const bool isStructInit = scopeStack.top().isStructInit || tok->strAt(-1) == "=" || (initlist && !isInitlistLambda && !Token::Match(tok->tokAt(-1), ")|}|...")); scopeStack.emplace(isExecutable, isStructInit, isEnumStart(tok), variableMap.getVarId()); + if (isInitlistLambda) + initlistLambdaEnds.push(tok->link()); initlist = false; } else { /* if (tok->str() == "}") */ bool isNamespace = false; @@ -4894,6 +4898,11 @@ void Tokenizer::setVarIdPass1() if (scopeStack.empty()) { // should be impossible scopeStack.emplace(/*VarIdScopeInfo()*/); } + if (!initlistLambdaEnds.empty() && initlistLambdaEnds.top() == tok) { + // continue with the initializer list after the lambda + initlistLambdaEnds.pop(); + initlist = true; + } } } } diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 96e0bb0fe71..72c1c2592ff 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2739,6 +2739,30 @@ class TestVarID : public TestFixture { "10: } ;\n" "11: int T :: g ( ) { return * p@5 ; }\n", tokenize(code14)); + + const char code15[] = "struct S {\n" // lambda in initializer list + " int x;\n" + " int* p;\n" + " S(int* p) : x([p] { return *p; }()), p(p) {}\n" + " S(int* p, int) : x([](int* q) { int y = *q; return y; }(p)), p(p) {}\n" + "};\n" + "struct T {\n" + " int* p;\n" + " int g();\n" + "};\n" + "int T::g() { return *p; }\n"; + ASSERT_EQUALS("1: struct S {\n" + "2: int x@1 ;\n" + "3: int * p@2 ;\n" + "4: S ( int * p@3 ) : x@1 ( [ p@3 ] { return * p@3 ; } ( ) ) , p@2 ( p@3 ) { }\n" + "5: S ( int * p@4 , int ) : x@1 ( [ ] ( int * q@5 ) { int y@6 ; y@6 = * q@5 ; return y@6 ; } ( p@4 ) ) , p@2 ( p@4 ) { }\n" + "6: } ;\n" + "7: struct T {\n" + "8: int * p@7 ;\n" + "9: int g ( ) ;\n" + "10: } ;\n" + "11: int T :: g ( ) { return * p@7 ; }\n", + tokenize(code15)); } void varid_initListWithBaseTemplate() { From c90bd66c787d3b56a24195e21f772a77dd09c5ca Mon Sep 17 00:00:00 2001 From: Leander Schulten Date: Sat, 3 Oct 2026 19:49:50 +0200 Subject: [PATCH 3/3] Revert "Handle lambda in constructor initializer list in setVarIdPass1" This reverts commit b20b47c73. It treated `new T[n]{...}` in an initializer list as a lambda body; the lambda case will be fixed in a separate PR. Co-Authored-By: Claude Opus 5.5 --- lib/tokenize.cpp | 11 +---------- test/testvarid.cpp | 24 ------------------------ 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ec07d927c9d..f59a4d665d3 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4771,7 +4771,6 @@ void Tokenizer::setVarIdPass1() std::stack functionDeclEndStack; const Token *functionDeclEndToken = nullptr; bool initlist = false; - std::stack initlistLambdaEnds; // ends of lambda bodies in an initializer list bool inlineFunction = false; for (Token *tok = list.front(); tok; tok = tok->next()) { if (tok->isOp()) @@ -4844,7 +4843,6 @@ void Tokenizer::setVarIdPass1() while (Token::Match(prev, "%name%|.")) prev = prev->previous(); const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] ("); - const bool isInitlistLambda = initlist && (isLambda || Token::simpleMatch(prev, "]")); if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) || (initlist && tok->strAt(-1) == "}")) { isExecutable = true; @@ -4854,10 +4852,8 @@ void Tokenizer::setVarIdPass1() if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "=")) variableMap.enterScope(); } - const bool isStructInit = scopeStack.top().isStructInit || tok->strAt(-1) == "=" || (initlist && !isInitlistLambda && !Token::Match(tok->tokAt(-1), ")|}|...")); + const bool isStructInit = scopeStack.top().isStructInit || tok->strAt(-1) == "=" || (initlist && !Token::Match(tok->tokAt(-1), ")|}|...")); scopeStack.emplace(isExecutable, isStructInit, isEnumStart(tok), variableMap.getVarId()); - if (isInitlistLambda) - initlistLambdaEnds.push(tok->link()); initlist = false; } else { /* if (tok->str() == "}") */ bool isNamespace = false; @@ -4898,11 +4894,6 @@ void Tokenizer::setVarIdPass1() if (scopeStack.empty()) { // should be impossible scopeStack.emplace(/*VarIdScopeInfo()*/); } - if (!initlistLambdaEnds.empty() && initlistLambdaEnds.top() == tok) { - // continue with the initializer list after the lambda - initlistLambdaEnds.pop(); - initlist = true; - } } } } diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 72c1c2592ff..96e0bb0fe71 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -2739,30 +2739,6 @@ class TestVarID : public TestFixture { "10: } ;\n" "11: int T :: g ( ) { return * p@5 ; }\n", tokenize(code14)); - - const char code15[] = "struct S {\n" // lambda in initializer list - " int x;\n" - " int* p;\n" - " S(int* p) : x([p] { return *p; }()), p(p) {}\n" - " S(int* p, int) : x([](int* q) { int y = *q; return y; }(p)), p(p) {}\n" - "};\n" - "struct T {\n" - " int* p;\n" - " int g();\n" - "};\n" - "int T::g() { return *p; }\n"; - ASSERT_EQUALS("1: struct S {\n" - "2: int x@1 ;\n" - "3: int * p@2 ;\n" - "4: S ( int * p@3 ) : x@1 ( [ p@3 ] { return * p@3 ; } ( ) ) , p@2 ( p@3 ) { }\n" - "5: S ( int * p@4 , int ) : x@1 ( [ ] ( int * q@5 ) { int y@6 ; y@6 = * q@5 ; return y@6 ; } ( p@4 ) ) , p@2 ( p@4 ) { }\n" - "6: } ;\n" - "7: struct T {\n" - "8: int * p@7 ;\n" - "9: int g ( ) ;\n" - "10: } ;\n" - "11: int T :: g ( ) { return * p@7 ; }\n", - tokenize(code15)); } void varid_initListWithBaseTemplate() {