Ticket #5605: Don't consider '>' as a default template parameter value. Don't choke on template parameters with erroneous default values.
Ticket #5759: Properly handle pointers to class members in template parameter lists. Ticket #5762: Handle template specialization tokens.
This commit is contained in:
parent
4710c5c4f1
commit
2a6acdf357
|
@ -240,11 +240,20 @@ 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();
|
||||||
while (Token::Match(tok, "%var% ::"))
|
while (Token::Match(tok, "%var% ::")) {
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
|
if (tok->str() == "*") // Ticket #5759: Class member pointer as a template argument; skip '*'
|
||||||
|
tok = tok->next();
|
||||||
|
}
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -508,29 +517,51 @@ 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 (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
if (tok->str() == ",")
|
if (tok->str() == ",")
|
||||||
++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;
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,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);
|
||||||
|
|
||||||
|
@ -6503,6 +6504,20 @@ private:
|
||||||
tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault
|
tokenizer.tokenize(istr, "test.cpp"); // shouldn't segfault
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void syntax_error_templates_3() { // Ticket #5605, #5759, #5762
|
||||||
|
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> }");
|
||||||
|
tokenizeAndStringify("struct S { int i, j; }; "
|
||||||
|
"template<int S::*p, typename U> struct X {}; "
|
||||||
|
"X<&S::i, int> x = X<&S::i, int>(); "
|
||||||
|
"X<&S::j, int> y = X<&S::j, int>(); ");
|
||||||
|
tokenizeAndStringify("template <typename T> struct A {}; "
|
||||||
|
"template <> struct A<void> {}; "
|
||||||
|
"void foo(const void* f = 0) {}");
|
||||||
|
}
|
||||||
|
|
||||||
void removeKeywords() {
|
void removeKeywords() {
|
||||||
const char code[] = "if (__builtin_expect(!!(x), 1));";
|
const char code[] = "if (__builtin_expect(!!(x), 1));";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue