Fixed #4349 (Support C++11 variadic templates)
This commit is contained in:
parent
3bc71f982a
commit
9a9043a07e
|
@ -120,7 +120,7 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
|
||||||
isClass(Token::Match(next, "class|struct|union %name% <|{|:|;|::"));
|
isClass(Token::Match(next, "class|struct|union %name% <|{|:|;|::"));
|
||||||
if (mToken->strAt(1) == "<" && !isSpecialization()) {
|
if (mToken->strAt(1) == "<" && !isSpecialization()) {
|
||||||
const Token *end = mToken->next()->findClosingBracket();
|
const Token *end = mToken->next()->findClosingBracket();
|
||||||
isVariadic(end && Token::findmatch(mToken->tokAt(2), "typename|class ...", end));
|
isVariadic(end && Token::findmatch(mToken->tokAt(2), "%name% ...", end));
|
||||||
}
|
}
|
||||||
const Token *tok1 = mNameToken->next();
|
const Token *tok1 = mNameToken->next();
|
||||||
if (tok1->str() == "<") {
|
if (tok1->str() == "<") {
|
||||||
|
@ -1324,11 +1324,12 @@ void TemplateSimplifier::simplifyTemplateAliases()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[])
|
bool TemplateSimplifier::instantiateMatch(const Token *instance, const std::size_t numberOfArguments, bool variadic, const char patternAfter[])
|
||||||
{
|
{
|
||||||
assert(instance->strAt(1) == "<");
|
assert(instance->strAt(1) == "<");
|
||||||
|
|
||||||
if (numberOfArguments != templateParameters(instance->next()))
|
auto n = templateParameters(instance->next());
|
||||||
|
if (variadic ? (n + 1 < numberOfArguments) : (numberOfArguments != n))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (patternAfter) {
|
if (patternAfter) {
|
||||||
|
@ -1650,8 +1651,12 @@ void TemplateSimplifier::expandTemplate(
|
||||||
std::stack<Token *> brackets1; // holds "(" and "{" tokens
|
std::stack<Token *> brackets1; // holds "(" and "{" tokens
|
||||||
bool pointerType = false;
|
bool pointerType = false;
|
||||||
Token * const dst1 = dst->previous();
|
Token * const dst1 = dst->previous();
|
||||||
|
const bool isVariadicTemplateArg = templateDeclaration.isVariadic() && itype + 1 == typeParametersInDeclaration.size();
|
||||||
|
if (isVariadicTemplateArg && Token::Match(start, "%name% ... %name%"))
|
||||||
|
start = start->tokAt(2);
|
||||||
|
const std::string endsWith(isVariadicTemplateArg ? ">" : ",>");
|
||||||
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token();
|
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token();
|
||||||
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
|
typetok && (typeindentlevel > 0 || endsWith.find(typetok->str()[0]) == std::string::npos);
|
||||||
typetok = typetok->next()) {
|
typetok = typetok->next()) {
|
||||||
if (typeindentlevel == 0 && typetok->str() == "*")
|
if (typeindentlevel == 0 && typetok->str() == "*")
|
||||||
pointerType = true;
|
pointerType = true;
|
||||||
|
@ -1847,7 +1852,7 @@ void TemplateSimplifier::expandTemplate(
|
||||||
else if (inTemplateDefinition &&
|
else if (inTemplateDefinition &&
|
||||||
Token::Match(tok3, "%name% <") &&
|
Token::Match(tok3, "%name% <") &&
|
||||||
templateInstantiation.name() == tok3->str() &&
|
templateInstantiation.name() == tok3->str() &&
|
||||||
instantiateMatch(tok3, typeParametersInDeclaration.size(), ":: ~| %name% (")) {
|
instantiateMatch(tok3, typeParametersInDeclaration.size(), templateDeclaration.isVariadic(), ":: ~| %name% (")) {
|
||||||
// there must be template..
|
// there must be template..
|
||||||
bool istemplate = false;
|
bool istemplate = false;
|
||||||
Token * tok5 = nullptr; // start of function return type
|
Token * tok5 = nullptr; // start of function return type
|
||||||
|
@ -2003,8 +2008,12 @@ void TemplateSimplifier::expandTemplate(
|
||||||
std::stack<Token *> brackets1; // holds "(" and "{" tokens
|
std::stack<Token *> brackets1; // holds "(" and "{" tokens
|
||||||
Token * const beforeTypeToken = mTokenList.back();
|
Token * const beforeTypeToken = mTokenList.back();
|
||||||
bool pointerType = false;
|
bool pointerType = false;
|
||||||
|
const bool isVariadicTemplateArg = templateDeclaration.isVariadic() && itype + 1 == typeParametersInDeclaration.size();
|
||||||
|
if (isVariadicTemplateArg && Token::Match(tok3, "%name% ... %name%"))
|
||||||
|
tok3 = tok3->tokAt(2);
|
||||||
|
const std::string endsWith(isVariadicTemplateArg ? ">" : ",>");
|
||||||
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token();
|
for (const Token *typetok = mTypesUsedInTemplateInstantiation[itype].token();
|
||||||
typetok && (typeindentlevel > 0 || !Token::Match(typetok, ",|>"));
|
typetok && (typeindentlevel > 0 || endsWith.find(typetok->str()[0]) == std::string::npos);
|
||||||
typetok = typetok->next()) {
|
typetok = typetok->next()) {
|
||||||
if (typeindentlevel == 0 && typetok->str() == "*")
|
if (typeindentlevel == 0 && typetok->str() == "*")
|
||||||
pointerType = true;
|
pointerType = true;
|
||||||
|
@ -3091,7 +3100,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
|
if (Token::Match(startToken->previous(), ";|{|}|=|const") &&
|
||||||
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), isfunc ? "(" : isVar ? ";|%op%|(" : "*|&|::| %name%")))
|
(!specialized && !instantiateMatch(tok2, typeParametersInDeclaration.size(), templateDeclaration.isVariadic(), isfunc ? "(" : isVar ? ";|%op%|(" : "*|&|::| %name%")))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// New type..
|
// New type..
|
||||||
|
@ -3100,7 +3109,7 @@ bool TemplateSimplifier::simplifyTemplateInstantiations(
|
||||||
std::string typeForNewName = getNewName(tok2, typeStringsUsedInTemplateInstantiation);
|
std::string typeForNewName = getNewName(tok2, typeStringsUsedInTemplateInstantiation);
|
||||||
|
|
||||||
if ((typeForNewName.empty() && !templateDeclaration.isVariadic()) ||
|
if ((typeForNewName.empty() && !templateDeclaration.isVariadic()) ||
|
||||||
(!typeParametersInDeclaration.empty() && typeParametersInDeclaration.size() != mTypesUsedInTemplateInstantiation.size())) {
|
(!typeParametersInDeclaration.empty() && !instantiateMatch(tok2, typeParametersInDeclaration.size(), templateDeclaration.isVariadic(), nullptr))) {
|
||||||
if (printDebug && mErrorLogger) {
|
if (printDebug && mErrorLogger) {
|
||||||
std::list<const Token *> callstack(1, tok2);
|
std::list<const Token *> callstack(1, tok2);
|
||||||
mErrorLogger->reportErr(ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
mErrorLogger->reportErr(ErrorMessage(callstack, &mTokenList, Severity::debug, "debug",
|
||||||
|
|
|
@ -258,10 +258,11 @@ public:
|
||||||
* Match template declaration/instantiation
|
* Match template declaration/instantiation
|
||||||
* @param instance template instantiation
|
* @param instance template instantiation
|
||||||
* @param numberOfArguments number of template arguments
|
* @param numberOfArguments number of template arguments
|
||||||
|
* @param variadic last template argument is variadic
|
||||||
* @param patternAfter pattern that must match the tokens after the ">"
|
* @param patternAfter pattern that must match the tokens after the ">"
|
||||||
* @return match => true
|
* @return match => true
|
||||||
*/
|
*/
|
||||||
static bool instantiateMatch(const Token *instance, const std::size_t numberOfArguments, const char patternAfter[]);
|
static bool instantiateMatch(const Token *instance, const std::size_t numberOfArguments, bool variadic, const char patternAfter[]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match template declaration/instantiation
|
* Match template declaration/instantiation
|
||||||
|
|
|
@ -93,7 +93,6 @@ private:
|
||||||
TEST_CASE(template48); // #6134 - 100% CPU upon invalid code
|
TEST_CASE(template48); // #6134 - 100% CPU upon invalid code
|
||||||
TEST_CASE(template49); // #6237 - template instantiation
|
TEST_CASE(template49); // #6237 - template instantiation
|
||||||
TEST_CASE(template50); // #4272 - simple partial specialization
|
TEST_CASE(template50); // #4272 - simple partial specialization
|
||||||
TEST_CASE(template51); // #6172 - crash upon valid code
|
|
||||||
TEST_CASE(template52); // #6437 - crash upon valid code
|
TEST_CASE(template52); // #6437 - crash upon valid code
|
||||||
TEST_CASE(template53); // #4335 - bail out for valid code
|
TEST_CASE(template53); // #4335 - bail out for valid code
|
||||||
TEST_CASE(template54); // #6587 - memory corruption upon valid code
|
TEST_CASE(template54); // #6587 - memory corruption upon valid code
|
||||||
|
@ -271,6 +270,8 @@ private:
|
||||||
TEST_CASE(simplifyTemplateArgs2);
|
TEST_CASE(simplifyTemplateArgs2);
|
||||||
|
|
||||||
TEST_CASE(template_variadic_1); // #9144
|
TEST_CASE(template_variadic_1); // #9144
|
||||||
|
TEST_CASE(template_variadic_2); // #4349
|
||||||
|
TEST_CASE(template_variadic_3); // #6172
|
||||||
|
|
||||||
TEST_CASE(template_variable_1);
|
TEST_CASE(template_variable_1);
|
||||||
TEST_CASE(template_variable_2);
|
TEST_CASE(template_variable_2);
|
||||||
|
@ -1252,17 +1253,6 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
void template51() { // #6172
|
|
||||||
tok("template<int N, int ... M> struct A { "
|
|
||||||
" static void foo() { "
|
|
||||||
" int i = N; "
|
|
||||||
" } "
|
|
||||||
"}; "
|
|
||||||
"void bar() { "
|
|
||||||
" A<0>::foo(); "
|
|
||||||
"}");
|
|
||||||
}
|
|
||||||
|
|
||||||
void template52() { // #6437
|
void template52() { // #6437
|
||||||
const char code[] = "template <int value> int sum() { "
|
const char code[] = "template <int value> int sum() { "
|
||||||
" return value + sum<value/2>(); "
|
" return value + sum<value/2>(); "
|
||||||
|
@ -5493,7 +5483,7 @@ private:
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
tokenizer.tokenize(istr, "test.cpp", "");
|
tokenizer.tokenize(istr, "test.cpp", "");
|
||||||
|
|
||||||
return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), numberOfArguments, patternAfter);
|
return TemplateSimplifier::instantiateMatch(tokenizer.tokens(), numberOfArguments, false, patternAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void instantiateMatch() {
|
void instantiateMatch() {
|
||||||
|
@ -5841,6 +5831,34 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template_variadic_2() { // #4349
|
||||||
|
const char code[] = "template<typename T, typename... Args>\n"
|
||||||
|
"void printf(const char *s, T value, Args... args) {}\n"
|
||||||
|
"\n"
|
||||||
|
"int main() {\n"
|
||||||
|
" printf<int, float>(\"\", foo, bar);\n"
|
||||||
|
"}";
|
||||||
|
const char expected[] = "void printf<int,float> ( const char * s , int value , float ) ; "
|
||||||
|
"int main ( ) { printf<int,float> ( \"\" , foo , bar ) ; } "
|
||||||
|
"void printf<int,float> ( const char * s , int value , float ) { }";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
|
void template_variadic_3() { // #6172
|
||||||
|
const char code[] = "template<int N, int ... M> struct A { "
|
||||||
|
" static void foo() { "
|
||||||
|
" int i = N; "
|
||||||
|
" } "
|
||||||
|
"}; "
|
||||||
|
"void bar() { "
|
||||||
|
" A<0>::foo(); "
|
||||||
|
"}";
|
||||||
|
const char expected[] = "struct A<0> ; "
|
||||||
|
"void bar ( ) { A<0> :: foo ( ) ; } "
|
||||||
|
"struct A<0> { static void foo ( ) { int i ; i = 0 ; } } ;";
|
||||||
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
|
}
|
||||||
|
|
||||||
void template_variable_1() {
|
void template_variable_1() {
|
||||||
{
|
{
|
||||||
const char code[] = "template <int N> const int foo = N*N;\n"
|
const char code[] = "template <int N> const int foo = N*N;\n"
|
||||||
|
|
Loading…
Reference in New Issue