template simplifier: fix single parameter template with default value (#1842)

* template simplifier: fix single parameter template with default value

* fix derived class with single default argument
This commit is contained in:
IOBYTE 2019-05-19 13:19:57 -04:00 committed by Daniel Marjamäki
parent ce96ec2773
commit 592ff56b90
3 changed files with 197 additions and 126 deletions

View File

@ -835,7 +835,7 @@ void TemplateSimplifier::getTemplateInstantiations()
}
// Add outer template..
if (templateParameters(tok->next())) {
if (templateParameters(tok->next()) || tok->strAt(2) == ">") {
const std::string scopeName1(scopeName);
while (true) {
const std::string fullName = scopeName + (scopeName.empty()?"":" :: ") +
@ -890,154 +890,163 @@ void TemplateSimplifier::getTemplateInstantiations()
void TemplateSimplifier::useDefaultArgumentValues()
{
for (TokenAndName &template1 : mTemplateDeclarations) {
// template parameters with default value has syntax such as:
// x = y
// this list will contain all the '=' tokens for such arguments
std::list<Token *> eq;
// and this set the position of parameters with a default value
std::set<std::size_t> defaultedArgPos;
for (TokenAndName &template1 : mTemplateDeclarations)
useDefaultArgumentValues(template1);
// parameter number. 1,2,3,..
std::size_t templatepar = 1;
for (TokenAndName &template1 : mTemplateForwardDeclarations)
useDefaultArgumentValues(template1);
}
// parameter depth
std::size_t templateParmDepth = 0;
void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndName &template1)
{
// template parameters with default value has syntax such as:
// x = y
// this list will contain all the '=' tokens for such arguments
std::list<Token *> eq;
// and this set the position of parameters with a default value
std::set<std::size_t> defaultedArgPos;
// the template classname. This will be empty for template functions
std::string classname;
// parameter number. 1,2,3,..
std::size_t templatepar = 1;
// Scan template declaration..
for (Token *tok = template1.token; tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens
tok = tok->tokAt(2);
if (0 == templateParmDepth)
break;
continue;
}
// parameter depth
std::size_t templateParmDepth = 0;
if (tok->str() == "(") { // Ticket #6835
tok = tok->link();
continue;
}
// the template classname. This will be empty for template functions
std::string classname;
if (tok->str() == "<" && templateParameters(tok))
++templateParmDepth;
// Scan template declaration..
for (Token *tok = template1.token; tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens
tok = tok->tokAt(2);
if (0 == templateParmDepth)
break;
continue;
}
// end of template parameters?
if (tok->str() == ">") {
if (Token::Match(tok, "> class|struct|union %name%"))
classname = tok->strAt(2);
if (templateParmDepth<2)
break;
else
--templateParmDepth;
}
if (tok->str() == "(") { // Ticket #6835
tok = tok->link();
continue;
}
// next template parameter
if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters
++templatepar;
if (tok->str() == "<" && templateParameters(tok))
++templateParmDepth;
// default parameter value?
else if (Token::Match(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;
}
// end of template parameters?
if (tok->str() == ">") {
if (Token::Match(tok, "> class|struct|union %name%"))
classname = tok->strAt(2);
if (templateParmDepth<2)
break;
else
--templateParmDepth;
}
// next template parameter
if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters
++templatepar;
// default parameter value?
else if (Token::Match(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())
return;
// iterate through all template instantiations
for (const TokenAndName &templateInst : mTemplateInstantiations) {
Token *tok = templateInst.token;
if (!Token::simpleMatch(tok, (classname + " <").c_str()))
continue;
// iterate through all template instantiations
for (const TokenAndName &templateInst : mTemplateInstantiations) {
Token *tok = templateInst.token;
// count the parameters..
tok = tok->next();
const unsigned int usedpar = templateParameters(tok);
tok = tok->findClosingBracket();
if (!Token::simpleMatch(tok, (classname + " <").c_str()))
continue;
// count the parameters..
tok = tok->next();
const unsigned int usedpar = templateParameters(tok);
tok = tok->findClosingBracket();
if (tok && tok->str() == ">") {
tok = tok->previous();
std::list<Token *>::const_iterator it = eq.begin();
for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
++it;
while (it != eq.end()) {
int indentlevel = 0;
if (tok && tok->str() == ">") {
tok = tok->previous();
std::list<Token *>::const_iterator it = eq.begin();
for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
++it;
while (it != eq.end()) {
int indentlevel = 0;
if (usedpar) {
tok->insertToken(",");
tok = tok->next();
const Token *from = (*it)->next();
std::stack<Token *> links;
while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) {
if (from->str() == "<")
++indentlevel;
else if (from->str() == ">")
--indentlevel;
tok->insertToken(from->str(), from->originalName());
tok = tok->next();
if (Token::Match(tok, "(|["))
links.push(tok);
else if (!links.empty() && Token::Match(tok, ")|]")) {
Token::createMutualLinks(links.top(), tok);
links.pop();
}
from = from->next();
}
const Token *from = (*it)->next();
std::stack<Token *> links;
while (from && (!links.empty() || indentlevel || !Token::Match(from, ",|>"))) {
if (from->str() == "<")
++indentlevel;
else if (from->str() == ">")
--indentlevel;
tok->insertToken(from->str(), from->originalName());
tok = tok->next();
if (Token::Match(tok, "(|["))
links.push(tok);
else if (!links.empty() && Token::Match(tok, ")|]")) {
Token::createMutualLinks(links.top(), tok);
links.pop();
}
++it;
from = from->next();
}
++it;
}
}
}
for (Token * const eqtok : eq) {
Token *tok2;
int indentlevel = 0;
for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) {
if (Token::Match(tok2, ";|)|}|]")) { // bail out #6607
tok2 = nullptr;
break;
}
if (Token::Match(tok2, "(|{|["))
tok2 = tok2->link();
else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) {
std::list<TokenAndName>::iterator ti = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(tok2));
if (ti != mTemplateInstantiations.end())
mTemplateInstantiations.erase(ti);
++indentlevel;
} else if (indentlevel > 0 && tok2->str() == ">")
--indentlevel;
else if (indentlevel == 0 && Token::Match(tok2, ",|>"))
break;
if (indentlevel < 0)
break;
for (Token * const eqtok : eq) {
Token *tok2;
int indentlevel = 0;
for (tok2 = eqtok->next(); tok2; tok2 = tok2->next()) {
if (Token::Match(tok2, ";|)|}|]")) { // bail out #6607
tok2 = nullptr;
break;
}
// something went wrong, don't call eraseTokens()
// with a nullptr "end" parameter (=all remaining tokens).
if (!tok2)
continue;
// don't strip args from uninstantiated templates
std::list<TokenAndName>::iterator ti2 = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindName(template1.name));
if (ti2 == mTemplateInstantiations.end())
continue;
eraseTokens(eqtok, tok2);
eqtok->deleteThis();
// update parameter end pointer
template1.paramEnd = template1.token->next()->findClosingBracket();
if (Token::Match(tok2, "(|{|["))
tok2 = tok2->link();
else if (Token::Match(tok2, "%type% <") && templateParameters(tok2->next())) {
std::list<TokenAndName>::iterator ti = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindToken(tok2));
if (ti != mTemplateInstantiations.end())
mTemplateInstantiations.erase(ti);
++indentlevel;
} else if (indentlevel > 0 && tok2->str() == ">")
--indentlevel;
else if (indentlevel == 0 && Token::Match(tok2, ",|>"))
break;
if (indentlevel < 0)
break;
}
// something went wrong, don't call eraseTokens()
// with a nullptr "end" parameter (=all remaining tokens).
if (!tok2)
continue;
// don't strip args from uninstantiated templates
std::list<TokenAndName>::iterator ti2 = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(),
FindName(template1.name));
if (ti2 == mTemplateInstantiations.end())
continue;
eraseTokens(eqtok, tok2);
eqtok->deleteThis();
// update parameter end pointer
template1.paramEnd = template1.token->next()->findClosingBracket();
}
}

View File

@ -269,6 +269,12 @@ private:
*/
void useDefaultArgumentValues();
/**
* simplify template instantiations (use default argument values)
* @param template1 template declaration or forward declaration
*/
void useDefaultArgumentValues(TemplateSimplifier::TokenAndName &template1);
/**
* Try to locate a matching declaration for each user defined
* specialization.

View File

@ -2609,6 +2609,62 @@ private:
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> { } ;";
TODO_ASSERT_EQUALS(exp, curr, tok(code));
}
{
// #8890
const char code[] = "template <typename = void> struct a {\n"
" void c();\n"
"};\n"
"void f() {\n"
" a<> b;\n"
" b.a<>::c();\n"
"}";
ASSERT_EQUALS("struct a<void> ; "
"void f ( ) { "
"a<void> b ; "
"b . a<void> :: c ( ) ; "
"} "
"struct a<void> { "
"void c ( ) ; "
"} ;", tok(code));
}
{
// #8890
const char code[] = "template< typename T0 = void > class A;\n"
"template<>\n"
"class A< void > {\n"
" public:\n"
" A() { }\n"
" ~A() { }\n"
" void Print() { std::cout << \"A\" << std::endl; }\n"
"};\n"
"class B : public A<> {\n"
" public:\n"
" B() { }\n"
" ~B() { }\n"
"};\n"
"int main( int argc, char* argv[] ) {\n"
" B b;\n"
" b.A<>::Print();\n"
" return 0;\n"
"}";
ASSERT_EQUALS("template < typename T0 > class A ; "
"class A<void> { "
"public: "
"A<void> ( ) { } "
"~ A<void> ( ) { } "
"void Print ( ) { std :: cout << \"A\" << std :: endl ; } "
"} ; "
"class B : public A<void> { "
"public: "
"B ( ) { } "
"~ B ( ) { } "
"} ; "
"int main ( int argc , char * argv [ ] ) { "
"B b ; "
"b . A<void> :: Print ( ) ; "
"return 0 ; "
"}", tok(code));
}
}
void template_forward_declared_default_parameter() {