* Fix #9225 (Crash on valid C++14 code) This only fixes the crash. Specialization of nested templates is still broken. * fix cppcheck warnings * fixed another cppcheck warning
This commit is contained in:
parent
bbcffce529
commit
999d2f797c
|
@ -79,7 +79,21 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
|
|||
// only set flags for declaration
|
||||
if (token && nameToken && paramEnd) {
|
||||
isSpecialization(Token::simpleMatch(token, "template < >"));
|
||||
isPartialSpecialization(!isSpecialization() && nameToken->strAt(1) == "<");
|
||||
|
||||
if (!isSpecialization()) {
|
||||
if (Token::simpleMatch(token->next()->findClosingBracket(), "> template <")) {
|
||||
const Token * temp = nameToken->tokAt(-2);
|
||||
while (Token::Match(temp, ">|%name% ::")) {
|
||||
if (temp->str() == ">")
|
||||
temp = temp->findOpeningBracket()->previous();
|
||||
else
|
||||
temp = temp->tokAt(-2);
|
||||
}
|
||||
isPartialSpecialization(temp->strAt(1) == "<");
|
||||
} else
|
||||
isPartialSpecialization(nameToken->strAt(1) == "<");
|
||||
}
|
||||
|
||||
isAlias(paramEnd->strAt(1) == "using");
|
||||
|
||||
if (isAlias() && isPartialSpecialization()) {
|
||||
|
@ -775,6 +789,19 @@ bool TemplateSimplifier::getTemplateDeclarations()
|
|||
// ignore template template parameter
|
||||
if (tok->strAt(-1) == "<")
|
||||
continue;
|
||||
// ignore nested template
|
||||
if (tok->strAt(-1) == ">")
|
||||
continue;
|
||||
// skip to last nested template parameter
|
||||
const Token *tok1 = tok;
|
||||
while (tok1 && tok1->next() && Token::simpleMatch(tok1->next()->findClosingBracket(), "> template <")) {
|
||||
const Token *closing = tok1->next()->findClosingBracket();
|
||||
if (!closing)
|
||||
syntaxError(tok1->next());
|
||||
tok1 = closing->next();
|
||||
}
|
||||
if (!tok1)
|
||||
syntaxError(tok);
|
||||
// Some syntax checks, see #6865
|
||||
if (!tok->tokAt(2))
|
||||
syntaxError(tok->next());
|
||||
|
@ -782,7 +809,7 @@ bool TemplateSimplifier::getTemplateDeclarations()
|
|||
!Token::Match(tok->tokAt(3), "%name%|.|,|=|>"))
|
||||
syntaxError(tok->next());
|
||||
codeWithTemplates = true;
|
||||
const Token * const parmEnd = tok->next()->findClosingBracket();
|
||||
const Token * const parmEnd = tok1->next()->findClosingBracket();
|
||||
for (const Token *tok2 = parmEnd; tok2; tok2 = tok2->next()) {
|
||||
if (tok2->str() == "(" && tok2->link())
|
||||
tok2 = tok2->link();
|
||||
|
@ -1403,9 +1430,9 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateFunction(const Token *to
|
|||
if (Token::Match(tok->next(), ";|{"))
|
||||
return false;
|
||||
// skip decltype(...)
|
||||
else if (Token::simpleMatch(tok, "decltype (")) {
|
||||
const Token * end = tok->linkAt(1);
|
||||
while (tok && tok != end) {
|
||||
else if (Token::simpleMatch(tok->next(), "decltype (")) {
|
||||
const Token * end = tok->linkAt(2)->previous();
|
||||
while (tok && tok->next() && tok != end) {
|
||||
tok = tok->next();
|
||||
namepos++;
|
||||
}
|
||||
|
@ -1863,6 +1890,7 @@ void TemplateSimplifier::expandTemplate(
|
|||
if (tok5)
|
||||
tok5 = tok5->next();
|
||||
// copy return type
|
||||
std::stack<Token *> brackets2; // holds "(" and "{" tokens
|
||||
while (tok5 && tok5 != tok3) {
|
||||
// replace name if found
|
||||
if (Token::Match(tok5, "%name% <") && tok5->str() == templateInstantiation.name) {
|
||||
|
@ -1924,8 +1952,28 @@ void TemplateSimplifier::expandTemplate(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!added)
|
||||
if (!added) {
|
||||
mTokenList.addtoken(tok5, tok5->linenr(), tok5->fileIndex());
|
||||
Token *back = mTokenList.back();
|
||||
if (Token::Match(back, "{|(|[")) {
|
||||
brackets2.push(back);
|
||||
} else if (back->str() == "}") {
|
||||
assert(brackets2.empty() == false);
|
||||
assert(brackets2.top()->str() == "{");
|
||||
Token::createMutualLinks(brackets2.top(), back);
|
||||
brackets2.pop();
|
||||
} else if (back->str() == ")") {
|
||||
assert(brackets2.empty() == false);
|
||||
assert(brackets2.top()->str() == "(");
|
||||
Token::createMutualLinks(brackets2.top(), back);
|
||||
brackets2.pop();
|
||||
} else if (back->str() == "]") {
|
||||
assert(brackets2.empty() == false);
|
||||
assert(brackets2.top()->str() == "[");
|
||||
Token::createMutualLinks(brackets2.top(), back);
|
||||
brackets2.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tok5 = tok5->next();
|
||||
|
|
|
@ -111,7 +111,7 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end
|
|||
tok = tok->linkAt(1)->next();
|
||||
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
|
||||
tok = tok->linkAt(1)->next();
|
||||
if (tok && tok->str() == ".") { // trailing return type
|
||||
if (tok && tok->originalName() == "->") { // trailing return type
|
||||
for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
|
||||
if (tok->link() && Token::Match(tok, "<|[|("))
|
||||
tok = tok->link();
|
||||
|
|
|
@ -1592,7 +1592,6 @@ private:
|
|||
void garbageCode203() { // #8972
|
||||
checkCode("{ > () {} }");
|
||||
checkCode("template <> a > ::b();");
|
||||
ASSERT_THROW(checkCode("{ template <a> class b { } template <> template <c> c() b<a>::e() { } template b<d>; }"), InternalError);
|
||||
}
|
||||
|
||||
void garbageCode204() {
|
||||
|
|
|
@ -164,6 +164,7 @@ private:
|
|||
TEST_CASE(template124); // #9197
|
||||
TEST_CASE(template125);
|
||||
TEST_CASE(template126); // #9217
|
||||
TEST_CASE(template127); // #9225
|
||||
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)
|
||||
|
@ -2943,6 +2944,96 @@ private:
|
|||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template127() { // #9225
|
||||
{
|
||||
const char code[] = "template <typename> struct a {\n"
|
||||
" template <typename b> constexpr decltype(auto) operator()(b &&) const;\n"
|
||||
"};\n"
|
||||
"a<int> c;\n"
|
||||
"template <typename d>\n"
|
||||
"template <typename b>\n"
|
||||
"constexpr decltype(auto) a<d>::operator()(b &&) const {}";
|
||||
const char exp[] = "struct a<int> ; "
|
||||
"a<int> c ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } "
|
||||
"struct a<int> { "
|
||||
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; "
|
||||
"} ;";
|
||||
const char act[] = "struct a<int> ; "
|
||||
"a<int> c ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"const decltype ( auto ) a < d > :: operator() ( b & & ) const { } "
|
||||
"struct a<int> { "
|
||||
"template < typename b > const decltype ( auto ) operator() ( b & & ) const ; "
|
||||
"} ; "
|
||||
"const decltype ( auto ) a<int> :: operator() ( b & & ) const { }";
|
||||
TODO_ASSERT_EQUALS(exp, act, tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "template <typename> struct a {\n"
|
||||
" template <typename b> static void foo();\n"
|
||||
"};\n"
|
||||
"a<int> c;\n"
|
||||
"template <typename d>\n"
|
||||
"template <typename b>\n"
|
||||
"void a<d>::foo() {}\n"
|
||||
"void bar() { a<int>::foo<char>(); }";
|
||||
const char exp[] = "struct a<int> ; "
|
||||
"a<int> c ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"void a < d > :: foo ( ) { } "
|
||||
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
|
||||
"struct a<int> { "
|
||||
"template < typename b > static void foo ( ) ; "
|
||||
"static void foo<char> ( ) ; "
|
||||
"} ; "
|
||||
"void a<int> :: foo<char> ( ) { }";
|
||||
const char act[] = "struct a<int> ; "
|
||||
"a<int> c ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"void a < d > :: foo ( ) { } "
|
||||
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
|
||||
"struct a<int> { "
|
||||
"template < typename b > static void foo ( ) ; "
|
||||
"} ; "
|
||||
"void a<int> :: foo ( ) { }";
|
||||
TODO_ASSERT_EQUALS(exp, act, tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "template <typename> struct a {\n"
|
||||
" template <typename b> static void foo();\n"
|
||||
"};\n"
|
||||
"template <typename d>\n"
|
||||
"template <typename b>\n"
|
||||
"void a<d>::foo() {}\n"
|
||||
"void bar() { a<int>::foo<char>(); }";
|
||||
const char exp[] = "struct a<int> ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"void a < d > :: foo ( ) { } "
|
||||
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
|
||||
"struct a<int> { "
|
||||
"static void foo<char> ( ) ; "
|
||||
"} ; "
|
||||
"void a<int> :: foo<char> ( ) { }";
|
||||
const char act[] = "struct a<int> ; "
|
||||
"template < typename d > "
|
||||
"template < typename b > "
|
||||
"void a < d > :: foo ( ) { } "
|
||||
"void bar ( ) { a<int> :: foo < char > ( ) ; } "
|
||||
"struct a<int> { "
|
||||
"template < typename b > static void foo ( ) ; "
|
||||
"} ; "
|
||||
"void a<int> :: foo ( ) { }";
|
||||
TODO_ASSERT_EQUALS(exp, act, 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"
|
||||
|
|
Loading…
Reference in New Issue