template simplifier: fix expansion of template arguments in default parameter instantiation (#1857)
This commit is contained in:
parent
774556dc10
commit
1e7f5010eb
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue