template simplifier: specialized member class not recognized causing wrong instantiation (#1876)
Specialized member classes declared outsize the class were not recognized. This caused the the member class to be instantiated rather than the specialized class. We already had a test for this but it was wrong so it went unnoticed.
This commit is contained in:
parent
1f24aa778b
commit
5af8beecf6
|
@ -89,7 +89,7 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
|
||||||
throw InternalError(tok, "explicit specialization of alias templates is not permitted", InternalError::SYNTAX);
|
throw InternalError(tok, "explicit specialization of alias templates is not permitted", InternalError::SYNTAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:|;"));
|
isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:|;|::"));
|
||||||
if (token->strAt(1) == "<" && !isSpecialization()) {
|
if (token->strAt(1) == "<" && !isSpecialization()) {
|
||||||
const Token *end = token->next()->findClosingBracket();
|
const Token *end = token->next()->findClosingBracket();
|
||||||
isVariadic(end && Token::findmatch(token->tokAt(2), "typename|class . . .", end));
|
isVariadic(end && Token::findmatch(token->tokAt(2), "typename|class . . .", end));
|
||||||
|
@ -113,8 +113,8 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
|
||||||
if (tok1)
|
if (tok1)
|
||||||
isForwardDeclaration(tok1->str() == ";");
|
isForwardDeclaration(tok1->str() == ";");
|
||||||
}
|
}
|
||||||
// check for member function and adjust scope
|
// check for member class or function and adjust scope
|
||||||
if (isFunction() && nameToken->strAt(-1) == "::") {
|
if ((isFunction() || isClass()) && nameToken->strAt(-1) == "::") {
|
||||||
const Token * start = nameToken;
|
const Token * start = nameToken;
|
||||||
|
|
||||||
while (Token::Match(start->tokAt(-2), "%name% ::") ||
|
while (Token::Match(start->tokAt(-2), "%name% ::") ||
|
||||||
|
@ -1397,16 +1397,48 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateVariable(const Token *to
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TemplateSimplifier::getTemplateNamePositionTemplateClass(const Token *tok, int &namepos)
|
||||||
|
{
|
||||||
|
if (Token::Match(tok, "> class|struct|union %type% :|<|;|{|::")) {
|
||||||
|
namepos = 2;
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
while (Token::Match(tok, "%type% :: %type%") ||
|
||||||
|
(Token::Match(tok, "%type% <") && Token::Match(tok->next()->findClosingBracket(), "> :: %type%"))) {
|
||||||
|
if (tok->strAt(1) == "::") {
|
||||||
|
tok = tok->tokAt(2);
|
||||||
|
namepos += 2;
|
||||||
|
} else {
|
||||||
|
const Token *end = tok->next()->findClosingBracket();
|
||||||
|
if (!end || !end->tokAt(2)) {
|
||||||
|
// syntax error
|
||||||
|
namepos = -1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
end = end->tokAt(2);
|
||||||
|
do {
|
||||||
|
tok = tok->next();
|
||||||
|
namepos += 1;
|
||||||
|
} while (tok && tok != end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
int TemplateSimplifier::getTemplateNamePosition(const Token *tok)
|
||||||
{
|
{
|
||||||
|
// FIXME: tok == ">>" is a tokenizer bug that needs to be fixed
|
||||||
|
assert(tok && (tok->str() == ">" || tok->str() == ">>"));
|
||||||
|
|
||||||
auto it = mTemplateNamePos.find(tok);
|
auto it = mTemplateNamePos.find(tok);
|
||||||
if (!mSettings->debugtemplate && it != mTemplateNamePos.end()) {
|
if (!mSettings->debugtemplate && it != mTemplateNamePos.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
// get the position of the template name
|
// get the position of the template name
|
||||||
int namepos = 0;
|
int namepos = 0;
|
||||||
if (Token::Match(tok, "> class|struct|union %type% :|<|;|{"))
|
if (getTemplateNamePositionTemplateClass(tok, namepos))
|
||||||
namepos = 2;
|
;
|
||||||
else if (Token::Match(tok, "> using %name% ="))
|
else if (Token::Match(tok, "> using %name% ="))
|
||||||
namepos = 2;
|
namepos = 2;
|
||||||
else if (getTemplateNamePositionTemplateVariable(tok, namepos))
|
else if (getTemplateNamePositionTemplateVariable(tok, namepos))
|
||||||
|
@ -1500,7 +1532,9 @@ void TemplateSimplifier::expandTemplate(
|
||||||
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
|
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
|
||||||
templateDeclaration.token->insertToken(newName, "", true);
|
templateDeclaration.token->insertToken(newName, "", true);
|
||||||
templateDeclaration.token->insertToken(";", "", true);
|
templateDeclaration.token->insertToken(";", "", true);
|
||||||
} else if ((isFunction && (copy || isSpecialization)) || (isVariable && !isSpecialization)) {
|
} else if ((isFunction && (copy || isSpecialization)) ||
|
||||||
|
(isVariable && !isSpecialization) ||
|
||||||
|
(isClass && isSpecialization && mTemplateSpecializationMap.find(templateDeclaration.token) != mTemplateSpecializationMap.end())) {
|
||||||
Token * dst = templateDeclaration.token;
|
Token * dst = templateDeclaration.token;
|
||||||
Token * dstStart = dst->previous();
|
Token * dstStart = dst->previous();
|
||||||
bool isStatic = false;
|
bool isStatic = false;
|
||||||
|
|
|
@ -240,11 +240,19 @@ public:
|
||||||
int getTemplateNamePosition(const Token *tok);
|
int getTemplateNamePosition(const Token *tok);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get function template name position
|
* Get class template name position
|
||||||
* @param tok The ">" token e.g. before "class"
|
* @param tok The ">" token e.g. before "class"
|
||||||
* @param namepos return offset to name
|
* @param namepos return offset to name
|
||||||
* @return true if name found, false if not
|
* @return true if name found, false if not
|
||||||
* */
|
* */
|
||||||
|
static bool getTemplateNamePositionTemplateClass(const Token *tok, int &namepos);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get function template name position
|
||||||
|
* @param tok The ">" token
|
||||||
|
* @param namepos return offset to name
|
||||||
|
* @return true if name found, false if not
|
||||||
|
* */
|
||||||
static bool getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos);
|
static bool getTemplateNamePositionTemplateFunction(const Token *tok, int &namepos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -976,7 +976,12 @@ private:
|
||||||
" template<typename T> struct X { T t; };"
|
" template<typename T> struct X { T t; };"
|
||||||
"};"
|
"};"
|
||||||
"template<> struct A::X<int> { int *t; };";
|
"template<> struct A::X<int> { int *t; };";
|
||||||
ASSERT_EQUALS("struct A { struct X<int> ; } ; struct A :: X<int> { int t ; } ;", tok(code));
|
const char expected[] = "struct A { "
|
||||||
|
"struct X<int> ; "
|
||||||
|
"template < typename T > struct X { T t ; } ; "
|
||||||
|
"} ; "
|
||||||
|
"struct A :: X<int> { int * t ; } ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
void template41() { // #4710 - const in template instantiation not handled perfectly
|
void template41() { // #4710 - const in template instantiation not handled perfectly
|
||||||
|
@ -1021,6 +1026,7 @@ private:
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"}";
|
"}";
|
||||||
const char expected[] = "struct E<void*> ; "
|
const char expected[] = "struct E<void*> ; "
|
||||||
|
"struct C<B<A>> ; "
|
||||||
"struct C<A> ; "
|
"struct C<A> ; "
|
||||||
"struct D<B<A>> ; "
|
"struct D<B<A>> ; "
|
||||||
"int f2<B<A>> ( ) ; "
|
"int f2<B<A>> ( ) ; "
|
||||||
|
@ -1215,7 +1221,8 @@ private:
|
||||||
" enum { value = 1 }; "
|
" enum { value = 1 }; "
|
||||||
"};"
|
"};"
|
||||||
"const int x = Factorial<4>::value;";
|
"const int x = Factorial<4>::value;";
|
||||||
const char expected[] = "struct Factorial<4> ; "
|
const char expected[] = "struct Factorial<0> ; "
|
||||||
|
"struct Factorial<4> ; "
|
||||||
"struct Factorial<3> ; "
|
"struct Factorial<3> ; "
|
||||||
"struct Factorial<2> ; "
|
"struct Factorial<2> ; "
|
||||||
"struct Factorial<1> ; "
|
"struct Factorial<1> ; "
|
||||||
|
@ -1342,7 +1349,8 @@ private:
|
||||||
"int main () {\n"
|
"int main () {\n"
|
||||||
" return diagonalGroupTest<4>();\n"
|
" return diagonalGroupTest<4>();\n"
|
||||||
"}";
|
"}";
|
||||||
const char exp[] = "struct Factorial<4> ; "
|
const char exp[] = "struct Factorial<0> ; "
|
||||||
|
"struct Factorial<4> ; "
|
||||||
"struct Factorial<3> ; "
|
"struct Factorial<3> ; "
|
||||||
"struct Factorial<2> ; "
|
"struct Factorial<2> ; "
|
||||||
"struct Factorial<1> ; "
|
"struct Factorial<1> ; "
|
||||||
|
@ -1576,13 +1584,22 @@ private:
|
||||||
" void foo() { }\n"
|
" void foo() { }\n"
|
||||||
"};";
|
"};";
|
||||||
const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
const char exp [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
||||||
|
"class Bar<void,void> ; "
|
||||||
"class Bar<void,void> { "
|
"class Bar<void,void> { "
|
||||||
"} ; "
|
"} ; "
|
||||||
"template < typename K , typename V , int KeySize = 0 > "
|
"template < typename K , typename V , int KeySize = 0 > "
|
||||||
"class Bar : private Bar<void,void> { "
|
"class Bar : private Bar<void,void> { "
|
||||||
"void foo ( ) { } "
|
"void foo ( ) { } "
|
||||||
"} ;";
|
"} ;";
|
||||||
ASSERT_EQUALS(exp, tok(code));
|
const char act [] = "template < typename T , typename V , int KeySize = 0 > class Bar ; "
|
||||||
|
"class Bar<void,void> { "
|
||||||
|
"} ; "
|
||||||
|
"class Bar<void,void> ; "
|
||||||
|
"template < typename K , typename V , int KeySize = 0 > "
|
||||||
|
"class Bar : private Bar<void,void> { "
|
||||||
|
"void foo ( ) { } "
|
||||||
|
"} ;";
|
||||||
|
TODO_ASSERT_EQUALS(exp, act, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
void template71() { // #8821
|
void template71() { // #8821
|
||||||
|
@ -1679,7 +1696,8 @@ private:
|
||||||
" std::cout << is_void<char>::value << std::endl;\n"
|
" std::cout << is_void<char>::value << std::endl;\n"
|
||||||
" std::cout << is_void<void>::value << std::endl;\n"
|
" std::cout << is_void<void>::value << std::endl;\n"
|
||||||
"}";
|
"}";
|
||||||
const char exp[] = "struct is_void<char> ; "
|
const char exp[] = "struct is_void<void> ; "
|
||||||
|
"struct is_void<char> ; "
|
||||||
"struct is_void<void> : std :: true_type { } ; "
|
"struct is_void<void> : std :: true_type { } ; "
|
||||||
"int main ( ) { "
|
"int main ( ) { "
|
||||||
"std :: cout << is_void<char> :: value << std :: endl ; "
|
"std :: cout << is_void<char> :: value << std :: endl ; "
|
||||||
|
@ -2846,7 +2864,8 @@ private:
|
||||||
" b.A<>::Print();\n"
|
" b.A<>::Print();\n"
|
||||||
" return 0;\n"
|
" return 0;\n"
|
||||||
"}";
|
"}";
|
||||||
ASSERT_EQUALS("template < typename T0 > class A ; "
|
ASSERT_EQUALS("class A<void> ; "
|
||||||
|
"template < typename T0 > class A ; "
|
||||||
"class A<void> { "
|
"class A<void> { "
|
||||||
"public: "
|
"public: "
|
||||||
"A<void> ( ) { } "
|
"A<void> ( ) { } "
|
||||||
|
@ -3261,6 +3280,7 @@ private:
|
||||||
"template class Fred<1>;\n"
|
"template class Fred<1>;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
ASSERT_EQUALS("namespace NS { "
|
ASSERT_EQUALS("namespace NS { "
|
||||||
|
"struct Barney<1> ; "
|
||||||
"template < int type > struct Barney ; "
|
"template < int type > struct Barney ; "
|
||||||
"struct Barney<1> { } ; "
|
"struct Barney<1> { } ; "
|
||||||
"class Fred<1> ; "
|
"class Fred<1> ; "
|
||||||
|
@ -3577,7 +3597,8 @@ private:
|
||||||
const char code[] = "template<typename T> class C { };\n"
|
const char code[] = "template<typename T> class C { };\n"
|
||||||
"template<> class C<char> { };\n"
|
"template<> class C<char> { };\n"
|
||||||
"map<int> m;\n";
|
"map<int> m;\n";
|
||||||
const char expected[] = "template < typename T > class C { } ; "
|
const char expected[] = "class C<char> ; "
|
||||||
|
"template < typename T > class C { } ; "
|
||||||
"class C<char> { } ; "
|
"class C<char> { } ; "
|
||||||
"map < int > m ;";
|
"map < int > m ;";
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
@ -3587,7 +3608,8 @@ private:
|
||||||
"template<> class C<char> { };\n"
|
"template<> class C<char> { };\n"
|
||||||
"map<int> m;\n"
|
"map<int> m;\n"
|
||||||
"C<int> i;";
|
"C<int> i;";
|
||||||
const char expected[] = "class C<int> ; "
|
const char expected[] = "class C<char> ; "
|
||||||
|
"class C<int> ; "
|
||||||
"class C<char> { } ; "
|
"class C<char> { } ; "
|
||||||
"map < int > m ; "
|
"map < int > m ; "
|
||||||
"C<int> i ; "
|
"C<int> i ; "
|
||||||
|
@ -3600,7 +3622,8 @@ private:
|
||||||
"map<int> m;\n"
|
"map<int> m;\n"
|
||||||
"C<int> i;\n"
|
"C<int> i;\n"
|
||||||
"C<char> c;";
|
"C<char> c;";
|
||||||
const char expected[] = "class C<int> ; "
|
const char expected[] = "class C<char> ; "
|
||||||
|
"class C<int> ; "
|
||||||
"class C<char> { } ; "
|
"class C<char> { } ; "
|
||||||
"map < int > m ; "
|
"map < int > m ; "
|
||||||
"C<int> i ; "
|
"C<int> i ; "
|
||||||
|
|
Loading…
Reference in New Issue