Fix issue 9109: Syntax error for valid C++ code

This commit is contained in:
Paul Fultz II 2019-05-24 10:44:08 +02:00 committed by Daniel Marjamäki
parent 5efb23ffff
commit cb7f925f5e
3 changed files with 116 additions and 11 deletions

View File

@ -1056,8 +1056,9 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
void TemplateSimplifier::simplifyTemplateAliases()
{
std::list<TokenAndName>::iterator it1, it2;
std::list<TokenAndName>::iterator it1, it2, it3;
for (it1 = mTemplateInstantiations.begin(); it1 != mTemplateInstantiations.end();) {
it3 = it1;
TokenAndName &templateAlias = *it1;
++it1;
Token *startToken = templateAlias.token;
@ -1065,13 +1066,15 @@ void TemplateSimplifier::simplifyTemplateAliases()
continue;
while (Token::Match(startToken->tokAt(-2), "%name% :: %name%"))
startToken = startToken->tokAt(-2);
if (!Token::Match(startToken->tokAt(-4), "> using %name% = %name% ::|<"))
if (!(Token::Match(startToken->tokAt(-4), "> using %name% = %name% ::|<") ||
Token::Match(startToken->tokAt(-5), "> using %name% = typename %name% ::|<")))
continue;
const std::string aliasName(startToken->strAt(-2));
const bool hasTypename(startToken->strAt(-1) == "typename");
const std::string aliasName(startToken->strAt(hasTypename ? -3 : -2));
const Token * const aliasToken1 = startToken;
// Get start token for alias
startToken = startToken->tokAt(-5);
startToken = startToken->tokAt(hasTypename ? -6 : -5);
while (Token::Match(startToken, "%name%|<|>|>>|,"))
startToken = startToken->previous();
// handle case where 'template' is first token
@ -1158,6 +1161,8 @@ void TemplateSimplifier::simplifyTemplateAliases()
}
endToken = endToken1->next();
while (endToken->str() != ";")
endToken = endToken->next();
// Remove alias usage code (parameters)
Token::eraseTokens(tok2->previous(), args.back().second);
@ -1180,7 +1185,7 @@ void TemplateSimplifier::simplifyTemplateAliases()
}
// find declaration
const std::list<TokenAndName>::iterator it3 = std::find_if(mTemplateDeclarations.begin(),
const std::list<TokenAndName>::iterator it4 = std::find_if(mTemplateDeclarations.begin(),
mTemplateDeclarations.end(),
FindToken(startToken ? startToken->next() : mTokenList.front()));
@ -1192,9 +1197,10 @@ void TemplateSimplifier::simplifyTemplateAliases()
}
// remove declaration
if (it3 != mTemplateDeclarations.end())
mTemplateDeclarations.erase(it3);
}
if (it4 != mTemplateDeclarations.end())
mTemplateDeclarations.erase(it4);
} else
mTemplateInstantiations.erase(it3);
}
}
@ -2417,7 +2423,8 @@ std::string TemplateSimplifier::getNewName(
{
std::string typeForNewName;
unsigned int indentlevel = 0;
for (Token *tok3 = tok2->tokAt(2); tok3 && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
const Token * endToken = tok2->next()->findClosingBracket();
for (Token *tok3 = tok2->tokAt(2); tok3 != endToken && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
// #2648 - unhandled parentheses => bail out
// #2721 - unhandled [ => bail out
if (Token::Match(tok3, "(|[")) {
@ -2686,10 +2693,11 @@ void TemplateSimplifier::replaceTemplateUsage(
// match parameters
Token * tok2 = nameTok->tokAt(2);
const Token * endToken = nameTok->next()->findClosingBracket();
unsigned int typeCountInInstantiation = tok2->str() == ">" ? 0U : 1U;
const Token *typetok = (!mTypesUsedInTemplateInstantiation.empty()) ? mTypesUsedInTemplateInstantiation[0].token : nullptr;
unsigned int indentlevel2 = 0; // indentlevel for tokgt
while (tok2 && (indentlevel2 > 0 || tok2->str() != ">")) {
while (tok2 != endToken && (indentlevel2 > 0 || tok2->str() != ">")) {
if (tok2->str() == "<" && templateParameters(tok2) > 0)
++indentlevel2;
else if (indentlevel2 > 0 && Token::Match(tok2, "> [,>]"))

View File

@ -145,6 +145,7 @@ private:
TEST_CASE(template105); // #9076
TEST_CASE(template106);
TEST_CASE(template107); // #8663
TEST_CASE(template108); // #9109
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
@ -2448,6 +2449,88 @@ private:
ASSERT_EQUALS(exp, tok(code));
}
void template108() { // #9109
{
const char code[] = "template <typename> struct a;\n"
"template <typename> struct b {};\n"
"template <typename> struct c;\n"
"template <typename d> struct e {\n"
" using f = a<b<typename c<d>::g>>;\n"
" bool h = f::h;\n"
"};\n"
"struct i {\n"
" e<int> j();\n"
"};\n";
const char exp[] = "template < typename > struct a ; "
"struct b<c<int>::g> ; "
"template < typename > struct c ; "
"struct e<int> ; "
"struct i { e<int> j ( ) ; "
"} ; "
"struct e<int> { bool h ; "
"h = a < b<c<int>::g> > :: h ; "
"} ; "
"struct b<c<int>::g> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "namespace {\n"
"template <typename> struct a;\n"
"template <typename> struct b {};\n"
"}\n"
"namespace {\n"
"template <typename> struct c;\n"
"template <typename d> struct e {\n"
" using f = a<b<typename c<d>::g>>;\n"
" bool h = f::h;\n"
"};\n"
"template <typename i> using j = typename e<i>::g;\n"
"}";
const char exp[] = "namespace { "
"template < typename > struct a ; "
"template < typename > struct b { } ; "
"} "
"namespace { "
"template < typename > struct c ; "
"template < typename d > struct e { "
"using f = a < b < c < d > :: g > > ; "
"bool h ; h = f :: h ; "
"} ; "
"template < typename i > using j = typename e < i > :: g ; "
"}";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "namespace {\n"
"template <typename> struct a;\n"
"template <typename> struct b {};\n"
"}\n"
"namespace {\n"
"template <typename> struct c;\n"
"template <typename d> struct e {\n"
" using f = a<b<typename c<d>::g>>;\n"
" bool h = f::h;\n"
"};\n"
"template <typename i> using j = typename e<i>::g;\n"
"}\n"
"j<int> foo;";
const char exp[] = "namespace { "
"template < typename > struct a ; "
"struct b<c<int>::g> ; "
"} "
"namespace { "
"template < typename > struct c ; "
"struct e<int> ; "
"} "
"e<int> foo ; "
"struct e<int> { "
"bool h ; h = a < b<c<int>::g> > :: h ; "
"} ; "
"struct b<c<int>::g> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
const char code[] = "template <typename T> struct C {};\n"
"template <typename T> struct S {a};\n"

View File

@ -7647,6 +7647,21 @@ private:
}
void checkTemplates() {
// #9109
ASSERT_NO_THROW(tokenizeAndStringify(
"namespace {\n"
"template <typename> struct a;\n"
"template <typename> struct b {};\n"
"}\n"
"namespace {\n"
"template <typename> struct c;\n"
"template <typename d> struct e {\n"
" using f = a< b<typename c<d>::g> >;\n"
" bool h = f::h;\n"
"};\n"
"template <typename i> using j = typename e<i>::g;\n"
"}\n"))
ASSERT_NO_THROW(tokenizeAndStringify(
"template <typename = void> struct a {\n"
" void c();\n"
@ -7666,7 +7681,6 @@ private:
"};\n"))
}
void noCrash1() {
ASSERT_NO_THROW(tokenizeAndStringify(
"struct A {\n"