parent
96cf2b34fd
commit
77717f73fd
|
@ -1583,6 +1583,12 @@ bool TemplateSimplifier::alreadyHasNamespace(const TokenAndName &templateDeclara
|
||||||
return Token::simpleMatch(tok->tokAt(offset), scope.c_str(), scope.size());
|
return Token::simpleMatch(tok->tokAt(offset), scope.c_str(), scope.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct newInstantiation {
|
||||||
|
newInstantiation(Token* t, std::string s) : token(t), scope(std::move(s)) {}
|
||||||
|
Token* token;
|
||||||
|
std::string scope;
|
||||||
|
};
|
||||||
|
|
||||||
void TemplateSimplifier::expandTemplate(
|
void TemplateSimplifier::expandTemplate(
|
||||||
const TokenAndName &templateDeclaration,
|
const TokenAndName &templateDeclaration,
|
||||||
const TokenAndName &templateInstantiation,
|
const TokenAndName &templateInstantiation,
|
||||||
|
@ -1599,11 +1605,7 @@ void TemplateSimplifier::expandTemplate(
|
||||||
const bool isFunction = templateDeclaration.isFunction();
|
const bool isFunction = templateDeclaration.isFunction();
|
||||||
const bool isSpecialization = templateDeclaration.isSpecialization();
|
const bool isSpecialization = templateDeclaration.isSpecialization();
|
||||||
const bool isVariable = templateDeclaration.isVariable();
|
const bool isVariable = templateDeclaration.isVariable();
|
||||||
struct newInstantiation {
|
|
||||||
newInstantiation(Token *t, std::string s) : token(t), scope(std::move(s)) {}
|
|
||||||
Token *token;
|
|
||||||
std::string scope;
|
|
||||||
};
|
|
||||||
std::vector<newInstantiation> newInstantiations;
|
std::vector<newInstantiation> newInstantiations;
|
||||||
|
|
||||||
// add forward declarations
|
// add forward declarations
|
||||||
|
@ -2251,7 +2253,9 @@ void TemplateSimplifier::expandTemplate(
|
||||||
|
|
||||||
// add new instantiations
|
// add new instantiations
|
||||||
for (const auto & inst : newInstantiations) {
|
for (const auto & inst : newInstantiations) {
|
||||||
simplifyTemplateArgs(inst.token->tokAt(2), inst.token->next()->findClosingBracket());
|
if (!inst.token)
|
||||||
|
continue;
|
||||||
|
simplifyTemplateArgs(inst.token->tokAt(2), inst.token->next()->findClosingBracket(), &newInstantiations);
|
||||||
// only add recursive instantiation if its arguments are a constant expression
|
// only add recursive instantiation if its arguments are a constant expression
|
||||||
if (templateDeclaration.name() != inst.token->str() ||
|
if (templateDeclaration.name() != inst.token->str() ||
|
||||||
(inst.token->tokAt(2)->isNumber() || inst.token->tokAt(2)->isStandardType()))
|
(inst.token->tokAt(2)->isNumber() || inst.token->tokAt(2)->isStandardType()))
|
||||||
|
@ -2409,7 +2413,17 @@ static Token *skipTernaryOp(Token *tok, const Token *backToken)
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end)
|
static void invalidateInst(const Token* beg, const Token* end, std::vector<newInstantiation>* newInst) {
|
||||||
|
if (!newInst)
|
||||||
|
return;
|
||||||
|
for (auto& inst : *newInst) {
|
||||||
|
for (const Token* tok = beg; tok != end; tok = tok->next())
|
||||||
|
if (inst.token == tok)
|
||||||
|
inst.token = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end, std::vector<newInstantiation>* newInst)
|
||||||
{
|
{
|
||||||
// start could be erased so use the token before start if available
|
// start could be erased so use the token before start if available
|
||||||
Token * first = (start && start->previous()) ? start->previous() : mTokenList.front();
|
Token * first = (start && start->previous()) ? start->previous() : mTokenList.front();
|
||||||
|
@ -2517,6 +2531,7 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(tok->next(), "false|0")) {
|
if (Token::Match(tok->next(), "false|0")) {
|
||||||
|
invalidateInst(tok->next(), colon, newInst);
|
||||||
// Use code after colon, remove code before it.
|
// Use code after colon, remove code before it.
|
||||||
Token::eraseTokens(tok, colon);
|
Token::eraseTokens(tok, colon);
|
||||||
|
|
||||||
|
@ -2543,6 +2558,7 @@ void TemplateSimplifier::simplifyTemplateArgs(Token *start, const Token *end)
|
||||||
else if (endTok->str() == ">" && !end)
|
else if (endTok->str() == ">" && !end)
|
||||||
;
|
;
|
||||||
else {
|
else {
|
||||||
|
invalidateInst(colon->tokAt(-1), endTok, newInst);
|
||||||
Token::eraseTokens(colon->tokAt(-2), endTok);
|
Token::eraseTokens(colon->tokAt(-2), endTok);
|
||||||
again = true;
|
again = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -37,6 +37,7 @@ class Settings;
|
||||||
class Token;
|
class Token;
|
||||||
class Tokenizer;
|
class Tokenizer;
|
||||||
class TokenList;
|
class TokenList;
|
||||||
|
struct newInstantiation;
|
||||||
|
|
||||||
/// @addtogroup Core
|
/// @addtogroup Core
|
||||||
/// @{
|
/// @{
|
||||||
|
@ -333,7 +334,7 @@ public:
|
||||||
* @param start first token of arguments
|
* @param start first token of arguments
|
||||||
* @param end token following last argument token
|
* @param end token following last argument token
|
||||||
*/
|
*/
|
||||||
void simplifyTemplateArgs(Token *start, const Token *end);
|
void simplifyTemplateArgs(Token *start, const Token *end, std::vector<newInstantiation>* newInst = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -278,6 +278,7 @@ private:
|
||||||
|
|
||||||
TEST_CASE(simplifyTemplateArgs1);
|
TEST_CASE(simplifyTemplateArgs1);
|
||||||
TEST_CASE(simplifyTemplateArgs2);
|
TEST_CASE(simplifyTemplateArgs2);
|
||||||
|
TEST_CASE(simplifyTemplateArgs3);
|
||||||
|
|
||||||
TEST_CASE(template_variadic_1); // #9144
|
TEST_CASE(template_variadic_1); // #9144
|
||||||
TEST_CASE(template_variadic_2); // #4349
|
TEST_CASE(template_variadic_2); // #4349
|
||||||
|
@ -6051,6 +6052,35 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyTemplateArgs3() { // #11418
|
||||||
|
const char code[] = "template <class T> struct S {};\n"
|
||||||
|
"template<typename T>\n"
|
||||||
|
"T f() {}\n"
|
||||||
|
"template<typename T, typename U>\n"
|
||||||
|
"void g() {\n"
|
||||||
|
" S<decltype(true ? f<T>() : f<U>())> s1;\n"
|
||||||
|
" S<decltype(false ? f<T>() : f<U>())> s2;\n"
|
||||||
|
"}\n"
|
||||||
|
"void h() {\n"
|
||||||
|
" g<int, char>();\n"
|
||||||
|
"}\n";
|
||||||
|
const char expected[] = "struct S<decltype((f<int>()))> ; "
|
||||||
|
"struct S<decltype(f<char>())> ; "
|
||||||
|
"int f<int> ( ) ; "
|
||||||
|
"char f<char> ( ) ; "
|
||||||
|
"void g<int,char> ( ) ; "
|
||||||
|
"void h ( ) { g<int,char> ( ) ; } "
|
||||||
|
"void g<int,char> ( ) { "
|
||||||
|
"S<decltype((f<int>()))> s1 ; "
|
||||||
|
"S<decltype(f<char>())> s2 ; "
|
||||||
|
"} "
|
||||||
|
"int f<int> ( ) { } "
|
||||||
|
"char f<char> ( ) { } "
|
||||||
|
"struct S<decltype((f<int>()))> { } ; "
|
||||||
|
"struct S<decltype(f<char>())> { } ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
void template_variadic_1() { // #9144
|
void template_variadic_1() { // #9144
|
||||||
const char code[] = "template <typename...> struct e {};\n"
|
const char code[] = "template <typename...> struct e {};\n"
|
||||||
"static_assert(sizeof(e<>) == sizeof(e<int,int>), \"\");";
|
"static_assert(sizeof(e<>) == sizeof(e<int,int>), \"\");";
|
||||||
|
|
Loading…
Reference in New Issue