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:
Christian Kandeler
2023-02-28 11:09:50 +01:00
parent 7214d79420
commit 47d375bbb4
12 changed files with 111 additions and 0 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;

View File

@@ -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())

View File

@@ -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;

View File

@@ -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);

View File

@@ -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)) {

View File

@@ -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 *) {}

View File

@@ -167,6 +167,7 @@ class QtPropertyDeclarationItemAST;
class QualifiedNameAST;
class RangeBasedForStatementAST;
class ReferenceAST;
class RequiresClauseAST;
class RequiresExpressionAST;
class ReturnStatementAST;
class SimpleDeclarationAST;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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"