From ffe6a0be2baadcaf992d6b04fcdca49e2f5aac64 Mon Sep 17 00:00:00 2001 From: Simon Martin Date: Sat, 3 May 2014 16:26:14 +0200 Subject: [PATCH] Ticket #5605: Don't consider '>' as a default template parameter value. Don't choke on template parameters with erroneous default values. --- lib/templatesimplifier.cpp | 34 +++++++++++++++++++++++++++++----- test/testsimplifytokens.cpp | 4 ++-- test/testtokenize.cpp | 8 ++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lib/templatesimplifier.cpp b/lib/templatesimplifier.cpp index 021152220..9dccd529a 100644 --- a/lib/templatesimplifier.cpp +++ b/lib/templatesimplifier.cpp @@ -240,6 +240,12 @@ 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(); @@ -508,20 +514,31 @@ 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 (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 @@ -529,8 +546,15 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list &temp ++templatepar; // default parameter value - else if (tok->str() == "=") - eq.push_back(tok); + 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 ce099eedb..413769b91 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -416,6 +416,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); @@ -6497,6 +6498,13 @@ private: tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault } + void syntax_error_templates_3() { // Ticket #5605 + 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 }"); + } + void removeKeywords() { const char code[] = "if (__builtin_expect(!!(x), 1));";