diff --git a/src/libs/3rdparty/cplusplus/AST.cpp b/src/libs/3rdparty/cplusplus/AST.cpp index 2f351ff7be8..53c84a95c68 100644 --- a/src/libs/3rdparty/cplusplus/AST.cpp +++ b/src/libs/3rdparty/cplusplus/AST.cpp @@ -3763,6 +3763,8 @@ int TemplateTypeParameterAST::firstToken() const { if (template_token) return template_token; + if (typeConstraint) + return typeConstraint->firstToken(); if (less_token) return less_token; if (template_parameter_list) @@ -3807,6 +3809,8 @@ int TemplateTypeParameterAST::lastToken() const return candidate; if (less_token) return less_token + 1; + if (typeConstraint) + return typeConstraint->lastToken(); if (template_token) return template_token + 1; return 1; diff --git a/src/libs/3rdparty/cplusplus/AST.h b/src/libs/3rdparty/cplusplus/AST.h index ff5759ffb2b..0d7e337fd8b 100644 --- a/src/libs/3rdparty/cplusplus/AST.h +++ b/src/libs/3rdparty/cplusplus/AST.h @@ -184,6 +184,7 @@ public: virtual ArrayInitializerAST *asArrayInitializer() { return nullptr; } virtual AsmDefinitionAST *asAsmDefinition() { return nullptr; } virtual AttributeSpecifierAST *asAttributeSpecifier() { return nullptr; } + virtual AwaitExpressionAST *asAwaitExpression() { return nullptr; } virtual BaseSpecifierAST *asBaseSpecifier() { return nullptr; } virtual BinaryExpressionAST *asBinaryExpression() { return nullptr; } virtual BoolLiteralAST *asBoolLiteral() { return nullptr; } @@ -344,6 +345,7 @@ public: virtual UsingAST *asUsing() { return nullptr; } virtual UsingDirectiveAST *asUsingDirective() { return nullptr; } virtual WhileStatementAST *asWhileStatement() { return nullptr; } + virtual YieldExpressionAST *asYieldExpression() { return nullptr; } protected: virtual void accept0(ASTVisitor *visitor) = 0; @@ -2826,6 +2828,44 @@ protected: bool match0(AST *, ASTMatcher *) override; }; +class CPLUSPLUS_EXPORT YieldExpressionAST: public ExpressionAST +{ +public: + int yield_token = 0; + ExpressionAST *expression = nullptr; + +public: + YieldExpressionAST *asYieldExpression() override { return this; } + + int firstToken() const override { return yield_token; } + int lastToken() const override { return expression->lastToken(); } + + YieldExpressionAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + +class CPLUSPLUS_EXPORT AwaitExpressionAST: public ExpressionAST +{ +public: + int await_token = 0; + ExpressionAST *castExpression = nullptr; + +public: + AwaitExpressionAST *asAwaitExpression() override { return this; } + + int firstToken() const override { return await_token; } + int lastToken() const override { return castExpression->lastToken(); } + + AwaitExpressionAST *clone(MemoryPool *pool) const override; + +protected: + void accept0(ASTVisitor *visitor) override; + bool match0(AST *, ASTMatcher *) override; +}; + class CPLUSPLUS_EXPORT NoExceptOperatorExpressionAST: public ExpressionAST { public: @@ -2956,6 +2996,7 @@ class CPLUSPLUS_EXPORT TemplateTypeParameterAST: public DeclarationAST { public: int template_token = 0; + TypeConstraintAST *typeConstraint = nullptr; int less_token = 0; DeclarationListAST *template_parameter_list = nullptr; int greater_token = 0; diff --git a/src/libs/3rdparty/cplusplus/ASTClone.cpp b/src/libs/3rdparty/cplusplus/ASTClone.cpp index f4a2f626dad..e1e014afccf 100644 --- a/src/libs/3rdparty/cplusplus/ASTClone.cpp +++ b/src/libs/3rdparty/cplusplus/ASTClone.cpp @@ -147,6 +147,8 @@ TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) *ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); + if (conceptName) + ast->conceptName = conceptName->clone(pool); ast->lessToken = lessToken; for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) @@ -1358,6 +1360,24 @@ ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const return ast; } +YieldExpressionAST *YieldExpressionAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) YieldExpressionAST; + ast->yield_token = yield_token; + if (expression) + ast->expression = expression->clone(pool); + return ast; +} + +AwaitExpressionAST *AwaitExpressionAST::clone(MemoryPool *pool) const +{ + const auto ast = new (pool) AwaitExpressionAST; + ast->await_token = await_token; + if (castExpression) + ast->castExpression = castExpression->clone(pool); + return ast; +} + NoExceptOperatorExpressionAST *NoExceptOperatorExpressionAST::clone(MemoryPool *pool) const { NoExceptOperatorExpressionAST *ast = new (pool) NoExceptOperatorExpressionAST; @@ -1429,6 +1449,8 @@ TemplateTypeParameterAST *TemplateTypeParameterAST::clone(MemoryPool *pool) cons { TemplateTypeParameterAST *ast = new (pool) TemplateTypeParameterAST; ast->template_token = template_token; + if (typeConstraint) + ast->typeConstraint = typeConstraint->clone(pool); ast->less_token = less_token; for (DeclarationListAST *iter = template_parameter_list, **ast_iter = &ast->template_parameter_list; iter; iter = iter->next, ast_iter = &(*ast_iter)->next) diff --git a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp index a4bd9935f0e..b58bd59efe0 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatch0.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatch0.cpp @@ -941,6 +941,20 @@ bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher) return false; } +bool YieldExpressionAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asYieldExpression()) + return matcher->match(this, other); + return false; +} + +bool AwaitExpressionAST::match0(AST *pattern, ASTMatcher *matcher) +{ + if (const auto other = pattern->asAwaitExpression()) + return matcher->match(this, other); + return false; +} + bool NoExceptOperatorExpressionAST::match0(AST *pattern, ASTMatcher *matcher) { if (NoExceptOperatorExpressionAST *_other = pattern->asNoExceptOperatorExpression()) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp index d39d0717c55..4567cd68a25 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.cpp +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.cpp @@ -2277,6 +2277,26 @@ bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern) return true; } +bool ASTMatcher::match(YieldExpressionAST *node, YieldExpressionAST *pattern) +{ + pattern->yield_token = node->yield_token; + if (!pattern->expression) + pattern->expression = node->expression; + else if (!AST::match(node->expression, pattern->expression, this)) + return false; + return true; +} + +bool ASTMatcher::match(AwaitExpressionAST *node, AwaitExpressionAST *pattern) +{ + pattern->await_token = node->await_token; + if (!pattern->castExpression) + pattern->castExpression = node->castExpression; + else if (!AST::match(node->castExpression, pattern->castExpression, this)) + return false; + return true; +} + bool ASTMatcher::match(NoExceptOperatorExpressionAST *node, NoExceptOperatorExpressionAST *pattern) { (void) node; @@ -2398,6 +2418,11 @@ bool ASTMatcher::match(TemplateTypeParameterAST *node, TemplateTypeParameterAST pattern->template_token = node->template_token; + if (!pattern->typeConstraint) + pattern->typeConstraint = node->typeConstraint; + else if (!AST::match(node->typeConstraint, pattern->typeConstraint, this)) + return false; + pattern->less_token = node->less_token; if (! pattern->template_parameter_list) diff --git a/src/libs/3rdparty/cplusplus/ASTMatcher.h b/src/libs/3rdparty/cplusplus/ASTMatcher.h index c7d762c9e11..fb6109a07dc 100644 --- a/src/libs/3rdparty/cplusplus/ASTMatcher.h +++ b/src/libs/3rdparty/cplusplus/ASTMatcher.h @@ -38,6 +38,7 @@ public: virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern); virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern); virtual bool match(ArrayInitializerAST *node, ArrayInitializerAST *pattern); + virtual bool match(AwaitExpressionAST *node, AwaitExpressionAST *pattern); virtual bool match(AsmDefinitionAST *node, AsmDefinitionAST *pattern); virtual bool match(BaseSpecifierAST *node, BaseSpecifierAST *pattern); virtual bool match(BinaryExpressionAST *node, BinaryExpressionAST *pattern); @@ -188,6 +189,7 @@ public: virtual bool match(UsingAST *node, UsingAST *pattern); virtual bool match(UsingDirectiveAST *node, UsingDirectiveAST *pattern); virtual bool match(WhileStatementAST *node, WhileStatementAST *pattern); + virtual bool match(YieldExpressionAST *node, YieldExpressionAST *pattern); }; } // namespace CPlusPlus diff --git a/src/libs/3rdparty/cplusplus/ASTVisit.cpp b/src/libs/3rdparty/cplusplus/ASTVisit.cpp index cde7842280d..d83684b966d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisit.cpp +++ b/src/libs/3rdparty/cplusplus/ASTVisit.cpp @@ -996,6 +996,20 @@ void ThrowExpressionAST::accept0(ASTVisitor *visitor) visitor->endVisit(this); } +void YieldExpressionAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(expression, visitor); + visitor->endVisit(this); +} + +void AwaitExpressionAST::accept0(ASTVisitor *visitor) +{ + if (visitor->visit(this)) + accept(castExpression, visitor); + visitor->endVisit(this); +} + void NoExceptOperatorExpressionAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { @@ -1051,6 +1065,7 @@ void TypenameTypeParameterAST::accept0(ASTVisitor *visitor) void TemplateTypeParameterAST::accept0(ASTVisitor *visitor) { if (visitor->visit(this)) { + accept(typeConstraint, visitor); accept(template_parameter_list, visitor); accept(name, visitor); accept(type_id, visitor); diff --git a/src/libs/3rdparty/cplusplus/ASTVisitor.h b/src/libs/3rdparty/cplusplus/ASTVisitor.h index 9f277836937..9d9fec75b1d 100644 --- a/src/libs/3rdparty/cplusplus/ASTVisitor.h +++ b/src/libs/3rdparty/cplusplus/ASTVisitor.h @@ -81,6 +81,7 @@ public: virtual bool visit(ArrayDeclaratorAST *) { return true; } virtual bool visit(ArrayInitializerAST *) { return true; } virtual bool visit(AsmDefinitionAST *) { return true; } + virtual bool visit(AwaitExpressionAST *) { return true; } virtual bool visit(BaseSpecifierAST *) { return true; } virtual bool visit(BinaryExpressionAST *) { return true; } virtual bool visit(BoolLiteralAST *) { return true; } @@ -230,6 +231,7 @@ public: virtual bool visit(UsingAST *) { return true; } virtual bool visit(UsingDirectiveAST *) { return true; } virtual bool visit(WhileStatementAST *) { return true; } + virtual bool visit(YieldExpressionAST *) { return true; } virtual void endVisit(AccessDeclarationAST *) {} virtual void endVisit(AliasDeclarationAST *) {} @@ -240,6 +242,7 @@ public: virtual void endVisit(ArrayDeclaratorAST *) {} virtual void endVisit(ArrayInitializerAST *) {} virtual void endVisit(AsmDefinitionAST *) {} + virtual void endVisit(AwaitExpressionAST *) {} virtual void endVisit(BaseSpecifierAST *) {} virtual void endVisit(BinaryExpressionAST *) {} virtual void endVisit(BoolLiteralAST *) {} @@ -389,6 +392,7 @@ public: virtual void endVisit(UsingAST *) {} virtual void endVisit(UsingDirectiveAST *) {} virtual void endVisit(WhileStatementAST *) {} + virtual void endVisit(YieldExpressionAST *) {} private: TranslationUnit *_translationUnit; diff --git a/src/libs/3rdparty/cplusplus/ASTfwd.h b/src/libs/3rdparty/cplusplus/ASTfwd.h index b5222e2bbec..102fda75fb5 100644 --- a/src/libs/3rdparty/cplusplus/ASTfwd.h +++ b/src/libs/3rdparty/cplusplus/ASTfwd.h @@ -40,6 +40,7 @@ class ArrayDeclaratorAST; class ArrayInitializerAST; class AsmDefinitionAST; class AttributeSpecifierAST; +class AwaitExpressionAST; class BaseSpecifierAST; class BinaryExpressionAST; class BoolLiteralAST; @@ -200,6 +201,7 @@ class UnaryExpressionAST; class UsingAST; class UsingDirectiveAST; class WhileStatementAST; +class YieldExpressionAST; typedef List ExpressionListAST; typedef List DeclarationListAST; diff --git a/src/libs/3rdparty/cplusplus/Bind.cpp b/src/libs/3rdparty/cplusplus/Bind.cpp index 6293d732e05..202c36a51fa 100644 --- a/src/libs/3rdparty/cplusplus/Bind.cpp +++ b/src/libs/3rdparty/cplusplus/Bind.cpp @@ -2532,6 +2532,11 @@ bool Bind::visit(TemplateTypeParameterAST *ast) return false; } +bool Bind::visit(TypeConstraintAST *) +{ + return false; +} + bool Bind::visit(UsingAST *ast) { int sourceLocation = location(ast->name, ast->firstToken()); diff --git a/src/libs/3rdparty/cplusplus/Bind.h b/src/libs/3rdparty/cplusplus/Bind.h index 4d12beee86d..867ed7baaa8 100644 --- a/src/libs/3rdparty/cplusplus/Bind.h +++ b/src/libs/3rdparty/cplusplus/Bind.h @@ -230,6 +230,7 @@ protected: bool visit(TemplateDeclarationAST *ast) override; bool visit(TypenameTypeParameterAST *ast) override; bool visit(TemplateTypeParameterAST *ast) override; + bool visit(TypeConstraintAST *ast) override; bool visit(UsingAST *ast) override; bool visit(UsingDirectiveAST *ast) override; bool visit(ObjCClassForwardDeclarationAST *ast) override; diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index 004bee40e71..45c2493fff4 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -413,6 +413,7 @@ bool Parser::skipUntilStatement() case T_BREAK: case T_CONTINUE: case T_RETURN: + case T_CO_RETURN: case T_GOTO: case T_TRY: case T_CATCH: @@ -1329,16 +1330,20 @@ bool Parser::parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node) bool Parser::parseTypeConstraint(TypeConstraintAST *&node) { + if (!_languageFeatures.cxx20Enabled) + return false; NestedNameSpecifierListAST *nestedName = nullptr; parseNestedNameSpecifierOpt(nestedName, true); NameAST *conceptName = nullptr; - if (!parseUnqualifiedName(conceptName, true)) + if (!parseUnqualifiedName(conceptName, false)) return false; const auto typeConstraint = new (_pool) TypeConstraintAST; typeConstraint->nestedName = nestedName; typeConstraint->conceptName = conceptName; - if (LA() != T_LESS) + if (LA() != T_LESS) { + node = typeConstraint; return true; + } typeConstraint->lessToken = consumeToken(); if (LA() != T_GREATER) { if (!parseTemplateArgumentList(typeConstraint->templateArgs)) @@ -2208,8 +2213,8 @@ bool Parser::parseTypenameTypeParameter(DeclarationAST *&node) bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) { DEBUG_THIS_RULE(); + TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; if (LA() == T_TEMPLATE) { - TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; ast->template_token = consumeToken(); if (LA() == T_LESS) ast->less_token = consumeToken(); @@ -2218,20 +2223,21 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) ast->greater_token = consumeToken(); if (LA() == T_CLASS) ast->class_token = consumeToken(); - if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT) - ast->dot_dot_dot_token = consumeToken(); - - // parse optional name - parseName(ast->name); - - if (LA() == T_EQUAL) { - ast->equal_token = consumeToken(); - parseTypeId(ast->type_id); - } - node = ast; - return true; + } else if (!parseTypeConstraint(ast->typeConstraint)) { + return false; } - return false; + if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT) + ast->dot_dot_dot_token = consumeToken(); + + // parse optional name + parseName(ast->name); + + if (LA() == T_EQUAL) { + ast->equal_token = consumeToken(); + parseTypeId(ast->type_id); + } + node = ast; + return true; } bool Parser::lookAtTypeParameter() @@ -2267,10 +2273,9 @@ bool Parser::parseTypeParameter(DeclarationAST *&node) if (lookAtTypeParameter()) return parseTypenameTypeParameter(node); - else if (LA() == T_TEMPLATE) + if (LA() == T_TEMPLATE) return parseTemplateTypeParameter(node); - else - return false; + return parseTemplateTypeParameter(node); } bool Parser::parseTypeId(ExpressionAST *&node) @@ -3556,6 +3561,7 @@ bool Parser::parseStatement(StatementAST *&node, bool blockLabeledStatement) return parseGotoStatement(node); case T_RETURN: + case T_CO_RETURN: return parseReturnStatement(node); case T_LBRACE: @@ -3666,7 +3672,7 @@ bool Parser::parseGotoStatement(StatementAST *&node) bool Parser::parseReturnStatement(StatementAST *&node) { DEBUG_THIS_RULE(); - if (LA() == T_RETURN) { + if (LA() == T_RETURN || LA() == T_CO_RETURN) { ReturnStatementAST *ast = new (_pool) ReturnStatementAST; ast->return_token = consumeToken(); if (_languageFeatures.cxx11Enabled && LA() == T_LBRACE) @@ -5637,6 +5643,11 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node) return parseNoExceptOperatorExpression(node); } + case T_CO_AWAIT: + if (!_languageFeatures.cxx20Enabled) + break; + return parseAwaitExpression(node); + default: break; } // switch @@ -5895,6 +5906,8 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node) DEBUG_THIS_RULE(); if (LA() == T_THROW) return parseThrowExpression(node); + else if (LA() == T_CO_YIELD) + return parseYieldExpression(node); else PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment) } @@ -6023,6 +6036,34 @@ bool Parser::parseThrowExpression(ExpressionAST *&node) return false; } +bool Parser::parseYieldExpression(ExpressionAST *&node) +{ + DEBUG_THIS_RULE(); + if (LA() != T_CO_YIELD) + return false; + const auto ast = new (_pool) YieldExpressionAST; + ast->yield_token = consumeToken(); + if (parseBracedInitList0x(ast->expression) || parseAssignmentExpression(ast->expression)) { + node = ast; + return true; + } + return false; +} + +bool Parser::parseAwaitExpression(ExpressionAST *&node) +{ + DEBUG_THIS_RULE(); + if (LA() != T_CO_AWAIT) + return false; + const auto ast = new (_pool) AwaitExpressionAST; + ast->await_token = consumeToken(); + if (parseCastExpression(ast->castExpression)) { + node = ast; + return true; + } + return false; +} + bool Parser::parseNoExceptOperatorExpression(ExpressionAST *&node) { DEBUG_THIS_RULE(); diff --git a/src/libs/3rdparty/cplusplus/Parser.h b/src/libs/3rdparty/cplusplus/Parser.h index a50706b5f34..e34a4ff5223 100644 --- a/src/libs/3rdparty/cplusplus/Parser.h +++ b/src/libs/3rdparty/cplusplus/Parser.h @@ -152,6 +152,8 @@ public: bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node); bool parseThrowExpression(ExpressionAST *&node); + bool parseYieldExpression(ExpressionAST *&node); + bool parseAwaitExpression(ExpressionAST *&node); bool parseNoExceptOperatorExpression(ExpressionAST *&node); bool parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder); bool parseCatchClause(CatchClauseListAST *&node); diff --git a/src/plugins/cppeditor/cppcodeformatter.cpp b/src/plugins/cppeditor/cppcodeformatter.cpp index ce250f672b0..6b30e78fa6c 100644 --- a/src/plugins/cppeditor/cppcodeformatter.cpp +++ b/src/plugins/cppeditor/cppcodeformatter.cpp @@ -924,6 +924,7 @@ bool CodeFormatter::tryStatement() return true; switch (kind) { case T_RETURN: + case T_CO_RETURN: enter(return_statement); enter(expression); return true; @@ -1651,6 +1652,7 @@ void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, in case T_BREAK: case T_CONTINUE: case T_RETURN: + case T_CO_RETURN: if (topState.type == case_cont) { *indentDepth = topState.savedIndentDepth; if (m_styleSettings.indentControlFlowRelativeToSwitchLabels) diff --git a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp index ea859b77d98..4bb4e4b4b24 100644 --- a/tests/auto/cplusplus/cxx11/tst_cxx11.cpp +++ b/tests/auto/cplusplus/cxx11/tst_cxx11.cpp @@ -148,6 +148,7 @@ private Q_SLOTS: void concepts(); void requiresClause(); + void coroutines(); }; @@ -315,7 +316,7 @@ void *func2(IsPointer auto p) processDocument(doc, source.toUtf8(), features, &errors); const bool hasErrors = !errors.isEmpty(); if (hasErrors) - qDebug() << errors; + qDebug().noquote() << errors; QVERIFY(!hasErrors); } @@ -337,7 +338,186 @@ template void h(T) requires (is_purrable()); processDocument(doc, source.toUtf8(), features, &errors); const bool hasErrors = !errors.isEmpty(); if (hasErrors) - qDebug() << errors; + qDebug().noquote() << errors; + QVERIFY(!hasErrors); +} + +void tst_cxx11::coroutines() +{ + LanguageFeatures features; + features.cxxEnabled = true; + features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true; + + const QString source = R"( +struct promise; +struct coroutine : std::coroutine_handle +{ + using promise_type = struct promise; +}; +struct promise +{ + coroutine get_return_object() { return {coroutine::from_promise(*this)}; } + std::suspend_always initial_suspend() noexcept { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} +}; +struct S +{ + int i; + coroutine f() + { + std::cout << i; + co_return; + } +}; +void good() +{ + coroutine h = [](int i) -> coroutine + { + std::cout << i; + co_return; + }(0); + h.resume(); + h.destroy(); +} +auto switch_to_new_thread(std::jthread& out) +{ + struct awaitable + { + std::jthread* p_out; + bool await_ready() { return false; } + void await_suspend(std::coroutine_handle<> h) + { + std::jthread& out = *p_out; + if (out.joinable()) + throw std::runtime_error("Output jthread parameter not empty"); + out = std::jthread([h] { h.resume(); }); + std::cout << "New thread ID: " << out.get_id() << '\n'; // this is OK + } + void await_resume() {} + }; + return awaitable{&out}; +} +struct task +{ + struct promise_type + { + task get_return_object() { return {}; } + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void return_void() {} + void unhandled_exception() {} + }; +}; +task resuming_on_new_thread(std::jthread& out) +{ + std::cout << "Coroutine started on thread: " << std::this_thread::get_id() << '\n'; + co_await switch_to_new_thread(out); + std::cout << "Coroutine resumed on thread: " << std::this_thread::get_id() << '\n'; +} +void run() +{ + std::jthread out; + resuming_on_new_thread(out); +} +template +struct Generator +{ + struct promise_type; + using handle_type = std::coroutine_handle; + struct promise_type // required + { + T value_; + std::exception_ptr exception_; + + Generator get_return_object() + { + return Generator(handle_type::from_promise(*this)); + } + std::suspend_always initial_suspend() { return {}; } + std::suspend_always final_suspend() noexcept { return {}; } + void unhandled_exception() { exception_ = std::current_exception(); } + template From> + std::suspend_always yield_value(From&& from) + { + value_ = std::forward(from); + return {}; + } + void return_void() { } + }; + handle_type h_; + Generator(handle_type h) : h_(h) {} + ~Generator() { h_.destroy(); } + explicit operator bool() + { + fill(); + return !h_.done(); + } + T operator()() + { + fill(); + full_ = false; + return std::move(h_.promise().value_); + } +private: + bool full_ = false; + void fill() + { + if (!full_) + { + h_(); + if (h_.promise().exception_) + std::rethrow_exception(h_.promise().exception_); + full_ = true; + } + } +}; +Generator +fibonacci_sequence(unsigned n) +{ + if (n == 0) + co_return; + if (n > 94) + throw std::runtime_error("Too big Fibonacci sequence. Elements would overflow."); + co_yield 0; + if (n == 1) + co_return; + co_yield 1; + if (n == 2) + co_return; + std::uint64_t a = 0; + std::uint64_t b = 1; + for (unsigned i = 2; i < n; i++) + { + std::uint64_t s = a + b; + co_yield s; + a = b; + b = s; + } +} +int main() +{ + try + { + auto gen = fibonacci_sequence(10); // max 94 before uint64_t overflows + for (int j = 0; gen; j++) + std::cout << "fib(" << j << ")=" << gen() << '\n'; + } catch (const std::exception& ex) { + std::cerr << "Exception: " << ex.what() << '\n'; + } + catch (...) + { + std::cerr << "Unknown exception.\n"; + } +} +)"; + 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().noquote() << errors; QVERIFY(!hasErrors); }