template simplifier: fix expansion of template arguments in default parameter instantiation (#1857)

This commit is contained in:
IOBYTE 2019-05-28 15:32:37 -04:00 committed by Daniel Marjamäki
parent 774556dc10
commit 1e7f5010eb
4 changed files with 78 additions and 64 deletions

View File

@ -894,15 +894,21 @@ void TemplateSimplifier::getTemplateInstantiations()
void TemplateSimplifier::useDefaultArgumentValues() void TemplateSimplifier::useDefaultArgumentValues()
{ {
for (TokenAndName &template1 : mTemplateDeclarations) for (TokenAndName &declaration : mTemplateDeclarations)
useDefaultArgumentValues(template1); useDefaultArgumentValues(declaration);
for (TokenAndName &template1 : mTemplateForwardDeclarations) for (TokenAndName &declaration : mTemplateForwardDeclarations)
useDefaultArgumentValues(template1); useDefaultArgumentValues(declaration);
} }
void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndName &template1) void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
{ {
// Ticket #5762: Skip specialization tokens
// FIXME: should be: if (declaration.isSpecialization() || declaration.isAlias())
// but there is a problem with functions
if (!declaration.isClass())
return;
// template parameters with default value has syntax such as: // template parameters with default value has syntax such as:
// x = y // x = y
// this list will contain all the '=' tokens for such arguments // this list will contain all the '=' tokens for such arguments
@ -916,19 +922,12 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
// parameter depth // parameter depth
std::size_t templateParmDepth = 0; std::size_t templateParmDepth = 0;
// the template classname. This will be empty for template functions // map type parameter name to index
std::string classname; std::map<std::string, unsigned int> typeParameterNames;
// Scan template declaration.. // Scan template declaration..
for (Token *tok = template1.token; tok; tok = tok->next()) { for (Token *tok = declaration.token; tok; tok = tok->next()) {
if (Token::simpleMatch(tok, "template < >")) { // Ticket #5762: Skip specialization tokens if (tok->link()) { // Ticket #6835
tok = tok->tokAt(2);
if (0 == templateParmDepth)
break;
continue;
}
if (tok->str() == "(") { // Ticket #6835
tok = tok->link(); tok = tok->link();
continue; continue;
} }
@ -938,14 +937,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
// end of template parameters? // end of template parameters?
if (tok->str() == ">") { if (tok->str() == ">") {
if (Token::Match(tok, "> class|struct|union %name%"))
classname = tok->strAt(2);
if (templateParmDepth<2) if (templateParmDepth<2)
break; break;
else else
--templateParmDepth; --templateParmDepth;
} }
// map type parameter name to index
if (Token::Match(tok, "typename|class %name% ,|>"))
typeParameterNames[tok->strAt(1)] = templatepar - 1;
// next template parameter // next template parameter
if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters if (tok->str() == "," && (1 == templateParmDepth)) // Ticket #5823: Properly count parameters
++templatepar; ++templatepar;
@ -961,16 +962,43 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
} }
} }
} }
if (eq.empty() || classname.empty()) if (eq.empty())
return; return;
// iterate through all template instantiations // iterate through all template instantiations
for (const TokenAndName &templateInst : mTemplateInstantiations) { for (const TokenAndName &instantiation : mTemplateInstantiations) {
Token *tok = templateInst.token; Token *tok = instantiation.token;
if (!Token::simpleMatch(tok, (classname + " <").c_str())) if (!Token::simpleMatch(tok, (declaration.name + " <").c_str()))
continue; continue;
// instantiation arguments..
std::vector<std::vector<const Token *>> instantiationArgs;
std::size_t index = 0;
instantiationArgs.resize(1);
const Token *end = instantiation.token->next()->findClosingBracket();
if (!end)
continue;
for (const Token *tok1 = instantiation.token->tokAt(2); tok1 && tok1!= end; tok1 = tok1->next()) {
if (tok1->link()) {
const Token *endLink = tok1->link();
do {
instantiationArgs[index].push_back(tok1);
tok1 = tok1->next();
} while (tok1 && tok1 != endLink);
} else if (tok1->str() == "<") {
const Token *endLink = tok1->findClosingBracket();
do {
instantiationArgs[index].push_back(tok1);
tok1 = tok1->next();
} while (tok1 && tok1 != endLink);
} else if (tok1->str() == ",") {
++index;
instantiationArgs.resize(index + 1);
} else
instantiationArgs[index].push_back(tok1);
}
// count the parameters.. // count the parameters..
tok = tok->next(); tok = tok->next();
const unsigned int usedpar = templateParameters(tok); const unsigned int usedpar = templateParameters(tok);
@ -983,7 +1011,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
++it; ++it;
while (it != eq.end()) { while (it != eq.end()) {
int indentlevel = 0; int indentlevel = 0;
if (usedpar) { if (usedpar && usedpar <= instantiationArgs.size()) {
tok->insertToken(","); tok->insertToken(",");
tok = tok->next(); tok = tok->next();
} }
@ -994,8 +1022,16 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
++indentlevel; ++indentlevel;
else if (from->str() == ">") else if (from->str() == ">")
--indentlevel; --indentlevel;
auto entry = typeParameterNames.find(from->str());
if (entry != typeParameterNames.end() && entry->second < instantiationArgs.size()) {
for (const Token *tok1 : instantiationArgs[entry->second]) {
tok->insertToken(tok1->str(), tok1->originalName());
tok = tok->next();
}
} else {
tok->insertToken(from->str(), from->originalName()); tok->insertToken(from->str(), from->originalName());
tok = tok->next(); tok = tok->next();
}
if (Token::Match(tok, "(|[|{")) if (Token::Match(tok, "(|[|{"))
links.push(tok); links.push(tok);
else if (!links.empty() && Token::Match(tok, ")|]|}")) { else if (!links.empty() && Token::Match(tok, ")|]|}")) {
@ -1041,7 +1077,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
// don't strip args from uninstantiated templates // don't strip args from uninstantiated templates
std::list<TokenAndName>::iterator ti2 = std::find_if(mTemplateInstantiations.begin(), std::list<TokenAndName>::iterator ti2 = std::find_if(mTemplateInstantiations.begin(),
mTemplateInstantiations.end(), mTemplateInstantiations.end(),
FindName(template1.name)); FindName(declaration.name));
if (ti2 == mTemplateInstantiations.end()) if (ti2 == mTemplateInstantiations.end())
continue; continue;
@ -1050,7 +1086,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TemplateSimplifier::TokenAndNa
eqtok->deleteThis(); eqtok->deleteThis();
// update parameter end pointer // update parameter end pointer
template1.paramEnd = template1.token->next()->findClosingBracket(); declaration.paramEnd = declaration.token->next()->findClosingBracket();
} }
} }
@ -2360,6 +2396,8 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
const Token * tok, const Token * tok,
std::vector<const Token *> & typeParametersInDeclaration) std::vector<const Token *> & typeParametersInDeclaration)
{ {
assert(tok->strAt(-1) == "<");
typeParametersInDeclaration.clear(); typeParametersInDeclaration.clear();
const Token *end = tok->previous()->findClosingBracket(); const Token *end = tok->previous()->findClosingBracket();
for (; tok && tok!= end; tok = tok->next()) { for (; tok && tok!= end; tok = tok->next()) {
@ -2367,9 +2405,9 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
const Token *closing = tok->next()->findClosingBracket(); const Token *closing = tok->next()->findClosingBracket();
if (closing) if (closing)
tok = closing->next(); tok = closing->next();
} } else if (tok->link())
tok = tok->link();
if (Token::Match(tok, "%name% ,|>|=")) else if (Token::Match(tok, "%name% ,|>|="))
typeParametersInDeclaration.push_back(tok); typeParametersInDeclaration.push_back(tok);
} }
return tok; return tok;

