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);
|
||||
}
|
||||
|
||||
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()) {
|
||||
const Token *end = mToken->next()->findClosingBracket();
|
||||
isVariadic(end && Token::findmatch(mToken->tokAt(2), "typename|class . . .", end));
|
||||
|
@ -119,22 +124,24 @@ TemplateSimplifier::TokenAndName::TokenAndName(Token *token, const std::string &
|
|||
throw InternalError(mToken, "unsupported syntax", InternalError::SYNTAX);
|
||||
}
|
||||
isFunction(tok1->str() == "(");
|
||||
isVariable(!isClass() && !isAlias() && Token::Match(tok1, "=|;"));
|
||||
if (isVariable())
|
||||
isForwardDeclaration(tok1->str() == ";");
|
||||
else if (!isAlias()) {
|
||||
if (isFunction())
|
||||
tok1 = tok1->link()->next();
|
||||
while (tok1 && !Token::Match(tok1, ";|{")) {
|
||||
if (tok1->str() == "<")
|
||||
tok1 = tok1->findClosingBracket();
|
||||
else if (Token::Match(tok1, "(|[") && tok1->link())
|
||||
tok1 = tok1->link();
|
||||
if (tok1)
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
if (tok1)
|
||||
isVariable(!isClass() && !isAlias() && !isFriend() && Token::Match(tok1, "=|;"));
|
||||
if (!isFriend()) {
|
||||
if (isVariable())
|
||||
isForwardDeclaration(tok1->str() == ";");
|
||||
else if (!isAlias()) {
|
||||
if (isFunction())
|
||||
tok1 = tok1->link()->next();
|
||||
while (tok1 && !Token::Match(tok1, ";|{")) {
|
||||
if (tok1->str() == "<")
|
||||
tok1 = tok1->findClosingBracket();
|
||||
else if (Token::Match(tok1, "(|[") && tok1->link())
|
||||
tok1 = tok1->link();
|
||||
if (tok1)
|
||||
tok1 = tok1->next();
|
||||
}
|
||||
if (tok1)
|
||||
isForwardDeclaration(tok1->str() == ";");
|
||||
}
|
||||
}
|
||||
// check for member class or function and adjust scope
|
||||
if ((isFunction() || isClass()) && mNameToken->strAt(-1) == "::") {
|
||||
|
@ -983,7 +990,7 @@ void TemplateSimplifier::useDefaultArgumentValues()
|
|||
void TemplateSimplifier::useDefaultArgumentValues(TokenAndName &declaration)
|
||||
{
|
||||
// Ticket #5762: Skip specialization tokens
|
||||
if (declaration.isSpecialization() || declaration.isAlias())
|
||||
if (declaration.isSpecialization() || declaration.isAlias() || declaration.isFriend())
|
||||
return;
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (Token::Match(tok, "> class|struct|union %type% :|<|;|{|::")) {
|
||||
namepos = 2;
|
||||
tok = tok->tokAt(2);
|
||||
if (Token::Match(tok, "> friend| class|struct|union %type% :|<|;|{|::")) {
|
||||
namepos = tok->strAt(1) == "friend" ? 3 : 2;
|
||||
tok = tok->tokAt(namepos);
|
||||
while (Token::Match(tok, "%type% :: %type%") ||
|
||||
(Token::Match(tok, "%type% <") && Token::Match(tok->next()->findClosingBracket(), "> :: %type%"))) {
|
||||
if (tok->strAt(1) == "::") {
|
||||
|
@ -2026,7 +2033,11 @@ void TemplateSimplifier::expandTemplate(
|
|||
}
|
||||
}
|
||||
} 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
|
||||
if (!templateDeclaration.scope().empty() &&
|
||||
(isClass ? tok3->strAt(1) != "(" : true)) {
|
||||
|
@ -3154,7 +3165,7 @@ static bool specMatch(
|
|||
const TemplateSimplifier::TokenAndName &decl)
|
||||
{
|
||||
// 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 spec.isSameFamily(decl);
|
||||
|
@ -3237,8 +3248,8 @@ void TemplateSimplifier::fixForwardDeclaredDefaultArgumentValues()
|
|||
getTemplateParametersInDeclaration(forwardDecl.token()->tokAt(2), params1);
|
||||
|
||||
for (auto & decl : mTemplateDeclarations) {
|
||||
// skip partializations
|
||||
if (decl.isPartialSpecialization())
|
||||
// skip partializations, type aliases and friends
|
||||
if (decl.isPartialSpecialization() || decl.isAlias() || decl.isFriend())
|
||||
continue;
|
||||
|
||||
std::vector<const Token *> params2;
|
||||
|
@ -3321,6 +3332,8 @@ void TemplateSimplifier::printOut(const TokenAndName &tokenAndName, const std::s
|
|||
std::cout << " isForwardDeclaration";
|
||||
if (tokenAndName.isVariadic())
|
||||
std::cout << " isVariadic";
|
||||
if (tokenAndName.isFriend())
|
||||
std::cout << " isFriend";
|
||||
std::cout << std::endl;
|
||||
if (tokenAndName.token() && !tokenAndName.paramEnd() && tokenAndName.token()->strAt(1) == "<") {
|
||||
const Token *end = tokenAndName.token()->next()->findClosingBracket();
|
||||
|
@ -3544,13 +3557,13 @@ void TemplateSimplifier::simplifyTemplates(
|
|||
std::set<std::string> expandedtemplates;
|
||||
|
||||
for (std::list<TokenAndName>::reverse_iterator iter1 = mTemplateDeclarations.rbegin(); iter1 != mTemplateDeclarations.rend(); ++iter1) {
|
||||
if (iter1->isAlias())
|
||||
if (iter1->isAlias() || iter1->isFriend())
|
||||
continue;
|
||||
|
||||
// get specializations..
|
||||
std::list<const Token *> specializations;
|
||||
for (std::list<TokenAndName>::const_iterator iter2 = mTemplateDeclarations.begin(); iter2 != mTemplateDeclarations.end(); ++iter2) {
|
||||
if (iter2->isAlias())
|
||||
if (iter2->isAlias() || iter2->isFriend())
|
||||
continue;
|
||||
|
||||
if (iter1->fullName() == iter2->fullName())
|
||||
|
|
|
@ -87,6 +87,7 @@ public:
|
|||
fIsPartialSpecialization = (1 << 5), // user partial specialized template
|
||||
fIsForwardDeclaration = (1 << 6), // forward declaration
|
||||
fIsVariadic = (1 << 7), // variadic template
|
||||
fIsFriend = (1 << 8), // friend template
|
||||
fFamilyMask = (fIsClass | fIsFunction | fIsVariable)
|
||||
};
|
||||
|
||||
|
@ -114,6 +115,9 @@ public:
|
|||
void isVariadic(bool state) {
|
||||
setFlag(fIsVariadic, state);
|
||||
}
|
||||
void isFriend(bool state) {
|
||||
setFlag(fIsFriend, state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get specified flag state.
|
||||
|
@ -205,6 +209,9 @@ public:
|
|||
bool isVariadic() const {
|
||||
return getFlag(fIsVariadic);
|
||||
}
|
||||
bool isFriend() const {
|
||||
return getFlag(fIsFriend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get alias start token.
|
||||
|
|
|
@ -176,6 +176,7 @@ private:
|
|||
TEST_CASE(template136); // #9287
|
||||
TEST_CASE(template137); // #9288
|
||||
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_2); // #7868 - template specialization template <typename T> struct S<C<T>> {..};
|
||||
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>> {..};
|
||||
const char code[] = "template <typename T> struct C {};\n"
|
||||
"template <typename T> struct S {a};\n"
|
||||
|
|
Loading…
Reference in New Issue