template simplifier: various small fixes (#1916)
* fix adding instantiation of first argument to an instantiation * add support for function pointer template variables * fix more cases where templates ending in ">>" are changed to end in "> >" * fix travis build * standard types can't be a template parameter name * remove redundant level == 0 checks * fix lambda in template variable * fix a test
This commit is contained in:
parent
ec4e43767e
commit
16788df055
|
@ -206,6 +206,26 @@ TemplateSimplifier::~TemplateSimplifier()
|
|||
{
|
||||
}
|
||||
|
||||
void TemplateSimplifier::fixAngleBrackets()
|
||||
{
|
||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||
// Ticket #6181: normalize C++11 template parameter list closing syntax
|
||||
if (tok->str() == "<" && templateParameters(tok)) {
|
||||
Token *endTok = tok->findClosingBracket();
|
||||
if (endTok && endTok->str() == ">>") {
|
||||
endTok->str(">");
|
||||
endTok->insertToken(">");
|
||||
}
|
||||
} else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <")) {
|
||||
Token *endTok = tok->tokAt(2)->findClosingBracket();
|
||||
if (Token::Match(endTok, ">> ;|{")) {
|
||||
endTok->str(">");
|
||||
endTok->insertToken(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateSimplifier::cleanupAfterSimplify()
|
||||
{
|
||||
bool goback = false;
|
||||
|
@ -368,6 +388,8 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
|
|||
if (Token::Match(tok->previous(), "%var% <"))
|
||||
return 0;
|
||||
tok = tok->next();
|
||||
if (tok->str() == ">")
|
||||
return 0;
|
||||
|
||||
unsigned int level = 0;
|
||||
|
||||
|
@ -375,9 +397,18 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
|
|||
// skip template template
|
||||
if (level == 0 && Token::simpleMatch(tok, "template <")) {
|
||||
const Token *closing = tok->next()->findClosingBracket();
|
||||
if (closing)
|
||||
if (closing) {
|
||||
if (closing->str() == ">>")
|
||||
return numberOfParameters;
|
||||
tok = closing->next();
|
||||
else
|
||||
if (tok->str() == ">" || tok->str() == ">>")
|
||||
return numberOfParameters;
|
||||
else if (tok->str() == ",") {
|
||||
++numberOfParameters;
|
||||
tok = tok->next();
|
||||
continue;
|
||||
}
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -394,10 +425,26 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
|
|||
tok = tok->next();
|
||||
|
||||
// Skip variadic types (Ticket #5774, #6059, #6172)
|
||||
if (Token::Match(tok, "%type% . . .")) {
|
||||
tok = tok->tokAt(4);
|
||||
if (Token::simpleMatch(tok, ". . .")) {
|
||||
if ((tok->previous()->isName() && !Token::Match(tok->tokAt(-2), "<|,")) ||
|
||||
(!tok->previous()->isName() && tok->strAt(-1) != ">"))
|
||||
return 0; // syntax error
|
||||
tok = tok->tokAt(3);
|
||||
if (!tok)
|
||||
return 0;
|
||||
if (tok->str() == ">") {
|
||||
if (level == 0)
|
||||
return numberOfParameters;
|
||||
--level;
|
||||
} else if (tok->str() == ">>") {
|
||||
if (level == 1)
|
||||
return numberOfParameters;
|
||||
} else if (tok->str() == "," && level == 0) {
|
||||
++numberOfParameters;
|
||||
tok = tok->next();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip '=', '?', ':'
|
||||
if (Token::Match(tok, "=|?|:"))
|
||||
|
@ -414,6 +461,8 @@ unsigned int TemplateSimplifier::templateParameters(const Token *tok)
|
|||
return 0;
|
||||
if (tok->str() == ">" && level == 0)
|
||||
return numberOfParameters;
|
||||
else if (tok->str() == ">>" && level == 1)
|
||||
return numberOfParameters;
|
||||
else if (tok->str() == "," && level == 0) {
|
||||
++numberOfParameters;
|
||||
tok = tok->next();
|
||||
|
@ -900,8 +949,8 @@ void TemplateSimplifier::getTemplateInstantiations()
|
|||
// parse backwards and add template instantiations
|
||||
// TODO
|
||||
for (; tok2 && tok2 != tok; tok2 = tok2->previous()) {
|
||||
if (Token::Match(tok2, ", %name% <") &&
|
||||
templateParameters(tok2->tokAt(2))) {
|
||||
if (Token::Match(tok2, ",|< %name% <") &&
|
||||
(tok2->strAt(3) == ">" || templateParameters(tok2->tokAt(2)))) {
|
||||
addInstantiation(tok2->next(), getScopeName(scopeList));
|
||||
} else if (Token::Match(tok2->next(), "class|struct"))
|
||||
tok2->deleteNext();
|
||||
|
@ -1351,7 +1400,14 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateVariable(const Token *to
|
|||
while (tok && tok->next()) {
|
||||
if (Token::Match(tok->next(), ";|{|(|using"))
|
||||
return false;
|
||||
else if (Token::Match(tok->next(), "%type% <")) {
|
||||
// skip decltype(...)
|
||||
else if (Token::simpleMatch(tok->next(), "decltype (")) {
|
||||
const Token * end = tok->linkAt(2);
|
||||
while (tok && tok->next() && tok != end) {
|
||||
tok = tok->next();
|
||||
namepos++;
|
||||
}
|
||||
} else if (Token::Match(tok->next(), "%type% <")) {
|
||||
const Token *closing = tok->tokAt(2)->findClosingBracket();
|
||||
if (closing) {
|
||||
if (Token::Match(closing->next(), "=|;"))
|
||||
|
@ -1401,8 +1457,7 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateClass(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() == ">>"));
|
||||
assert(tok && tok->str() == ">");
|
||||
|
||||
auto it = mTemplateNamePos.find(tok);
|
||||
if (!mSettings->debugtemplate && it != mTemplateNamePos.end()) {
|
||||
|
@ -1540,8 +1595,15 @@ void TemplateSimplifier::expandTemplate(
|
|||
end = end->findClosingBracket()->next();
|
||||
if (end->str() == "(")
|
||||
end = end->link()->next();
|
||||
else if (isVariable && end->str() == "=")
|
||||
end = const_cast<Token *>(Token::findsimplematch(templateDeclarationNameToken, ";"));
|
||||
else if (isVariable && end->str() == "=") {
|
||||
Token *temp = end->next();
|
||||
while (temp && temp->str() != ";") {
|
||||
if (temp->link() && Token::Match(temp, "{|[|("))
|
||||
temp = temp->link();
|
||||
temp = temp->next();
|
||||
}
|
||||
end = temp;
|
||||
}
|
||||
}
|
||||
unsigned int typeindentlevel = 0;
|
||||
while (!(typeindentlevel == 0 && Token::Match(end, ";|{|:"))) {
|
||||
|
@ -1697,9 +1759,17 @@ void TemplateSimplifier::expandTemplate(
|
|||
}
|
||||
if (inTemplateDefinition) {
|
||||
if (!endOfTemplateDefinition) {
|
||||
if (isVariable)
|
||||
endOfTemplateDefinition = Token::findsimplematch(tok3, ";");
|
||||
else if (tok3->str() == "{")
|
||||
if (isVariable) {
|
||||
Token *temp = tok3->findClosingBracket();
|
||||
if (temp) {
|
||||
while (temp && temp->str() != ";") {
|
||||
if (temp->link() && Token::Match(temp, "{|[|("))
|
||||
temp = temp->link();
|
||||
temp = temp->next();
|
||||
}
|
||||
endOfTemplateDefinition = temp;
|
||||
}
|
||||
} else if (tok3->str() == "{")
|
||||
endOfTemplateDefinition = tok3->link();
|
||||
}
|
||||
if (tok3 == endOfTemplateDefinition) {
|
||||
|
@ -1773,7 +1843,7 @@ void TemplateSimplifier::expandTemplate(
|
|||
}
|
||||
} else if (copy) {
|
||||
bool added = false;
|
||||
if (tok5->isName() && !Token::Match(tok5, "class|typename|struct")) {
|
||||
if (tok5->isName() && !Token::Match(tok5, "class|typename|struct") && !tok5->isStandardType()) {
|
||||
// search for this token in the type vector
|
||||
unsigned int itype = 0;
|
||||
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != tok5->str())
|
||||
|
@ -1852,7 +1922,7 @@ void TemplateSimplifier::expandTemplate(
|
|||
const std::string lastName = (templateInstantiation.name.find(' ') != std::string::npos) ? templateInstantiation.name.substr(templateInstantiation.name.rfind(' ')+1) : templateInstantiation.name;
|
||||
|
||||
for (; tok3; tok3 = tok3->next()) {
|
||||
if (tok3->isName() && !Token::Match(tok3, "class|typename|struct")) {
|
||||
if (tok3->isName() && !Token::Match(tok3, "class|typename|struct") && !tok3->isStandardType()) {
|
||||
// search for this token in the type vector
|
||||
unsigned int itype = 0;
|
||||
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != tok3->str())
|
||||
|
@ -2746,7 +2816,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
|||
}
|
||||
|
||||
if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
|
||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : isVar ? ";|%op%" : "*|&|::| %name%")))
|
||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : isVar ? ";|%op%|(" : "*|&|::| %name%")))
|
||||
continue;
|
||||
|
||||
// New type..
|
||||
|
@ -2808,7 +2878,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
|||
}
|
||||
|
||||
if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
|
||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : isVar ? ";|%op%" : "*|&|::| %name%")))
|
||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : isVar ? ";|%op%|(" : "*|&|::| %name%")))
|
||||
return false;
|
||||
|
||||
// already simplified
|
||||
|
@ -3282,6 +3352,9 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
const std::time_t maxtime,
|
||||
bool &codeWithTemplates)
|
||||
{
|
||||
// split ">>" into "> >"
|
||||
fixAngleBrackets();
|
||||
|
||||
// Remove "typename" unless used in template arguments or using type alias..
|
||||
for (Token *tok = mTokenList.front(); tok; tok = tok->next()) {
|
||||
if (Token::Match(tok, "typename %name%") && !Token::Match(tok->tokAt(-3), "using %name% ="))
|
||||
|
|
|
@ -294,6 +294,11 @@ public:
|
|||
*/
|
||||
void simplifyTemplateArgs(Token *start, Token *end);
|
||||
|
||||
/** Fix angle brackets.
|
||||
* foo < bar < >> => foo < bar < > >
|
||||
*/
|
||||
void fixAngleBrackets();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get template declarations
|
||||
|
|
|
@ -2817,23 +2817,6 @@ void Tokenizer::simplifyTemplates()
|
|||
if (isC())
|
||||
return;
|
||||
|
||||
for (Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
// Ticket #6181: normalize C++11 template parameter list closing syntax
|
||||
if (tok->str() == "<" && mTemplateSimplifier->templateParameters(tok)) {
|
||||
Token *endTok = tok->findClosingBracket();
|
||||
if (endTok && endTok->str() == ">>") {
|
||||
endTok->str(">");
|
||||
endTok->insertToken(">");
|
||||
}
|
||||
} else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <")) {
|
||||
Token *endTok = tok->tokAt(2)->findClosingBracket();
|
||||
if (Token::Match(endTok, ">> ;|{")) {
|
||||
endTok->str(">");
|
||||
endTok->insertToken(">");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTemplateSimplifier->simplifyTemplates(
|
||||
#ifdef MAXTIME
|
||||
mMaxTime,
|
||||
|
|
|
@ -154,6 +154,9 @@ private:
|
|||
TEST_CASE(template114); // #9155
|
||||
TEST_CASE(template115); // #9153
|
||||
TEST_CASE(template116); // #9178
|
||||
TEST_CASE(template117);
|
||||
TEST_CASE(template118);
|
||||
TEST_CASE(template119); // #9186
|
||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
TEST_CASE(template_specialization_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||
|
@ -207,6 +210,7 @@ private:
|
|||
TEST_CASE(template_variable_1);
|
||||
TEST_CASE(template_variable_2);
|
||||
TEST_CASE(template_variable_3);
|
||||
TEST_CASE(template_variable_4);
|
||||
}
|
||||
|
||||
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
|
||||
|
@ -945,19 +949,19 @@ private:
|
|||
" A<A<BLA>> gna1;\n"
|
||||
" A<BLA> gna2;\n"
|
||||
"}\n";
|
||||
const char expected[] = "class A<A<BLA>> ; "
|
||||
"class A<BLA> ; "
|
||||
const char expected[] = "class A<BLA> ; "
|
||||
"class A<A<BLA>> ; "
|
||||
"int main ( ) { "
|
||||
"A<A<BLA>> gna1 ; "
|
||||
"A<BLA> gna2 ; "
|
||||
"} "
|
||||
"class A<A<BLA>> { "
|
||||
"A<BLA> mT ; "
|
||||
"class A<BLA> { "
|
||||
"BLA mT ; "
|
||||
"public: "
|
||||
"void foo ( ) { } "
|
||||
"} ; "
|
||||
"class A<BLA> { "
|
||||
"BLA mT ; "
|
||||
"class A<A<BLA>> { "
|
||||
"A<BLA> mT ; "
|
||||
"public: "
|
||||
"void foo ( ) { } "
|
||||
"} ;";
|
||||
|
@ -2763,6 +2767,58 @@ private:
|
|||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template117() {
|
||||
const char code[] = "template<typename T = void> struct X {};\n"
|
||||
"X<X<>> x;";
|
||||
const char exp[] = "struct X<void> ; "
|
||||
"struct X<X<void>> ; "
|
||||
"X<X<void>> x ; "
|
||||
"struct X<void> { } ; "
|
||||
"struct X<X<void>> { } ;";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template118() {
|
||||
const char code[] = "template<int> struct S { void f(int i); };\n"
|
||||
"S<1> s;";
|
||||
const char exp[] = "struct S<1> ; "
|
||||
"S<1> s ; struct S<1> { "
|
||||
"void f ( int i ) ; "
|
||||
"} ;";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void template119() { // #9186
|
||||
{
|
||||
const char code[] = "template <typename T>\n"
|
||||
"constexpr auto func = [](auto x){ return T(x);};\n"
|
||||
"template <typename T>\n"
|
||||
"constexpr auto funcBraced = [](auto x){ return T{x};};\n"
|
||||
"double f(int x) { return func<double>(x); }\n"
|
||||
"double fBraced(int x) { return funcBraced<int>(x); }";
|
||||
const char exp[] = "const auto func<double> = [ ] ( auto x ) { return double ( x ) ; } ; "
|
||||
"const auto funcBraced<int> = [ ] ( auto x ) { return int { x } ; } ; "
|
||||
"double f ( int x ) { return func<double> ( x ) ; } "
|
||||
"double fBraced ( int x ) { return funcBraced<int> ( x ) ; }";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
{
|
||||
const char code[] = "template <typename T>\n"
|
||||
"constexpr auto func = [](auto x){ return T(x);};\n"
|
||||
"void foo() {\n"
|
||||
" func<int>(x);\n"
|
||||
" func<double>(x);\n"
|
||||
"}";
|
||||
const char exp[] = "const auto func<int> = [ ] ( auto x ) { return int ( x ) ; } ; "
|
||||
"const auto func<double> = [ ] ( auto x ) { return double ( x ) ; } ; "
|
||||
"void foo ( ) { "
|
||||
"func<int> ( x ) ; "
|
||||
"func<double> ( x ) ; "
|
||||
"}";
|
||||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
}
|
||||
|
||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
const char code[] = "template <typename T> struct C {};\n"
|
||||
"template <typename T> struct S {a};\n"
|
||||
|
@ -3433,11 +3489,13 @@ private:
|
|||
Tokenizer tokenizer(&settings, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp", "");
|
||||
tokenizer.createTokens(istr, "test.cpp");
|
||||
tokenizer.createLinks();
|
||||
tokenizer.mTemplateSimplifier->fixAngleBrackets();
|
||||
|
||||
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
|
||||
if (tok->str() == "var1")
|
||||
(const_cast<Token *>(tok))->varId(1);
|
||||
for (const Token *tok1 = tokenizer.tokens(); tok1; tok1 = tok1->next()) {
|
||||
if (tok1->str() == "var1")
|
||||
(const_cast<Token *>(tok1))->varId(1);
|
||||
}
|
||||
|
||||
return TemplateSimplifier::templateParameters(tokenizer.tokens()->next());
|
||||
|
@ -3459,14 +3517,28 @@ private:
|
|||
ASSERT_EQUALS(2U, templateParameters("X<class, typename... T> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("X<int(&)(), class> x;"));
|
||||
ASSERT_EQUALS(3U, templateParameters("X<char, int(*)(), bool> x;"));
|
||||
TODO_ASSERT_EQUALS(1U, 0U, templateParameters("X<int...> x;")); // Mishandled valid syntax
|
||||
TODO_ASSERT_EQUALS(2U, 0U, templateParameters("X<class, typename...> x;")); // Mishandled valid syntax
|
||||
ASSERT_EQUALS(1U, templateParameters("X<int...> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("X<class, typename...> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("X<1, T> x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("X<i == 0> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("X<int, i>=0> x;"));
|
||||
ASSERT_EQUALS(3U, templateParameters("X<int, i>=0, i - 2> x;"));
|
||||
ASSERT_EQUALS(0U, templateParameters("var1<1> x;"));
|
||||
ASSERT_EQUALS(0U, templateParameters("X<1>2;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<typename...B,typename=SameSize<B...>> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<typename...B,typename=SameSize<B...> > x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("template<template<typename>...Foo> x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("template<template<typename>> x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("template<template<template<typename>>> x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("template<template<template<template<typename>>>> x;"));
|
||||
ASSERT_EQUALS(1U, templateParameters("template<template<template<template<template<typename>>>>> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<template<typename>,int> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<template<template<typename>>,int> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<template<template<template<typename>>>,int> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<template<template<template<template<typename>>>>,int> x;"));
|
||||
ASSERT_EQUALS(2U, templateParameters("template<template<typename>...Foo,template<template<template<typename>>>> x;"));
|
||||
ASSERT_EQUALS(3U, templateParameters("template<template<typename>...Foo,int,template<template<template<typename>>>> x;"));
|
||||
ASSERT_EQUALS(4U, templateParameters("template<template<typename>...Foo,int,template<template<template<typename>>>,int> x;"));
|
||||
}
|
||||
|
||||
// Helper function to unit test TemplateSimplifier::getTemplateNamePosition
|
||||
|
@ -3474,7 +3546,9 @@ private:
|
|||
Tokenizer tokenizer(&settings, this);
|
||||
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp", emptyString);
|
||||
tokenizer.createTokens(istr, "test.cpp");
|
||||
tokenizer.createLinks();
|
||||
tokenizer.mTemplateSimplifier->fixAngleBrackets();
|
||||
|
||||
const Token *_tok = tokenizer.tokens();
|
||||
for (unsigned i = 0 ; i < offset ; ++i)
|
||||
|
@ -4040,6 +4114,16 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void template_variable_4() {
|
||||
const char code[] = "template<typename T> void test() { }\n"
|
||||
"template<typename T> decltype(test<T>)* foo = &(test<T>);\n"
|
||||
"void bar() { foo<int>(); }";
|
||||
const char expected[] = "void test<int> ( ) ; "
|
||||
"decltype ( test<int> ) * foo<int> = & ( test<int> ) ; "
|
||||
"void bar ( ) { foo<int> ( ) ; } "
|
||||
"void test<int> ( ) { }";
|
||||
ASSERT_EQUALS(expected, tok(code));
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestSimplifyTemplate)
|
||||
|
|
Loading…
Reference in New Issue