Remove bailout and fix varid for template class member initialized in out-of-line constructor (#8031)
This commit is contained in:
parent
8a668aa860
commit
28960a8bba
|
@ -710,6 +710,33 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::stri
|
|||
return true;
|
||||
}
|
||||
|
||||
// Utility function for TemplateSimplifier::getTemplateNamePosition, that works on template member functions,
|
||||
// hence this pattern: "> %type% [%type%] < ... > :: %type% ("
|
||||
bool getTemplateNamePositionTemplateMember(const Token *tok, int &namepos)
|
||||
{
|
||||
if (!Token::Match(tok, "> %type% <") && !Token::Match(tok, "> %type% %type% <"))
|
||||
return false;
|
||||
|
||||
int currPos = 0;
|
||||
currPos = 2 + (Token::Match(tok, "> %type% %type%"));
|
||||
|
||||
// Find the end of the template argument list
|
||||
const Token *templateParmEnd = tok->linkAt(currPos);
|
||||
if (!templateParmEnd)
|
||||
templateParmEnd = tok->tokAt(currPos)->findClosingBracket();
|
||||
if (!templateParmEnd)
|
||||
return false;
|
||||
|
||||
if (Token::Match(templateParmEnd->next(), ":: %type% (")) {
|
||||
// We have a match, and currPos points at the template list opening '<'. Move it to the closing '>'
|
||||
for (const Token *tok2 = tok->tokAt(currPos) ; tok2 != templateParmEnd ; tok2 = tok2->next())
|
||||
++currPos;
|
||||
namepos = currPos + 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
||||
{
|
||||
// get the position of the template name
|
||||
|
@ -720,14 +747,9 @@ int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
|||
namepos = 2;
|
||||
else if (Token::Match(tok, "> %type% %type% *|&| %type% ("))
|
||||
namepos = 3;
|
||||
else if ((Token::Match(tok, "> %type% <") && Token::Match(tok->linkAt(2), "> :: %type% (")) ||
|
||||
(Token::Match(tok, "> %type% %type% <") && Token::Match(tok->linkAt(3), "> :: %type% ("))) {
|
||||
namepos = 2 + (Token::Match(tok, "> %type% %type%"));
|
||||
const Token *end = tok->linkAt(namepos);
|
||||
for (const Token *tok2 = tok->tokAt(namepos) ; tok2 != end ; tok2 = tok2->next())
|
||||
++namepos;
|
||||
namepos += 2;
|
||||
} else if (Token::Match(tok, "> %type% *|&| %type% :: %type% (")) {
|
||||
else if (getTemplateNamePositionTemplateMember(tok, namepos))
|
||||
;
|
||||
else if (Token::Match(tok, "> %type% *|&| %type% :: %type% (")) {
|
||||
namepos = 4;
|
||||
starAmpPossiblePosition = 2;
|
||||
} else if (Token::Match(tok, "> %type% %type% *|&| %type% :: %type% (")) {
|
||||
|
|
|
@ -2910,8 +2910,10 @@ void Tokenizer::setVarIdPass2()
|
|||
for (std::list<Token *>::iterator func = allMemberFunctions.begin(); func != allMemberFunctions.end(); ++func) {
|
||||
Token *tok2 = *func;
|
||||
|
||||
if (!Token::Match(tok2, classname.c_str()))
|
||||
continue;
|
||||
if (!Token::Match(tok2, classname.c_str())) {
|
||||
if (tok2->str() != classname) // #8031: Both could be "A < B >" and if so, one must not bail out
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Token::Match(tok2, "%name% <"))
|
||||
tok2 = tok2->next()->findClosingBracket();
|
||||
|
|
|
@ -1359,11 +1359,14 @@ private:
|
|||
}
|
||||
|
||||
// Helper function to unit test TemplateSimplifier::getTemplateNamePosition
|
||||
int templateNamePositionHelper(const char code[], unsigned offset = 0) {
|
||||
int templateNamePositionHelper(const char code[], unsigned offset = 0, bool onlyCreateTokens = false) {
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp", emptyString);
|
||||
if (onlyCreateTokens)
|
||||
tokenizer.createTokens(istr, "test.cpp");
|
||||
else
|
||||
tokenizer.tokenize(istr, "test.cpp", emptyString);
|
||||
|
||||
const Token *_tok = tokenizer.tokens();
|
||||
for (unsigned i = 0 ; i < offset ; ++i)
|
||||
|
@ -1398,6 +1401,11 @@ private:
|
|||
"template<class T> unsigned A<T>::foo() { return 0; }", 19));
|
||||
ASSERT_EQUALS(9, templateNamePositionHelper("template<class T, class U> class A { unsigned foo(); }; "
|
||||
"template<class T, class U> unsigned A<T, U>::foo() { return 0; }", 25));
|
||||
ASSERT_EQUALS(9, templateNamePositionHelper("template<class T, class U> class A { unsigned foo(); }; "
|
||||
"template<class T, class U> unsigned A<T, U>::foo() { return 0; }", 25, /*onlyCreateTokens=*/true));
|
||||
ASSERT_EQUALS(12, templateNamePositionHelper("template<class T> class v {}; "
|
||||
"template<class T, class U> class A { unsigned foo(); }; "
|
||||
"template<> unsigned A<int, v<char> >::foo() { return 0; }", 30, /*onlyCreateTokens=*/true));
|
||||
}
|
||||
|
||||
void expandSpecialized() {
|
||||
|
|
|
@ -63,6 +63,7 @@ private:
|
|||
TEST_CASE(tokenize31); // #3503 (Wrong handling of member function taking function pointer as argument)
|
||||
TEST_CASE(tokenize32); // #5884 (fsanitize=undefined: left shift of negative value -10000 in lib/templatesimplifier.cpp:852:46)
|
||||
TEST_CASE(tokenize33); // #5780 Various crashes on valid template code
|
||||
TEST_CASE(tokenize34); // #8031
|
||||
|
||||
TEST_CASE(validate);
|
||||
|
||||
|
@ -785,6 +786,39 @@ private:
|
|||
tokenizeAndStringify(code, true);
|
||||
}
|
||||
|
||||
void tokenize34() { // #8031
|
||||
{
|
||||
const char code[] = "struct Containter {\n"
|
||||
" Containter();\n"
|
||||
" int* mElements;\n"
|
||||
"};\n"
|
||||
"Containter::Containter() : mElements(nullptr) {}\n"
|
||||
"Containter intContainer;";
|
||||
const char exp [] = "1: struct Containter {\n"
|
||||
"2: Containter ( ) ;\n"
|
||||
"3: int * mElements@1 ;\n"
|
||||
"4: } ;\n"
|
||||
"5: Containter :: Containter ( ) : mElements@1 ( nullptr ) { }\n"
|
||||
"6: Containter intContainer@2 ;\n";
|
||||
ASSERT_EQUALS(exp, tokenizeDebugListing(code, /*simplify=*/true));
|
||||
}
|
||||
{
|
||||
const char code[] = "template<class T> struct Containter {\n"
|
||||
" Containter();\n"
|
||||
" int* mElements;\n"
|
||||
"};\n"
|
||||
"template <class T> Containter<T>::Containter() : mElements(nullptr) {}\n"
|
||||
"Containter<int> intContainer;";
|
||||
const char exp [] = "5: template < class T > Containter < T > :: Containter ( ) : mElements ( nullptr ) { }\n"
|
||||
"6: Containter < int > intContainer@1 ; struct Containter < int > {\n"
|
||||
"2: Containter < int > ( ) ;\n"
|
||||
"3: int * mElements@2 ;\n"
|
||||
"4: } ;\n"
|
||||
"5: Containter < int > :: Containter ( ) : mElements@2 ( nullptr ) { }\n";
|
||||
ASSERT_EQUALS(exp, tokenizeDebugListing(code, /*simplify=*/true));
|
||||
}
|
||||
}
|
||||
|
||||
void validate() {
|
||||
// C++ code in C file
|
||||
ASSERT_THROW(tokenizeAndStringify(";using namespace std;",false,false,Settings::Native,"test.c"), InternalError);
|
||||
|
|
Loading…
Reference in New Issue