template simplifier: ignore friend templates (#2122)
* template simplifier: ignore friend templates friend templates were interpreted as variable templates * fix cppcheck warning
This commit is contained in:
parent
d918f76a0d
commit
3a1aec8850
|
@ -105,7 +105,12 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
|
||||||
throw InternalError(mToken, "explicit specialization of alias templates is not permitted", InternalError::SYNTAX);
|
throw InternalError(mToken, "explicit specialization of alias templates is not permitted", InternalError::SYNTAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
isClass(Token::Match(mParamEnd->next(), "class|struct|union %name% <|{|:|;|::"));
|
isFriend(mParamEnd->strAt(1) == "friend");
|
||||||
|
const Token *next = mParamEnd->next();
|
||||||
|
if (isFriend())
|
||||||
|
next = next->next();
|
||||||
|
|
||||||
|
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), "typename|class . . .", end));
|
||||||
|
@ -119,7 +124,8 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
|
||||||
throw InternalError(mToken, "unsupported syntax", InternalError::SYNTAX);
|
throw InternalError(mToken, "unsupported syntax", InternalError::SYNTAX);
|
||||||
}
|
}
|
||||||
isFunction(tok1->str() == "(");
|
isFunction(tok1->str() == "(");
|
||||||
isVariable(!isClass() && !isAlias() && Token::Match(tok1, "=|;"));
|
isVariable(!isClass() && !isAlias() && !isFriend() && Token::Match(tok1, "=|;"));
|
||||||
|
if (!isFriend()) {
|
||||||
if (isVariable())
|
if (isVariable())
|
||||||
isForwardDeclaration(tok1->str() == ";");
|
isForwardDeclaration(tok1->str() == ";");
|
||||||
else if (!isAlias()) {
|
else if (!isAlias()) {
|
||||||
|
@ -136,6 +142,7 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
|
||||||
if (tok1)
|
if (tok1)
|
||||||
isForwardDeclaration(tok1->str() == ";");
|
isForwardDeclaration(tok1->str() == ";");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// check for member class or function and adjust scope
|
// check for member class or function and adjust scope
|
||||||
if ((isFunction() || isClass()) && mNameToken->strAt(-1) == "::") {
|
if ((isFunction() || isClass()) && mNameToken->strAt(-1) == "::") {
|
||||||
const Token * start = mNameToken;
|
const Token * start = mNameToken;
|
||||||
|
@ -983,7 +990,7 @@ void TemplateSimplifier::useDefaultArgumentValues()
|
||||||
void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
|
void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
|
||||||
{
|
{
|
||||||
// Ticket #5762: Skip specialization tokens
|
// Ticket #5762: Skip specialization tokens
|
||||||
if (declaration.isSpecialization() || declaration.isAlias())
|
if (declaration.isSpecialization() || declaration.isAlias() || declaration.isFriend())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// template parameters with default value has syntax such as:
|
// template parameters with default value has syntax such as:
|
||||||
|
@ -1395,9 +1402,9 @@ bool TemplateSimplifier::getTemplateNamePositionTemplateVariable(const Token *to
|
||||||
|
|
||||||
bool TemplateSimplifier::getTemplateNamePositionTemplateClass(const Token *tok, int &namepos)
|
bool TemplateSimplifier::getTemplateNamePositionTemplateClass(const Token *tok, int &namepos)
|
||||||
{
|
{
|
||||||
if (Token::Match(tok, "> class|struct|union %type% :|<|;|{|::")) {
|
if (Token::Match(tok, "> friend| class|struct|union %type% :|<|;|{|::")) {
|
||||||
namepos = 2;
|
namepos = tok->strAt(1) == "friend" ? 3 : 2;
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(namepos);
|
||||||
while (Token::Match(tok, "%type% :: %type%") ||
|
while (Token::Match(tok, "%type% :: %type%") ||
|
||||||
(Token::Match(tok, "%type% <") && Token::Match(tok->next()->findClosingBracket(), "> :: %type%"))) {
|
(Token::Match(tok, "%type% <") && Token::Match(tok->next()->findClosingBracket(), "> :: %type%"))) {
|
||||||
if (tok->strAt(1) == "::") {
|
if (tok->strAt(1) == "::") {
|
||||||
|
@ -2026,7 +2033,11 @@ void TemplateSimplifier::expandTemplate(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (copy) {
|
// don't modify friend
|
||||||
|
if (Token::Match(tok3->tokAt(-3), "> friend class|struct|union")) {
|
||||||
|
if (copy)
|
||||||
|
mTokenList.addtoken(tok3);
|
||||||
|
} else if (copy) {
|
||||||
// add namespace if necessary
|
// add namespace if necessary
|
||||||
if (!templateDeclaration.scope().empty() &&
|
if (!templateDeclaration.scope().empty() &&
|
||||||
(isClass ? tok3->strAt(1) != "(" : true)) {
|
(isClass ? tok3->strAt(1) != "(" : true)) {
|
||||||
|
@ -3154,7 +3165,7 @@ static bool specMatch(
|
||||||
const TemplateSimplifier::TokenAndName &decl)
|
const TemplateSimplifier::TokenAndName &decl)
|
||||||
{
|
{
|
||||||
// make sure decl is really a declaration
|
// make sure decl is really a declaration
|
||||||
if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias())
|
if (decl.isPartialSpecialization() || decl.isSpecialization() || decl.isAlias() || decl.isFriend())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return spec.isSameFamily(decl);
|
return spec.isSameFamily(decl);
|
||||||
|
@ -3237,8 +3248,8 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
||||||
getTemplateParametersInDeclaration(forwardDecl.token()->tokAt(2), params1);
|
getTemplateParametersInDeclaration(forwardDecl.token()->tokAt(2), params1);
|
||||||
|
|
||||||
for (auto & decl : mTemplateDeclarations) {
|
for (auto & decl : mTemplateDeclarations) {
|
||||||
// skip partializations
|
// skip partializations, type aliases and friends
|
||||||
if (decl.isPartialSpecialization())
|
if (decl.isPartialSpecialization() || decl.isAlias() || decl.isFriend())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<const Token *> params2;
|
std::vector<const Token *> params2;
|
||||||
|
@ -3321,6 +3332,8 @@ void TemplateSimplifier::printOut(const TokenAndName &tokenAndName, const std::s
|
||||||
std::cout << " isForwardDeclaration";
|
std::cout << " isForwardDeclaration";
|
||||||
if (tokenAndName.isVariadic())
|
if (tokenAndName.isVariadic())
|
||||||
std::cout << " isVariadic";
|
std::cout << " isVariadic";
|
||||||
|
if (tokenAndName.isFriend())
|
||||||
|
std::cout << " isFriend";
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
if (tokenAndName.token() && !tokenAndName.paramEnd() && tokenAndName.token()->strAt(1) == "<") {
|
if (tokenAndName.token() && !tokenAndName.paramEnd() && tokenAndName.token()->strAt(1) == "<") {
|
||||||
const Token *end = tokenAndName.token()->next()->findClosingBracket();
|
const Token *end = tokenAndName.token()->next()->findClosingBracket();
|
||||||
|
@ -3544,13 +3557,13 @@ void TemplateSimplifier::simplifyTemplates(
|
||||||
std::set<std::string> expandedtemplates;
|
std::set<std::string> expandedtemplates;
|
||||||
|
|
||||||
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
||||||
if (iter1->isAlias())
|
if (iter1->isAlias() || iter1->isFriend())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// get specializations..
|
// get specializations..
|
||||||
std::list<const Token *> specializations;
|
std::list<const Token *> specializations;
|
||||||
for (std::list<TokenAndName>::const_iterator iter2 = mTemplateDeclarations.begin(); iter2 != mTemplateDeclarations.end(); ++iter2) {
|
for (std::list<TokenAndName>::const_iterator iter2 = mTemplateDeclarations.begin(); iter2 != mTemplateDeclarations.end(); ++iter2) {
|
||||||
if (iter2->isAlias())
|
if (iter2->isAlias() || iter2->isFriend())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (iter1->fullName() == iter2->fullName())
|
if (iter1->fullName() == iter2->fullName())
|
||||||
|
|
|
@ -87,6 +87,7 @@ public:
|
||||||
fIsPartialSpecialization = (1 << 5), // user partial specialized template
|
fIsPartialSpecialization = (1 << 5), // user partial specialized template
|
||||||
fIsForwardDeclaration = (1 << 6), // forward declaration
|
fIsForwardDeclaration = (1 << 6), // forward declaration
|
||||||
fIsVariadic = (1 << 7), // variadic template
|
fIsVariadic = (1 << 7), // variadic template
|
||||||
|
fIsFriend = (1 << 8), // friend template
|
||||||
fFamilyMask = (fIsClass | fIsFunction | fIsVariable)
|
fFamilyMask = (fIsClass | fIsFunction | fIsVariable)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -114,6 +115,9 @@ public:
|
||||||
void isVariadic(bool state) {
|
void isVariadic(bool state) {
|
||||||
setFlag(fIsVariadic, state);
|
setFlag(fIsVariadic, state);
|
||||||
}
|
}
|
||||||
|
void isFriend(bool state) {
|
||||||
|
setFlag(fIsFriend, state);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get specified flag state.
|
* Get specified flag state.
|
||||||
|
@ -205,6 +209,9 @@ public:
|
||||||
bool isVariadic() const {
|
bool isVariadic() const {
|
||||||
return getFlag(fIsVariadic);
|
return getFlag(fIsVariadic);
|
||||||
}
|
}
|
||||||
|
bool isFriend() const {
|
||||||
|
return getFlag(fIsFriend);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get alias start token.
|
* Get alias start token.
|
||||||
|
|
|
@ -176,6 +176,7 @@ private:
|
||||||
TEST_CASE(template136); // #9287
|
TEST_CASE(template136); // #9287
|
||||||
TEST_CASE(template137); // #9288
|
TEST_CASE(template137); // #9288
|
||||||
TEST_CASE(template138);
|
TEST_CASE(template138);
|
||||||
|
TEST_CASE(template139);
|
||||||
TEST_CASE(template_specialization_1); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
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_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)
|
TEST_CASE(template_enum); // #6299 Syntax error in complex enum declaration (including template)
|
||||||
|
@ -3364,6 +3365,33 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void template139() {
|
||||||
|
{
|
||||||
|
const char code[] = "template<typename T>\n"
|
||||||
|
"struct Foo {\n"
|
||||||
|
" template<typename> friend struct Foo;\n"
|
||||||
|
"};";
|
||||||
|
const char exp[] = "template < typename T > "
|
||||||
|
"struct Foo { "
|
||||||
|
"template < typename > friend struct Foo ; "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const char code[] = "template<typename T>\n"
|
||||||
|
"struct Foo {\n"
|
||||||
|
" template<typename> friend struct Foo;\n"
|
||||||
|
"} ;\n"
|
||||||
|
"Foo<int> foo;";
|
||||||
|
const char exp[] = "struct Foo<int> ; "
|
||||||
|
"Foo<int> foo ; "
|
||||||
|
"struct Foo<int> { "
|
||||||
|
"template < typename > friend struct Foo ; "
|
||||||
|
"} ;";
|
||||||
|
ASSERT_EQUALS(exp, tok(code));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
void template_specialization_1() { // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||||
const char code[] = "template <typename T> struct C {};\n"
|
const char code[] = "template <typename T> struct C {};\n"
|
||||||
"template <typename T> struct S {a};\n"
|
"template <typename T> struct S {a};\n"
|
||||||
|
|
Loading…
Reference in New Issue