diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 260b3582713..2f351ff7be8 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -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; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index 9288725edd3..ff5759ffb2b 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -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: diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index 4e4cda40f9f..f4a2f626dad 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -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; diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index afe94aba06f..a4bd9935f0e 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -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()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index ccf41dbae2f..d39d0717c55 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -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; diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index 214c37a283b..c7d762c9e11 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -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); diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index cb05dbde62b..cde7842280d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -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)) { diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index 455936f9842..9f277836937 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -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 *) {} diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index f0899b2e1c8..b5222e2bbec 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -167,6 +167,7 @@ class QtPropertyDeclarationItemAST; class QualifiedNameAST; class RangeBasedForStatementAST; class ReferenceAST; +class RequiresClauseAST; class RequiresExpressionAST; class ReturnStatementAST; class SimpleDeclarationAST; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index ed023b15f03..004bee40e71 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -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; } diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index dbbb5630971..a50706b5f34 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -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); diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index f626c402230..ea859b77d98 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -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 constexpr bool is_meowable = true; +template constexpr bool is_purrable() { return true; } +template void f(T) requires is_meowable; +template requires is_meowable void g(T) ; +template void h(T) requires (is_purrable()); +)"; + 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"