diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 021152220..22d66674f 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -240,11 +240,20 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok) if (Token::Match(tok, "& ::| %var%")) tok = tok->next(); + // Skip '=' + if (Token::Match(tok, "=")) + tok = tok->next(); + if (!tok) + return 0; + // skip std:: if (tok && tok->str() == "::") tok = tok->next(); - while (Token::Match(tok, "%var% ::")) + while (Token::Match(tok, "%var% ::")) { tok = tok->tokAt(2); + if (tok->str() == "*") // Ticket #5759: Class member pointer as a template argument; skip '*' + tok = tok->next(); + } if (!tok) return 0; @@ -508,29 +517,51 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp // x = y // this list will contain all the '=' tokens for such arguments std::list eq; + // and this set the position of parameters with a default value + std::set defaultedArgPos; // parameter number. 1,2,3,.. std::size_t templatepar = 1; + // parameter depth + std::size_t templateParmDepth = 0; + // the template classname. This will be empty for template functions std::string classname; // Scan template declaration.. for (Token *tok = *iter1; tok; tok = tok->next()) { + if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens + tok = tok->tokAt(2); + continue; + } + + if (tok->str() == "<" && templateParameters(tok)) + ++templateParmDepth; + // end of template parameters? - if (tok->str() == ">") { - if (Token::Match(tok, "> class|struct %var%")) + if (tok->str() == ">" || tok->str() == ">>") { + if (Token::Match(tok, ">|>> class|struct %var%")) classname = tok->strAt(2); - break; + templateParmDepth -= (1 + (tok->str() == ">>")); + if (0 == templateParmDepth) + break; } // next template parameter if (tok->str() == ",") ++templatepar; - // default parameter value - else if (tok->str() == "=") - eq.push_back(tok); + // default parameter value? + else if (Token::Match(tok, "= !!>")) { + if (defaultedArgPos.insert(templatepar).second) { + eq.push_back(tok); + } else { + // Ticket #5605: Syntax error (two equal signs for the same parameter), bail out + eq.clear(); + break; + } + } } if (eq.empty() || classname.empty()) continue; diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 46cb6f4c3..d24e7d3a5 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2461,10 +2461,10 @@ private: } { const char code[] = "template> class B {};\n" - "template> class C;\n" + "template> class C {};\n" "template class D { };\n"; ASSERT_EQUALS("template < class T , class T2 > class B { } ; " - "template < class B , typename C > class C ; " + "template < class B , typename C > class C { } ; " "template < class B , typename C > class D { } ;", tok(code)); } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 064f70638..5676a13a6 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -417,6 +417,7 @@ private: TEST_CASE(syntax_error); TEST_CASE(syntax_error_templates_1); TEST_CASE(syntax_error_templates_2); + TEST_CASE(syntax_error_templates_3); // Ticket #5605 - invalid template declaration TEST_CASE(removeKeywords); @@ -6503,6 +6504,20 @@ private: tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault } + void syntax_error_templates_3() { // Ticket #5605, #5759, #5762 + tokenizeAndStringify("foo() template struct tuple Args> tuple { } main() { foo(); }"); + tokenizeAndStringify("( ) template < T1 = typename = unused> struct Args { } main ( ) { foo < int > ( ) ; }"); + tokenizeAndStringify("() template < T = typename = x > struct a {} { f () }"); + tokenizeAndStringify("template < T = typename = > struct a { f }"); + tokenizeAndStringify("struct S { int i, j; }; " + "template struct X {}; " + "X<&S::i, int> x = X<&S::i, int>(); " + "X<&S::j, int> y = X<&S::j, int>(); "); + tokenizeAndStringify("template struct A {}; " + "template <> struct A {}; " + "void foo(const void* f = 0) {}"); + } + void removeKeywords() { const char code[] = "if (__builtin_expect(!!(x), 1));";