View File

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

View File

@ -2556,19 +2556,7 @@ private:
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; " "static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; "
"struct e<> { } ; " "struct e<> { } ; "
"struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;"; "struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;";
const char actual[] = "namespace a { " ASSERT_EQUALS(exp, tok(code));
"template < typename b , bool > struct c ; "
"} "
"namespace boost { "
"using a :: c ; "
"} "
"using boost :: c ; "
"struct e<> ; "
"struct e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> ; "
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> ) , \"\" ) ; "
"struct e<> { } ; "
"struct e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> { } ;";
TODO_ASSERT_EQUALS(exp, actual, tok(code));
} }
{ {
const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n" const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
@ -2580,24 +2568,15 @@ private:
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; " "static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; "
"struct e<> { } ; " "struct e<> { } ; "
"struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;"; "struct e<c<int,std::is_empty<int>{}&&std::is_final<int>{}>,c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;";
const char actual[] = "template < typename b , bool > struct c ; " ASSERT_EQUALS(exp, tok(code));
"struct e<> ; "
"struct e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> ; "
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> ) , \"\" ) ; "
"struct e<> { } ; "
"struct e<c<int,std::is_empty<b>{}&&std::is_final<b>{}>,c<int,std::is_empty<b>{}&&std::is_final<b>{}>,int> { } ;";
TODO_ASSERT_EQUALS(exp, actual, tok(code));
} }
{ {
const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c{};\n" const char code[] = "template <typename b, bool = __is_empty(b) && __is_final(b)> struct c{};\n"
"c<int> cc;\n"; "c<int> cc;\n";
const char exp[] = "struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> ; " const char exp[] = "struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> ; "
"c<int,std::is_empty<b>{}&&std::is_final<b>{}> cc ; " "c<int,std::is_empty<int>{}&&std::is_final<int>{}> cc ; "
"struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> { } ;"; "struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> { } ;";
const char actual[] = "struct c<int,std::is_empty<b>{}&&std::is_final<b>{}> ; " ASSERT_EQUALS(exp, tok(code));
"c<int,std::is_empty<b>{}&&std::is_final<b>{}> cc ; "
"struct c<int,std::is_empty<b>{}&&std::is_final<b>{}> { } ;";
TODO_ASSERT_EQUALS(exp, actual, tok(code));
} }
} }
@ -2756,13 +2735,10 @@ private:
"template<class Key, class Val, class Mem=DefaultMemory<Key,Val> > class thv_table_c {}; " "template<class Key, class Val, class Mem=DefaultMemory<Key,Val> > class thv_table_c {}; "
"thv_table_c<void *,void *> id_table_m;"; "thv_table_c<void *,void *> id_table_m;";
const char exp [] = "template < class T , class U > class DefaultMemory { } ; " const char exp [] = "template < class T , class U > class DefaultMemory { } ; "
"thv_table_c<void * , void * , DefaultMemory < void * , void *>> id_table_m ; " "class thv_table_c<void*,void*,DefaultMemory<void*,void*>> ; "
"class thv_table_c<void * , void * , DefaultMemory < void * , void * >> { } ;"; "thv_table_c<void*,void*,DefaultMemory<void*,void*>> id_table_m ; "
const char curr[] = "template < class T , class U > class DefaultMemory { } ; " "class thv_table_c<void*,void*,DefaultMemory<void*,void*>> { } ;";
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> ; " ASSERT_EQUALS(exp, tok(code));
"thv_table_c<void*,void*,DefaultMemory<Key,Val>> id_table_m ; "
"class thv_table_c<void*,void*,DefaultMemory<Key,Val>> { } ;";
TODO_ASSERT_EQUALS(exp, curr, tok(code));
} }
{ {
// #8890 // #8890

View File

@ -5214,7 +5214,7 @@ private:
"template < class T , T t >\n" "template < class T , T t >\n"
"struct S\n" "struct S\n"
"{ } ;\n" "{ } ;\n"
"S < int , ( T ) 0 > s ;", // current result "S < int , ( int ) 0 > s ;", // current result
tokenizeAndStringify(code)); tokenizeAndStringify(code));
} }