C++: Fix variable template parsing in expression

Fix parser to not fail on TemplateId without parentheses, for example:
int i = foo<int> + foo<char>;

This fixes std::pair structure parsing in MSVC headers and find Usages
to work with pair->first and pair->second.

Change-Id: Ic300ea99d44a749705430d5eb47b2744715af995
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Volodymyr Zibarov
2020-05-29 14:57:45 +03:00
parent 1291eb975b
commit 3ad203b56e
3 changed files with 58 additions and 6 deletions

View File

@@ -5066,12 +5066,6 @@ bool Parser::parseNameId(NameAST *&name)
case T_CONST_CAST: case T_CONST_CAST:
rewind(start); rewind(start);
return parseName(name, false); return parseName(name, false);
default:
if (tok().isLiteral() || tok().isPunctuationOrOperator()) {
rewind(start);
return parseName(name, false);
}
} // switch } // switch
return true; return true;

View File

@@ -173,6 +173,7 @@ private slots:
//! "template<class ...Args> class T : Args... {};" //! "template<class ...Args> class T : Args... {};"
void cpp11_variadic_inheritance(); void cpp11_variadic_inheritance();
void cpp11_attributes(); void cpp11_attributes();
void variableTemplatesInExpression();
// Q_PROPERTY // Q_PROPERTY
void cpp_qproperty(); void cpp_qproperty();
@@ -1354,6 +1355,19 @@ void tst_AST::cpp11_attributes()
QVERIFY(attr != nullptr); QVERIFY(attr != nullptr);
} }
void tst_AST::variableTemplatesInExpression()
{
QSharedPointer<TranslationUnit> unit(parseDeclaration("int i = t<int> + t<char>;",
false, false, true));
AST *ast = unit->ast();
QVERIFY(ast != nullptr);
QCOMPARE(diag.errorCount, 0);
DeclarationAST *d = ast->asDeclaration();
QVERIFY(d != nullptr);
}
void tst_AST::if_constexpr() void tst_AST::if_constexpr()
{ {
QSharedPointer<TranslationUnit> unit(parseStatement("if constexpr (a) b;",true)); QSharedPointer<TranslationUnit> unit(parseStatement("if constexpr (a) b;",true));

View File

@@ -125,6 +125,7 @@ private Q_SLOTS:
void templatePartialSpecialization(); void templatePartialSpecialization();
void templatePartialSpecialization_2(); void templatePartialSpecialization_2();
void template_SFINAE_1(); void template_SFINAE_1();
void variableTemplateInExpression();
}; };
void tst_FindUsages::dump(const QList<Usage> &usages) const void tst_FindUsages::dump(const QList<Usage> &usages) const
@@ -1580,5 +1581,48 @@ int main(){
QCOMPARE(find.usages().size(), 2); QCOMPARE(find.usages().size(), 2);
} }
void tst_FindUsages::variableTemplateInExpression()
{
const QByteArray src =
R"(
struct S{int value;};
template<class T> constexpr int foo = sizeof(T);
template<class T1, class T2>
struct pair{
pair() noexcept(foo<T1> + foo<T2>){}
T1 first;
T2 second;
};
int main(){
pair<int, S> pair;
pair.second.value;
}
)";
Document::Ptr doc = Document::create("variableTemplateInExpression");
doc->setUtf8Source(src);
doc->parse();
doc->check();
QVERIFY(doc->diagnosticMessages().isEmpty());
QVERIFY(doc->globalSymbolCount()>=1);
Snapshot snapshot;
snapshot.insert(doc);
Class *s = doc->globalSymbolAt(0)->asClass();
QVERIFY(s);
QCOMPARE(s->name()->identifier()->chars(), "S");
QCOMPARE(s->memberCount(), 1);
Declaration *sv = s->memberAt(0)->asDeclaration();
QVERIFY(sv);
QCOMPARE(sv->name()->identifier()->chars(), "value");
FindUsages find(src, doc, snapshot);
find(sv);
QCOMPARE(find.usages().size(), 2);
}
QTEST_APPLESS_MAIN(tst_FindUsages) QTEST_APPLESS_MAIN(tst_FindUsages)
#include "tst_findusages.moc" #include "tst_findusages.moc"