token simplifier: fix namespace, token link and syntax error support for template type aliases (#1863)

This commit is contained in:
IOBYTE 2019-06-01 04:52:29 -04:00 committed by Daniel Marjamäki
parent 12f4353d40
commit bee248b2de
6 changed files with 390 additions and 110 deletions

View File

@ -81,6 +81,14 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
isSpecialization(Token::simpleMatch(token, "template < >"));
isPartialSpecialization(!isSpecialization() && nameToken->strAt(1) == "<");
isAlias(paramEnd->strAt(1) == "using");
if (isAlias() && isPartialSpecialization()) {
throw InternalError(tok, "partial specialization of alias templates is not permitted", InternalError::SYNTAX);
}
if (isAlias() && isSpecialization()) {
throw InternalError(tok, "explicit specialization of alias templates is not permitted", InternalError::SYNTAX);
}
isClass(Token::Match(paramEnd->next(), "class|struct|union %name% <|{|:|;"));
if (token->strAt(1) == "<" && !isSpecialization()) {
const Token *end = token->next()->findClosingBracket();
@ -95,10 +103,10 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *tok, const std::string &s,
throw InternalError(tok, "unsupported syntax", InternalError::SYNTAX);
}
isFunction(tok1->str() == "(");
isVariable(!isClass() && Token::Match(tok1, "=|;"));
isVariable(!isClass() && !isAlias() && Token::Match(tok1, "=|;"));
if (isVariable())
isForwardDeclaration(tok1->str() == ";");
else {
else if (!isAlias()) {
if (isFunction())
tok1 = tok1->link()->next();
tok1 = Token::findmatch(tok1, "{|;");
@ -156,6 +164,31 @@ TemplateSimplifier::TokenAndName::~TokenAndName()
token->templateSimplifierPointers().erase(this);
}
const Token * TemplateSimplifier::TokenAndName::aliasStartToken() const
{
if (paramEnd)
return paramEnd->tokAt(4);
return nullptr;
}
const Token * TemplateSimplifier::TokenAndName::aliasEndToken() const
{
if (aliasStartToken())
return Token::findsimplematch(aliasStartToken(), ";");
return nullptr;
}
bool TemplateSimplifier::TokenAndName::isAliasToken(const Token *tok) const
{
const Token *end = aliasEndToken();
for (const Token *tok1 = aliasStartToken(); tok1 != end; tok1 = tok1->next()) {
if (tok1 == tok)
return true;
}
return false;
}
TemplateSimplifier::TemplateSimplifier(Tokenizer *tokenizer)
: mTokenizer(tokenizer), mTokenList(tokenizer->list), mSettings(tokenizer->mSettings), mErrorLogger(tokenizer->mErrorLogger)
{
@ -711,13 +744,20 @@ void TemplateSimplifier::getTemplateInstantiations()
setScopeInfo(tok, &scopeList);
continue;
}
// template definition.. skip it
if (Token::simpleMatch(tok, "template <")) {
tok = tok->next()->findClosingBracket();
if (!tok)
break;
const bool isUsing = tok->strAt(1) == "using";
if (tok->strAt(-1) == "<") {
if (isUsing && Token::Match(tok->tokAt(2), "%name% <")) {
// Cant have specialized type alias so ignore it
const Token *tok2 = Token::findsimplematch(tok->tokAt(3), ";");
if (tok2)
tok = const_cast<Token *>(tok2);
} else if (tok->strAt(-1) == "<") {
// Don't ignore user specialization but don't consider it an instantiation.
// Instantiations in return type, function parameters, and executable code
// are not ignored.
@ -734,7 +774,17 @@ void TemplateSimplifier::getTemplateInstantiations()
else if (!isUsing && tok2 && tok2->str() == ";")
tok = const_cast<Token *>(tok2);
}
} else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|.|*|&|return|< %name% ::|<|(") ||
} else if (Token::Match(tok, "template using %name% <")) {
// Cant have specialized type alias so ignore it
const Token *tok2 = Token::findsimplematch(tok->tokAt(3), ";");
if (tok2)
tok = const_cast<Token *>(tok2);
} else if (Token::Match(tok, "using %name% <")) {
// Cant have specialized type alias so ignore it
const Token *tok2 = Token::findsimplematch(tok->tokAt(2), ";");
if (tok2)
tok = const_cast<Token *>(tok2);
} else if (Token::Match(tok->previous(), "(|{|}|;|=|>|<<|:|.|*|&|return|<|, %name% ::|<|(") ||
Token::Match(tok->previous(), "%type% %name% ::|<") ||
Token::Match(tok->tokAt(-2), "[,:] private|protected|public %name% ::|<")) {
std::string scopeName = getScopeName(scopeList);
@ -904,9 +954,7 @@ void TemplateSimplifier::useDefaultArgumentValues()
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())
if (declaration.isSpecialization() || declaration.isAlias())
return;
// template parameters with default value has syntax such as:
@ -927,7 +975,7 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
// Scan template declaration..
for (Token *tok = declaration.token; tok; tok = tok->next()) {
if (tok->link()) { // Ticket #6835
if (tok->link() && Token::Match(tok, "{|(|[")) { // Ticket #6835
tok = tok->link();
continue;
}
@ -967,20 +1015,19 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
// iterate through all template instantiations
for (const TokenAndName &instantiation : mTemplateInstantiations) {
Token *tok = instantiation.token;
if (!Token::simpleMatch(tok, (declaration.name + " <").c_str()))
if (declaration.fullName != instantiation.fullName)
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;
if (end != instantiation.token->tokAt(2))
instantiationArgs.resize(1);
for (const Token *tok1 = instantiation.token->tokAt(2); tok1 && tok1!= end; tok1 = tok1->next()) {
if (tok1->link()) {
if (tok1->link() && Token::Match(tok1, "{|(|[")) {
const Token *endLink = tok1->link();
do {
instantiationArgs[index].push_back(tok1);
@ -1000,8 +1047,8 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
}
// count the parameters..
tok = tok->next();
const unsigned int usedpar = templateParameters(tok);
Token *tok = instantiation.token->next();
unsigned int usedpar = templateParameters(tok);
tok = tok->findClosingBracket();
if (tok && tok->str() == ">") {
@ -1009,9 +1056,10 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
std::list<Token *>::const_iterator it = eq.begin();
for (std::size_t i = (templatepar - eq.size()); it != eq.end() && i < usedpar; ++i)
++it;
int count = 0;
while (it != eq.end()) {
int indentlevel = 0;
if (usedpar && usedpar <= instantiationArgs.size()) {
if ((usedpar + count) && usedpar <= (instantiationArgs.size() + count)) {
tok->insertToken(",");
tok = tok->next();
}
@ -1027,20 +1075,30 @@ void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
for (const Token *tok1 : instantiationArgs[entry->second]) {
tok->insertToken(tok1->str(), tok1->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();
}
}
} else {
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();
if (Token::Match(tok, "(|[|{"))
links.push(tok);
else if (!links.empty() && Token::Match(tok, ")|]|}")) {
Token::createMutualLinks(links.top(), tok);
links.pop();
}
}
from = from->next();
}
++it;
count++;
usedpar++;
}
}
}
@ -1106,8 +1164,6 @@ void TemplateSimplifier::simplifyTemplateAliases()
Token::Match(startToken->tokAt(-5), "> using %name% = typename %name% ::|<")))
continue;
const bool hasTypename(startToken->strAt(-1) == "typename");
const std::string aliasName(startToken->strAt(hasTypename ? -3 : -2));
const Token * const aliasToken1 = startToken;
// Get start token for alias
startToken = startToken->tokAt(hasTypename ? -6 : -5);
@ -1120,9 +1176,17 @@ void TemplateSimplifier::simplifyTemplateAliases()
} else if (!Token::Match(startToken, "[;{}] template <"))
continue;
std::list<TokenAndName>::iterator it5 = std::find_if(mTemplateDeclarations.begin(),
mTemplateDeclarations.end(),
FindToken(!startToken ? mTokenList.front() : startToken->next()));
if (it5 == mTemplateDeclarations.end())
continue;
TokenAndName &aliasDeclaration = *it5;
// alias parameters..
std::vector<const Token *> aliasParameters;
getTemplateParametersInDeclaration(startToken ? startToken->tokAt(3) : mTokenList.front()->tokAt(2), aliasParameters);
getTemplateParametersInDeclaration(aliasDeclaration.token->tokAt(2), aliasParameters);
std::map<std::string, unsigned int> aliasParameterNames;
for (unsigned int argnr = 0; argnr < aliasParameters.size(); ++argnr)
aliasParameterNames[aliasParameters[argnr]->str()] = argnr;
@ -1131,8 +1195,13 @@ void TemplateSimplifier::simplifyTemplateAliases()
const Token *endToken = nullptr;
for (it2 = it1; it2 != mTemplateInstantiations.end(); ++it2) {
TokenAndName &aliasUsage = *it2;
if (!aliasUsage.token || aliasUsage.name != aliasName)
if (!aliasUsage.token || aliasUsage.fullName != aliasDeclaration.fullName)
continue;
// don't recurse
if (aliasDeclaration.isAliasToken(aliasUsage.token))
continue;
std::vector<std::pair<Token *, Token *>> args;
Token *tok2 = aliasUsage.token->tokAt(2);
while (tok2) {
@ -1157,18 +1226,27 @@ void TemplateSimplifier::simplifyTemplateAliases()
// Replace template alias code..
aliasUsage.name = templateAlias.name;
if (aliasUsage.name.find(' ') == std::string::npos) {
const Token *temp = aliasToken1;
while (temp && temp != templateAlias.token) {
aliasUsage.token->insertToken(temp->str(), "", true);
temp = temp->next();
aliasUsage.fullName = templateAlias.fullName;
aliasUsage.scope = templateAlias.scope;
const Token *temp = aliasDeclaration.aliasStartToken();
if (temp->str() == "typename")
temp = temp->next();
std::stack<Token *> links;
while (temp && temp != templateAlias.token) {
aliasUsage.token->insertToken(temp->str(), "", true);
Token * previous = aliasUsage.token->previous();
if (Token::Match(previous, "(|[|{"))
links.push(previous);
else if (!links.empty() && Token::Match(previous, ")|]|}")) {
Token::createMutualLinks(links.top(), previous);
links.pop();
}
aliasUsage.token->str(templateAlias.token->str());
} else {
tok2 = TokenList::copyTokens(aliasUsage.token, aliasToken1, templateAlias.token, true);
deleteToken(aliasUsage.token);
aliasUsage.token = tok2;
temp = temp->next();
}
aliasUsage.token->str(templateAlias.token->str());
tok2 = aliasUsage.token->next(); // the '<'
const Token * const endToken1 = templateAlias.token->next()->findClosingBracket();
const Token * const endToken2 = TokenList::copyTokens(tok2, templateAlias.token->tokAt(2), endToken1->previous(), false)->next();
@ -1205,7 +1283,7 @@ void TemplateSimplifier::simplifyTemplateAliases()
}
if (endToken) {
// Remove all template instantiations in template alias
for (const Token *tok = startToken ? startToken : mTokenList.front(); tok != endToken; tok = tok->next()) {
for (const Token *tok = aliasDeclaration.paramEnd->tokAt(4); tok != endToken; tok = tok->next()) {
if (!Token::Match(tok, "%name% <"))
continue;
std::list<TokenAndName>::iterator it = std::find_if(mTemplateInstantiations.begin(),
@ -1220,21 +1298,15 @@ void TemplateSimplifier::simplifyTemplateAliases()
mTemplateInstantiations.erase(it,next);
}
// find declaration
const std::list<TokenAndName>::iterator it4 = std::find_if(mTemplateDeclarations.begin(),
mTemplateDeclarations.end(),
FindToken(startToken ? startToken->next() : mTokenList.front()));
if (startToken)
eraseTokens(startToken, endToken);
eraseTokens(startToken, endToken->next() ? endToken->next() : endToken);
else {
eraseTokens(mTokenList.front(), endToken);
eraseTokens(mTokenList.front(), endToken->next() ? endToken->next() : endToken);
deleteToken(mTokenList.front());
}
// remove declaration
if (it4 != mTemplateDeclarations.end())
mTemplateDeclarations.erase(it4);
mTemplateDeclarations.erase(it5);
} else
mTemplateInstantiations.erase(it3);
}
@ -1256,6 +1328,8 @@ bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size
++indentlevel;
if (indentlevel > 0 && tok->str() == ">")
--indentlevel;
if (indentlevel > 0 && Token::Match(tok, "{|(|["))
tok = tok->link();
}
if (!tok || !Token::Match(tok->next(), patternAfter))
return false;
@ -1483,7 +1557,8 @@ void TemplateSimplifier::expandTemplate(
while (itype < typeParametersInDeclaration.size() && typeParametersInDeclaration[itype]->str() != start->str())
++itype;
if (itype < typeParametersInDeclaration.size()) {
if (itype < typeParametersInDeclaration.size() &&
(!isVariable || !Token::Match(typeParametersInDeclaration[itype]->previous(), "<|, %type% >|,"))) {
typeindentlevel = 0;
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token;
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
@ -1680,6 +1755,7 @@ void TemplateSimplifier::expandTemplate(
// replace type with given type..
if (itype < typeParametersInDeclaration.size()) {
unsigned int typeindentlevel = 0;
std::stack<Token *> brackets1; // holds "(" and "{" tokens
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token;
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) {
@ -1691,7 +1767,23 @@ void TemplateSimplifier::expandTemplate(
else if (typeindentlevel > 0 && typetok->str() == ">")
--typeindentlevel;
mTokenList.addtoken(typetok, tok5->linenr(), tok5->fileIndex());
mTokenList.back()->isTemplateArg(true);
Token *back = mTokenList.back();
if (back->str() == "{") {
brackets1.push(back);
} else if (back->str() == "(") {
brackets1.push(back);
} else if (back->str() == "}") {
assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "{");
Token::createMutualLinks(brackets1.top(), back);
brackets1.pop();
} else if (back->str() == ")") {
assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "(");
Token::createMutualLinks(brackets1.top(), back);
brackets1.pop();
}
back->isTemplateArg(true);
added = true;
break;
}
@ -1740,6 +1832,7 @@ void TemplateSimplifier::expandTemplate(
// replace type with given type..
if (itype < typeParametersInDeclaration.size()) {
unsigned int typeindentlevel = 0;
std::stack<Token *> brackets1; // holds "(" and "{" tokens
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token;
typetok && (typeindentlevel>0 || !Token::Match(typetok, ",|>"));
typetok = typetok->next()) {
@ -1753,7 +1846,23 @@ void TemplateSimplifier::expandTemplate(
--typeindentlevel;
if (copy) {
mTokenList.addtoken(typetok, tok3->linenr(), tok3->fileIndex());
mTokenList.back()->isTemplateArg(true);
Token *back = mTokenList.back();
if (back->str() == "{") {
brackets1.push(back);
} else if (back->str() == "(") {
brackets1.push(back);
} else if (back->str() == "}") {
assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "{");
Token::createMutualLinks(brackets1.top(), back);
brackets1.pop();
} else if (back->str() == ")") {
assert(brackets1.empty() == false);
assert(brackets1.top()->str() == "(");
Token::createMutualLinks(brackets1.top(), back);
brackets1.pop();
}
back->isTemplateArg(true);
}
}
continue;
@ -2405,7 +2514,7 @@ const Token * TemplateSimplifier::getTemplateParametersInDeclaration(
const Token *closing = tok->next()->findClosingBracket();
if (closing)
tok = closing->next();
} else if (tok->link())
} else if (tok->link() && Token::Match(tok, "{|(|["))
tok = tok->link();
else if (Token::Match(tok, "%name% ,|>|="))
typeParametersInDeclaration.push_back(tok);
@ -2467,9 +2576,8 @@ std::string TemplateSimplifier::getNewName(
unsigned int indentlevel = 0;
const Token * endToken = tok2->next()->findClosingBracket();
for (Token *tok3 = tok2->tokAt(2); tok3 != endToken && (indentlevel > 0 || tok3->str() != ">"); tok3 = tok3->next()) {
// #2648 - unhandled parentheses => bail out
// #2721 - unhandled [ => bail out
if (Token::Match(tok3, "(|[")) {
if (tok3->str() == "[") {
typeForNewName.clear();
break;
}
@ -2964,6 +3072,15 @@ void TemplateSimplifier::printOut(const TokenAndName &tokenAndName, const std::s
}
std::cout << end->str() << std::endl;
}
} else if (tokenAndName.isAlias() && tokenAndName.paramEnd) {
if (tokenAndName.aliasStartToken()) {
std::cout << indent << "aliasStartToken: \"" << tokenAndName.aliasStartToken()->str() << "\" "
<< mTokenList.fileLine(tokenAndName.aliasStartToken()) << std::endl;
}
if (tokenAndName.aliasEndToken()) {
std::cout << indent << "aliasEndToken: \"" << tokenAndName.aliasEndToken()->str() << "\" "
<< mTokenList.fileLine(tokenAndName.aliasEndToken()) << std::endl;
}
}
}
@ -3131,7 +3248,7 @@ void TemplateSimplifier::simplifyTemplates(
codeWithTemplates = hasTemplates;
// Make sure there is something to simplify.
if (mTemplateDeclarations.empty())
if (mTemplateDeclarations.empty() && mTemplateForwardDeclarations.empty())
return;
// Copy default argument values from forward declaration to declaration
@ -3157,9 +3274,15 @@ void TemplateSimplifier::simplifyTemplates(
std::set<std::string> expandedtemplates;
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
if (iter1->isAlias())
continue;
// get specializations..
std::list<const Token *> specializations;
for (std::list<TokenAndName>::const_iterator iter2 = mTemplateDeclarations.begin(); iter2 != mTemplateDeclarations.end(); ++iter2) {
if (iter2->isAlias())
continue;
if (iter1->fullName == iter2->fullName)
specializations.push_back(iter2->nameToken);
}

View File

@ -183,6 +183,31 @@ public:
void setFlag(unsigned int flag, bool state) {
flags = state ? flags | flag : flags & ~flag;
}
/**
* Get alias start token.
* template < ... > using X = foo < ... >;
* ^
* @return alias start token
*/
const Token * aliasStartToken() const;
/**
* Get alias end token.
* template < ... > using X = foo < ... >;
* ^
* @return alias end token
*/
const Token * aliasEndToken() const;
/**
* Is token an alias token?
* template < ... > using X = foo < ... >;
* ^
* @param tok token to check
* @return true if alias token, false if not
*/
bool isAliasToken(const Token *tok) const;
};
/**

View File

@ -3847,7 +3847,7 @@ void Tokenizer::createLinks2()
while (!type.empty() && type.top()->str() == "<") {
const Token* end = type.top()->findClosingBracket();
if (Token::Match(end, "> %comp%|;|."))
if (Token::Match(end, "> %comp%|;|.|="))
break;
// Variable declaration
if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
@ -3871,7 +3871,7 @@ void Tokenizer::createLinks2()
if (token->str() == ">>")
continue;
if (token->next() &&
!Token::Match(token->next(), "%name%|%comp%|&|&&|*|::|,|(|)|{|}|;|[|:|.") &&
!Token::Match(token->next(), "%name%|%comp%|&|&&|*|::|,|(|)|{|}|;|[|:|.|=") &&
!Token::simpleMatch(token->next(), ". . .") &&
!Token::Match(token->next(), "&& %name% ="))
continue;

View File

@ -147,6 +147,8 @@ private:
TEST_CASE(template107); // #8663
TEST_CASE(template108); // #9109
TEST_CASE(template109); // #9144
TEST_CASE(template110);
TEST_CASE(template111); // crash
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)
@ -195,6 +197,10 @@ private:
TEST_CASE(simplifyTemplateArgs);
TEST_CASE(template_variadic_1); // #9144
TEST_CASE(template_variable_1);
TEST_CASE(template_variable_2);
TEST_CASE(template_variable_3);
}
std::string tok(const char code[], bool debugwarnings = false, Settings::PlatformType type = Settings::Native) {
@ -1356,12 +1362,19 @@ private:
"\n"
"void j() { h<int>(); }";
const char exp[] = "struct S<int> ; "
"template < typename T > void f ( ) { } " // <- TODO: This template is not expanded
"void f<S<int>::type(0)> ( ) ; "
"void h<int> ( ) ; "
"void j ( ) { h<int> ( ) ; } "
"void h<int> ( ) { f < S<int> :: type ( 0 ) > ( ) ; } "
"struct S<int> { } ;";
ASSERT_EQUALS(exp, tok(code));
"void h<int> ( ) { f<S<int>::type(0)> ( ) ; } "
"struct S<int> { } ; "
"void f<S<int>::type(0)> ( ) { }";
const char act[] = "template < typename T > struct S { } ; "
"void f<S<int>::type(0)> ( ) ; "
"void h<int> ( ) ; "
"void j ( ) { h<int> ( ) ; } "
"void h<int> ( ) { f<S<int>::type(0)> ( ) ; } "
"void f<S<int>::type(0)> ( ) { }";
TODO_ASSERT_EQUALS(exp, act, tok(code));
}
void template61() { // hang in daca, code extracted from kodi
@ -2254,8 +2267,7 @@ private:
" delete a;\n"
" });\n"
"}";
const char exp[] = "; "
"class A { } ; "
const char exp[] = "class A { } ; "
"static void func ( ) { "
"std :: unique_ptr < A , std :: function < void ( A * ) > > tmp ( new A ( ) , [ ] ( A * a ) { "
"delete a ; "
@ -2537,25 +2549,32 @@ private:
const char code[] = "namespace a {\n"
"template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
"}\n"
"namespace boost {\n"
"using a::c;\n"
"}\n"
"namespace d = boost;\n"
"using d::c;\n"
"template <typename...> struct e {};\n"
"static_assert(sizeof(e<>) == sizeof(e<c<int>, c<int>, int>), \"\");\n";
const char exp[] = "namespace a { "
"template < typename b , bool > struct c ; "
"} "
"namespace boost { "
"using a :: c ; "
"} "
"using boost :: c ; "
"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> ; "
"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<c<int>,c<int>,int> ; "
"static_assert ( sizeof ( e<> ) == sizeof ( e<c<int>,c<int>,int> ) , \"\" ) ; "
"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>,c<int>,int> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "namespace a {\n"
"template <typename b, bool = __is_empty(b) && __is_final(b)> struct c;\n"
"}\n"
"template <typename...> struct e {};\n"
"static_assert(sizeof(e<>) == sizeof(e<a::c<int>, a::c<int>, int>), \"\");\n";
const char exp[] = "namespace a { "
"template < typename b , bool > struct c ; "
"} "
"struct e<> ; "
"struct e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ; "
"static_assert ( sizeof ( e<> ) == sizeof ( e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> ) , \"\" ) ; "
"struct e<> { } ; "
"struct e<a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,a::c<int,std::is_empty<int>{}&&std::is_final<int>{}>,int> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
@ -2578,6 +2597,36 @@ private:
"struct c<int,std::is_empty<int>{}&&std::is_final<int>{}> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
{
const char code[] = "template <typename b, bool = unknown1(b) && unknown2(b)> struct c{};\n"
"c<int> cc;\n";
const char exp[] = "struct c<int,unknown1(int)&&unknown2(int)> ; "
"c<int,unknown1(int)&&unknown2(int)> cc ; "
"struct c<int,unknown1(int)&&unknown2(int)> { } ;";
ASSERT_EQUALS(exp, tok(code));
}
}
void template110() {
const char code[] = "template<typename T> using A = int;\n"
"template<typename T> using A<T*> = char;\n"
"template<> using A<char> = char;\n"
"template using A<char> = char;\n"
"using A<char> = char;";
const char exp[] = "template < typename T > using A = int ; "
"template < typename T > using A < T * > = char ; "
"template < > using A < char > = char ; "
"template using A < char > = char ; "
"using A < char > = char ;";
ASSERT_EQUALS(exp, tok(code));
}
void template111() { // crash
const char code[] = "template<typename T, typename U> struct pair;\n"
"template<typename T> using cell = pair<T*, cell<T>*>;";
const char exp[] = "template < typename T , typename U > struct pair ; "
"template < typename T > using cell = pair < T * , cell < T > * > ;";
ASSERT_EQUALS(exp, tok(code));
}
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
@ -2648,8 +2697,6 @@ private:
" A<int,2> a1;\n"
" A<int> a2;\n"
"}\n";
// The expected result..
const char expected[] = "class A<int,2> ; "
"class A<int,3> ; "
"void f ( ) "
@ -2674,7 +2721,6 @@ private:
" A<int,3> a2;\n"
"}\n";
// The expected result..
const char expected[] = "class A<int,3,2> ; "
"void f ( ) "
"{"
@ -2695,29 +2741,18 @@ private:
" A<int,(int)2> a1;\n"
" A<int> a2;\n"
"}\n";
const char wanted[] = "template < class T , int n >"
" class A"
" { T ar [ n ] ; } ;"
" void f ( )"
" {"
" A<int,(int)2> a1 ;"
" A<int,3> a2 ;"
" }"
" class A<int,2>"
" { int ar [ 2 ] ; }"
" class A<int,3>"
" { int ar [ 3 ] ; }";
const char current[] = "class A<int,3> ; "
"void f ( ) "
"{ "
"A < int , ( int ) 2 > a1 ; "
"A<int,3> a2 ; "
"} "
"class A<int,3> "
"{ int ar [ 3 ] ; } ;";
TODO_ASSERT_EQUALS(wanted, current, tok(code));
const char expected[] = "class A<int,(int)2> ; "
"class A<int,3> ; "
"void f ( ) "
"{ "
"A<int,(int)2> a1 ; "
"A<int,3> a2 ; "
"} "
"class A<int,(int)2> "
"{ int ar [ ( int ) 2 ] ; } ; "
"class A<int,3> "
"{ int ar [ 3 ] ; } ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "class A { }; "
@ -3560,7 +3595,6 @@ private:
"Bar<int> b;\n";
const char expected[] = "namespace A { struct Foo<int,3> ; } "
"; "
"A :: Foo<int,3> b ; "
"struct A :: Foo<int,3> { } ;";
@ -3582,8 +3616,7 @@ private:
"using IntrusivePtr = boost::intrusive_ptr<T>;\n"
"template <class T> class Vertex { };\n"
"IntrusivePtr<Vertex<int>> p;";
const char expected[] = "; "
"class Vertex<int> ; "
const char expected[] = "class Vertex<int> ; "
"boost :: intrusive_ptr < Vertex<int> > p ; "
"class Vertex<int> { } ;";
ASSERT_EQUALS(expected, tok(code));
@ -3758,6 +3791,106 @@ private:
ASSERT_EQUALS(expected, tok(code));
}
void template_variable_1() {
{
const char code[] = "template <int N> const int foo = N*N;\n"
"int x = foo<7>;";
const char expected[] = "const int foo<7> = 49 ; "
"int x ; x = foo<7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template <int> const int foo = 7;\n"
"int x = foo<7>;";
const char expected[] = "const int foo<7> = 7 ; "
"int x ; x = foo<7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template <int N = 7> const int foo = N*N;\n"
"int x = foo<7>;";
const char expected[] = "const int foo<7> = 49 ; "
"int x ; x = foo<7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template <int N = 7> const int foo = N*N;\n"
"int x = foo<>;";
const char expected[] = "const int foo<7> = 49 ; "
"int x ; x = foo<7> ;";
ASSERT_EQUALS(expected, tok(code));
}
}
void template_variable_2() {
{
const char code[] = "template<class T> constexpr T pi = T(3.1415926535897932385L);\n"
"float x = pi<float>;";
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
"float x ; x = pi<float> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class> constexpr float pi = float(3.1415926535897932385L);\n"
"float x = pi<float>;";
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
"float x ; x = pi<float> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class T = float> constexpr T pi = T(3.1415926535897932385L);\n"
"float x = pi<float>;";
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
"float x ; x = pi<float> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class T = float> constexpr T pi = T(3.1415926535897932385L);\n"
"float x = pi<>;";
const char expected[] = "const float pi<float> = float ( 3.1415926535897932385L ) ; "
"float x ; x = pi<float> ;";
ASSERT_EQUALS(expected, tok(code));
}
}
void template_variable_3() {
{
const char code[] = "template<class T, int N> constexpr T foo = T(N*N);\n"
"float x = foo<float,7>;";
const char expected[] = "const float foo<float,7> = float ( 49 ) ; "
"float x ; x = foo<float,7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class,int> constexpr float foo = float(7);\n"
"float x = foo<float,7>;";
const char expected[] = "const float foo<float,7> = float ( 7 ) ; "
"float x ; x = foo<float,7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
"double x = foo<double, 14>;";
const char expected[] = "const double foo<double,14> = double ( 7 ) ; "
"double x ; x = foo<double,14> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
"float x = foo<>;";
const char expected[] = "const float foo<float,7> = float ( 7 ) ; "
"float x ; x = foo<float,7> ;";
ASSERT_EQUALS(expected, tok(code));
}
{
const char code[] = "template<class T = float, int N = 7> constexpr T foo = T(7);\n"
"double x = foo<double>;";
const char expected[] = "const double foo<double,7> = double ( 7 ) ; "
"double x ; x = foo<double,7> ;";
ASSERT_EQUALS(expected, tok(code));
}
}
};
REGISTER_TEST(TestSimplifyTemplate)

View File

@ -5229,12 +5229,12 @@ private:
"struct S\n"
"{};\n"
"S<int> s;\n";
TODO_ASSERT_EQUALS("S<int,(int)0> s ; struct S<int,(int)0> { } ;", // wanted result
"template < class T , T t >\n"
"struct S\n"
"{ } ;\n"
"S < int , ( int ) 0 > s ;", // current result
tokenizeAndStringify(code));
ASSERT_EQUALS("struct S<int,(int)0> ;\n"
"\n"
"\n"
"S<int,(int)0> s ; struct S<int,(int)0>\n"
"{ } ;",
tokenizeAndStringify(code));
}
void cpp0xtemplate4() { // #6181, #6354, #6414

View File

@ -2192,8 +2192,7 @@ private:
void varid_templateUsing() { // #5781 #7273
const char code[] = "template<class T> using X = Y<T,4>;\n"
"X<int> x;";
ASSERT_EQUALS("1: ;\n"
"2: Y < int , 4 > x@1 ;\n",
ASSERT_EQUALS("2: Y < int , 4 > x@1 ;\n",
tokenize(code));
}