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);
|
||||
}
|
||||
|
||||
isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:|;"));
|
||||
isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:|;|::"));
|
||||
if (token->strAt(1) == "<" && !isSpecialization()) {
|
||||
const Token *end = token->next()->findClosingBracket();
|
||||
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)
|
||||
isForwardDeclaration(tok1->str() == ";");
|
||||
}
|
||||
// check for member function and adjust scope
|
||||
if (isFunction() && nameToken->strAt(-1) == "::") {
|
||||
// check for member class or function and adjust scope
|
||||
if ((isFunction() || isClass()) && nameToken->strAt(-1) == "::") {
|
||||
const Token * start = nameToken;
|
||||
|
||||
while (Token::Match(start->tokAt(-2), "%name% ::") ||
|
||||
|
@ -1397,16 +1397,48 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateVariable(const Token *to
|
|||
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)
|
||||
{
|
||||
// FIXME: tok == ">>" is a tokenizer bug that needs to be fixed
|
||||
assert(tok && (tok->str() == ">" || tok->str() == ">>"));
|
||||
|
||||
auto it = mTemplateNamePos.find(tok);
|
||||
if (!mSettings->debugtemplate && it != mTemplateNamePos.end()) {
|
||||
return it->second;
|
||||
}
|
||||
// get the position of the template name
|
||||
int namepos = 0;
|
||||
if (Token::Match(tok, "> class|struct|union %type% :|<|;|{"))
|
||||
namepos = 2;
|
||||
if (getTemplateNamePositionTemplateClass(tok, namepos))
|
||||
;
|
||||
else if (Token::Match(tok, "> using %name% ="))
|
||||
namepos = 2;
|
||||
else if (getTemplateNamePositionTemplateVariable(tok, namepos))
|
||||
|
@ -1500,7 +1532,9 @@ void TemplateSimplifier::expandTemplate(
|
|||
templateDeclaration.token->insertToken(templateDeclarationToken->strAt(1), "", true);
|
||||
templateDeclaration.token->insertToken(newName, "", 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 * dstStart = dst->previous();
|
||||
bool isStatic = false;
|
||||
|
|
|
@ -240,11 +240,19 @@ public:
|
|||
int getTemplateNamePosition(const Token *tok);
|
||||
|
||||
/**
|
||||
* Get function template name position
|
||||
* Get class template name position
|
||||
* @param tok The ">" token e.g. before "class"
|
||||
* @param namepos return offset to name
|
||||
* @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);
|
||||
|
||||
/**
|
||||
|
|
|
@ -976,7 +976,12 @@ private:
|
|||
" template<typename T> struct X { T 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
|
||||
|
@ -1021,6 +1026,7 @@ private:
|
|||
" return 0;\n"
|
||||
"}";
|
||||
const char expected[] = "struct E<void*> ; "
|
||||
"struct C<B<A>> ; "
|
||||
"struct C<A> ; "
|
||||
"struct D<B<A>> ; "
|
||||
"int f2<B<A>> ( ) ; "
|
||||
|
@ -1215,7 +1221,8 @@ private:
|
|||
" enum { value = 1 }; "
|
||||
"};"
|
||||
"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<2> ; "
|
||||
"struct Factorial<1> ; "
|
||||
|
@ -1342,7 +1349,8 @@ private:
|
|||
"int main () {\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<2> ; "
|
||||
"struct Factorial<1> ; "
|
||||
|
@ -1576,13 +1584,22 @@ private:
|
|||
" void foo() { }\n"
|
||||
"};";
|
||||
const char exp [] = "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 ( ) { } "
|
||||
"} ;";
|
||||
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
|
||||
|
@ -1679,7 +1696,8 @@ private:
|
|||
" std::cout << is_void<char>::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 { } ; "
|
||||
"int main ( ) { "
|
||||
"std :: cout << is_void<char> :: value << std :: endl ; "
|
||||
|
@ -2846,7 +2864,8 @@ private:
|
|||
" b.A<>::Print();\n"
|
||||
" return 0;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS("template < typename T0 > class A ; "
|
||||
ASSERT_EQUALS("class A<void> ; "
|
||||
"template < typename T0 > class A ; "
|
||||
"class A<void> { "
|
||||
"public: "
|
||||
"A<void> ( ) { } "
|
||||
|
@ -3261,6 +3280,7 @@ private:
|
|||
"template class Fred<1>;\n"
|
||||
"}\n";
|
||||
ASSERT_EQUALS("namespace NS { "
|
||||
"struct Barney<1> ; "
|
||||
"template < int type > struct Barney ; "
|
||||
"struct Barney<1> { } ; "
|
||||
"class Fred<1> ; "
|
||||
|
@ -3577,7 +3597,8 @@ private:
|
|||
const char code[] = "template<typename T> class C { };\n"
|
||||
"template<> class C<char> { };\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> { } ; "
|
||||
"map < int > m ;";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
|
@ -3587,7 +3608,8 @@ private:
|
|||
"template<> class C<char> { };\n"
|
||||
"map<int> m;\n"
|
||||
"C<int> i;";
|
||||
const char expected[] = "class C<int> ; "
|
||||
const char expected[] = "class C<char> ; "
|
||||
"class C<int> ; "
|
||||
"class C<char> { } ; "
|
||||
"map < int > m ; "
|
||||
"C<int> i ; "
|
||||
|
@ -3600,7 +3622,8 @@ private:
|
|||
"map<int> m;\n"
|
||||
"C<int> i;\n"
|
||||
"C<char> c;";
|
||||
const char expected[] = "class C<int> ; "
|
||||
const char expected[] = "class C<char> ; "
|
||||
"class C<int> ; "
|
||||
"class C<char> { } ; "
|
||||
"map < int > m ; "
|
||||
"C<int> i ; "
|
||||
|
|
Loading…
Reference in New Issue