forked from qt-creator/qt-creator
CPlusPlus: Support requires clause in parser
Change-Id: Ice6a7a287453516a1cfc296e2c9f16160b3ea130 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
2
src/libs/3rdparty/cplusplus/AST.cpp
vendored
2
src/libs/3rdparty/cplusplus/AST.cpp
vendored
@@ -911,6 +911,8 @@ int DeclaratorAST::lastToken() const
|
||||
return candidate;
|
||||
if (equal_token)
|
||||
return equal_token + 1;
|
||||
if (requiresClause)
|
||||
return requiresClause->lastToken();
|
||||
if (post_attribute_list)
|
||||
if (int candidate = post_attribute_list->lastToken())
|
||||
return candidate;
|
||||
|
22
src/libs/3rdparty/cplusplus/AST.h
vendored
22
src/libs/3rdparty/cplusplus/AST.h
vendored
@@ -340,6 +340,7 @@ public:
|
||||
virtual TypeofSpecifierAST *asTypeofSpecifier() { return nullptr; }
|
||||
virtual UnaryExpressionAST *asUnaryExpression() { return nullptr; }
|
||||
virtual RequiresExpressionAST *asRequiresExpression() { return nullptr; }
|
||||
virtual RequiresClauseAST *asRequiresClause() { return nullptr; }
|
||||
virtual UsingAST *asUsing() { return nullptr; }
|
||||
virtual UsingDirectiveAST *asUsingDirective() { return nullptr; }
|
||||
virtual WhileStatementAST *asWhileStatement() { return nullptr; }
|
||||
@@ -693,6 +694,7 @@ public:
|
||||
SpecifierListAST *post_attribute_list = nullptr;
|
||||
int equal_token = 0;
|
||||
ExpressionAST *initializer = nullptr;
|
||||
RequiresClauseAST *requiresClause = nullptr;
|
||||
|
||||
public:
|
||||
DeclaratorAST *asDeclarator() override { return this; }
|
||||
@@ -2763,6 +2765,7 @@ public:
|
||||
int less_token = 0;
|
||||
DeclarationListAST *template_parameter_list = nullptr;
|
||||
int greater_token = 0;
|
||||
RequiresClauseAST *requiresClause = nullptr;
|
||||
DeclarationAST *declaration = nullptr;
|
||||
|
||||
public: // annotations
|
||||
@@ -3020,6 +3023,25 @@ protected:
|
||||
bool match0(AST *, ASTMatcher *) override;
|
||||
};
|
||||
|
||||
class CPLUSPLUS_EXPORT RequiresClauseAST: public AST
|
||||
{
|
||||
public:
|
||||
int requires_token = 0;
|
||||
ExpressionAST *constraint = nullptr;
|
||||
|
||||
public:
|
||||
RequiresClauseAST *asRequiresClause() override { return this; }
|
||||
|
||||
int firstToken() const override { return requires_token; }
|
||||
int lastToken() const override { return constraint->lastToken(); }
|
||||
|
||||
RequiresClauseAST *clone(MemoryPool *pool) const override;
|
||||
|
||||
protected:
|
||||
void accept0(ASTVisitor *visitor) override;
|
||||
bool match0(AST *, ASTMatcher *) override;
|
||||
};
|
||||
|
||||
class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST
|
||||
{
|
||||
public:
|
||||
|
11
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
11
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
@@ -1305,6 +1305,8 @@ TemplateDeclarationAST *TemplateDeclarationAST::clone(MemoryPool *pool) const
|
||||
iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
|
||||
*ast_iter = new (pool) DeclarationListAST((iter->value) ? iter->value->clone(pool) : nullptr);
|
||||
ast->greater_token = greater_token;
|
||||
if (requiresClause)
|
||||
ast->requiresClause = requiresClause->clone(pool);
|
||||
if (declaration)
|
||||
ast->declaration = declaration->clone(pool);
|
||||
return ast;
|
||||
@@ -1338,6 +1340,15 @@ RequiresExpressionAST *RequiresExpressionAST::clone(MemoryPool *pool) const
|
||||
return ast;
|
||||
}
|
||||
|
||||
RequiresClauseAST *RequiresClauseAST::clone(MemoryPool *pool) const
|
||||
{
|
||||
const auto ast = new (pool) RequiresClauseAST;
|
||||
ast->requires_token = requires_token;
|
||||
if (constraint)
|
||||
ast->constraint = constraint->clone(pool);
|
||||
return ast;
|
||||
}
|
||||
|
||||
ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const
|
||||
{
|
||||
ThrowExpressionAST *ast = new (pool) ThrowExpressionAST;
|
||||
|
7
src/libs/3rdparty/cplusplus/ASTMatch0.cpp
vendored
7
src/libs/3rdparty/cplusplus/ASTMatch0.cpp
vendored
@@ -926,6 +926,13 @@ bool RequiresExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RequiresClauseAST::match0(AST *pattern, ASTMatcher *matcher)
|
||||
{
|
||||
if (const auto other = pattern->asRequiresClause())
|
||||
return matcher->match(this, other);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
|
||||
{
|
||||
if (ThrowExpressionAST *_other = pattern->asThrowExpression())
|
||||
|
15
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
15
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
@@ -2205,6 +2205,11 @@ bool ASTMatcher::match(TemplateDeclarationAST *node, TemplateDeclarationAST *pat
|
||||
|
||||
pattern->greater_token = node->greater_token;
|
||||
|
||||
if (! pattern->requiresClause)
|
||||
pattern->requiresClause = node->requiresClause;
|
||||
else if (! AST::match(node->requiresClause, pattern->requiresClause, this))
|
||||
return false;
|
||||
|
||||
if (! pattern->declaration)
|
||||
pattern->declaration = node->declaration;
|
||||
else if (! AST::match(node->declaration, pattern->declaration, this))
|
||||
@@ -2247,6 +2252,16 @@ bool ASTMatcher::match(RequiresExpressionAST *node, RequiresExpressionAST *patte
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTMatcher::match(RequiresClauseAST *node, RequiresClauseAST *pattern)
|
||||
{
|
||||
pattern->requires_token = node->requires_token;
|
||||
if (!pattern->constraint)
|
||||
pattern->constraint = node->constraint;
|
||||
else if (!AST::match(node->constraint, pattern->constraint, this))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern)
|
||||
{
|
||||
(void) node;
|
||||
|
1
src/libs/3rdparty/cplusplus/ASTMatcher.h
vendored
1
src/libs/3rdparty/cplusplus/ASTMatcher.h
vendored
@@ -158,6 +158,7 @@ public:
|
||||
virtual bool match(QualifiedNameAST *node, QualifiedNameAST *pattern);
|
||||
virtual bool match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern);
|
||||
virtual bool match(ReferenceAST *node, ReferenceAST *pattern);
|
||||
virtual bool match(RequiresClauseAST *node, RequiresClauseAST *pattern);
|
||||
virtual bool match(RequiresExpressionAST *node, RequiresExpressionAST *pattern);
|
||||
virtual bool match(ReturnStatementAST *node, ReturnStatementAST *pattern);
|
||||
virtual bool match(SimpleDeclarationAST *node, SimpleDeclarationAST *pattern);
|
||||
|
8
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
8
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
@@ -958,6 +958,7 @@ void TemplateDeclarationAST::accept0(ASTVisitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
accept(template_parameter_list, visitor);
|
||||
accept(requiresClause, visitor);
|
||||
accept(declaration, visitor);
|
||||
}
|
||||
visitor->endVisit(this);
|
||||
@@ -980,6 +981,13 @@ void RequiresExpressionAST::accept0(ASTVisitor *visitor)
|
||||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
void RequiresClauseAST::accept0(ASTVisitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this))
|
||||
accept(constraint, visitor);
|
||||
visitor->endVisit(this);
|
||||
}
|
||||
|
||||
void ThrowExpressionAST::accept0(ASTVisitor *visitor)
|
||||
{
|
||||
if (visitor->visit(this)) {
|
||||
|
2
src/libs/3rdparty/cplusplus/ASTVisitor.h
vendored
2
src/libs/3rdparty/cplusplus/ASTVisitor.h
vendored
@@ -201,6 +201,7 @@ public:
|
||||
virtual bool visit(RangeBasedForStatementAST *) { return true; }
|
||||
virtual bool visit(ReferenceAST *) { return true; }
|
||||
virtual bool visit(RequiresExpressionAST *) { return true; }
|
||||
virtual bool visit(RequiresClauseAST *) { return true; }
|
||||
virtual bool visit(ReturnStatementAST *) { return true; }
|
||||
virtual bool visit(SimpleDeclarationAST *) { return true; }
|
||||
virtual bool visit(SimpleNameAST *) { return true; }
|
||||
@@ -359,6 +360,7 @@ public:
|
||||
virtual void endVisit(RangeBasedForStatementAST *) {}
|
||||
virtual void endVisit(ReferenceAST *) {}
|
||||
virtual void endVisit(RequiresExpressionAST *) {}
|
||||
virtual void endVisit(RequiresClauseAST *) {}
|
||||
virtual void endVisit(ReturnStatementAST *) {}
|
||||
virtual void endVisit(SimpleDeclarationAST *) {}
|
||||
virtual void endVisit(SimpleNameAST *) {}
|
||||
|
1
src/libs/3rdparty/cplusplus/ASTfwd.h
vendored
1
src/libs/3rdparty/cplusplus/ASTfwd.h
vendored
@@ -167,6 +167,7 @@ class QtPropertyDeclarationItemAST;
|
||||
class QualifiedNameAST;
|
||||
class RangeBasedForStatementAST;
|
||||
class ReferenceAST;
|
||||
class RequiresClauseAST;
|
||||
class RequiresExpressionAST;
|
||||
class ReturnStatementAST;
|
||||
class SimpleDeclarationAST;
|
||||
|
18
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
18
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -1247,6 +1247,8 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node)
|
||||
ast->less_token = consumeToken();
|
||||
if (maybeSplitGreaterGreaterToken() || LA() == T_GREATER || parseTemplateParameterList(ast->template_parameter_list))
|
||||
match(T_GREATER, &ast->greater_token);
|
||||
if (!parseRequiresClauseOpt(ast->requiresClause))
|
||||
return false;
|
||||
}
|
||||
|
||||
while (LA()) {
|
||||
@@ -1402,6 +1404,20 @@ bool Parser::parseRequirement()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::parseRequiresClauseOpt(RequiresClauseAST *&node)
|
||||
{
|
||||
if (!_languageFeatures.cxx20Enabled)
|
||||
return true;
|
||||
if (LA() != T_REQUIRES)
|
||||
return true;
|
||||
const auto ast = new (_pool) RequiresClauseAST;
|
||||
ast->requires_token = consumeToken();
|
||||
if (!parseLogicalOrExpression(ast->constraint))
|
||||
return false;
|
||||
node = ast;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::parseRequiresExpression(ExpressionAST *&node)
|
||||
{
|
||||
if (!_languageFeatures.cxx20Enabled)
|
||||
@@ -2999,6 +3015,8 @@ bool Parser::parseInitDeclarator(DeclaratorAST *&node, SpecifierListAST *decl_sp
|
||||
} else if (node->core_declarator && node->core_declarator->asDecompositionDeclarator()) {
|
||||
error(cursor(), "structured binding needs initializer");
|
||||
return false;
|
||||
} else if (!parseRequiresClauseOpt(node->requiresClause)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
1
src/libs/3rdparty/cplusplus/Parser.h
vendored
1
src/libs/3rdparty/cplusplus/Parser.h
vendored
@@ -147,6 +147,7 @@ public:
|
||||
bool parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node);
|
||||
bool parseTypeConstraint(TypeConstraintAST *&node);
|
||||
bool parseRequirement();
|
||||
bool parseRequiresClauseOpt(RequiresClauseAST *&node);
|
||||
bool parseRequiresExpression(ExpressionAST *&node);
|
||||
bool parseTemplateParameter(DeclarationAST *&node);
|
||||
bool parseTemplateParameterList(DeclarationListAST *&node);
|
||||
|
@@ -147,6 +147,7 @@ private Q_SLOTS:
|
||||
void lambdaType();
|
||||
|
||||
void concepts();
|
||||
void requiresClause();
|
||||
};
|
||||
|
||||
|
||||
@@ -318,5 +319,27 @@ void *func2(IsPointer auto p)
|
||||
QVERIFY(!hasErrors);
|
||||
}
|
||||
|
||||
void tst_cxx11::requiresClause()
|
||||
{
|
||||
LanguageFeatures features;
|
||||
features.cxxEnabled = true;
|
||||
features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true;
|
||||
|
||||
const QString source = R"(
|
||||
template<class T> constexpr bool is_meowable = true;
|
||||
template<class T> constexpr bool is_purrable() { return true; }
|
||||
template<class T> void f(T) requires is_meowable<T>;
|
||||
template<class T> requires is_meowable<T> void g(T) ;
|
||||
template<class T> void h(T) requires (is_purrable<T>());
|
||||
)";
|
||||
QByteArray errors;
|
||||
Document::Ptr doc = Document::create(FilePath::fromPathPart(u"testFile"));
|
||||
processDocument(doc, source.toUtf8(), features, &errors);
|
||||
const bool hasErrors = !errors.isEmpty();
|
||||
if (hasErrors)
|
||||
qDebug() << errors;
|
||||
QVERIFY(!hasErrors);
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_cxx11)
|
||||
#include "tst_cxx11.moc"
|
||||
|
Reference in New Issue
Block a user