Ticket #5605: Don't consider '>' as a default template parameter value. Don't choke on template parameters with erroneous default values.

This commit is contained in:
Simon Martin 2014-05-03 16:26:14 +02:00
parent b363d0641a
commit ffe6a0be2b
3 changed files with 39 additions and 7 deletions

View File

@ -240,6 +240,12 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
if (Token::Match(tok, "& ::| %var%")) if (Token::Match(tok, "& ::| %var%"))
tok = tok->next(); tok = tok->next();
// Skip '='
if (Token::Match(tok, "="))
tok = tok->next();
if (!tok)
return 0;
// skip std:: // skip std::
if (tok && tok->str() == "::") if (tok && tok->str() == "::")
tok = tok->next(); tok = tok->next();
@ -508,20 +514,31 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<Token *> &temp
// x = y // x = y
// this list will contain all the '=' tokens for such arguments // this list will contain all the '=' tokens for such arguments
std::list<Token *> eq; std::list<Token *> eq;
// and this set the position of parameters with a default value
std::set<std::size_t> defaultedArgPos;
// parameter number. 1,2,3,.. // parameter number. 1,2,3,..
std::size_t templatepar = 1; std::size_t templatepar = 1;
// parameter depth
std::size_t templateParmDepth = 0;
// the template classname. This will be empty for template functions // the template classname. This will be empty for template functions
std::string classname; std::string classname;
// Scan template declaration.. // Scan template declaration..
for (Token *tok = *iter1; tok; tok = tok->next()) { for (Token *tok = *iter1; tok; tok = tok->next()) {
if (tok->str() == "<" && templateParameters(tok))
++templateParmDepth;
// end of template parameters? // end of template parameters?
if (tok->str() == ">") { if (tok->str() == ">" || tok->str() == ">>") {
if (Token::Match(tok, "> class|struct %var%")) if (Token::Match(tok, ">|>> class|struct %var%"))
classname = tok->strAt(2); classname = tok->strAt(2);
break; templateParmDepth -= (1 + (tok->str() == ">>"));
if(0 == templateParmDepth)
break;
} }
// next template parameter // next template parameter
@ -529,8 +546,15 @@ void TemplateSimplifier::useDefaultArgumentValues(const std::list<Token *> &temp
++templatepar; ++templatepar;
// default parameter value // default parameter value
else if (tok->str() == "=") else if (Token::Match(tok, "= !!>")) {
eq.push_back(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()) if (eq.empty() || classname.empty())
continue; continue;

View File

@ -2461,10 +2461,10 @@ private:
} }
{ {
const char code[] = "template<class T, class T2 = A<T>> class B {};\n" const char code[] = "template<class T, class T2 = A<T>> class B {};\n"
"template<class B = A, typename C = C<B>> class C;\n" "template<class B = A, typename C = C<B>> class C {};\n"
"template<class B, typename C> class D { };\n"; "template<class B, typename C> class D { };\n";
ASSERT_EQUALS("template < class T , class T2 > class B { } ; " 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)); "template < class B , typename C > class D { } ;", tok(code));
} }
} }

View File

@ -416,6 +416,7 @@ private:
TEST_CASE(syntax_error); TEST_CASE(syntax_error);
TEST_CASE(syntax_error_templates_1); TEST_CASE(syntax_error_templates_1);
TEST_CASE(syntax_error_templates_2); TEST_CASE(syntax_error_templates_2);
TEST_CASE(syntax_error_templates_3); // Ticket #5605 - invalid template declaration
TEST_CASE(removeKeywords); TEST_CASE(removeKeywords);
@ -6497,6 +6498,13 @@ private:
tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault
} }
void syntax_error_templates_3() { // Ticket #5605
tokenizeAndStringify("foo() template<typename T1 = T2 = typename = unused, T5 = = unused> struct tuple Args> tuple<Args...> { } main() { foo<int,int,int,int,int,int>(); }");
tokenizeAndStringify("( ) template < T1 = typename = unused> struct Args { } main ( ) { foo < int > ( ) ; }");
tokenizeAndStringify("() template < T = typename = x > struct a {} { f <int> () }");
tokenizeAndStringify("template < T = typename = > struct a { f <int> }");
}
void removeKeywords() { void removeKeywords() {
const char code[] = "if (__builtin_expect(!!(x), 1));"; const char code[] = "if (__builtin_expect(!!(x), 1));";