CPlusPlus: Add support for coroutines

Also fix some concept-related bugs uncovered by the test case.

Change-Id: Ia67c971026bcd85d9cc252f46cd4f56c2865d432
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-03-03 15:00:21 +01:00
parent dc8da57e64
commit 755d9769d8
15 changed files with 382 additions and 22 deletions

View File

@@ -3763,6 +3763,8 @@ int TemplateTypeParameterAST::firstToken() const
{ {
if (template_token) if (template_token)
return template_token; return template_token;
if (typeConstraint)
return typeConstraint->firstToken();
if (less_token) if (less_token)
return less_token; return less_token;
if (template_parameter_list) if (template_parameter_list)
@@ -3807,6 +3809,8 @@ int TemplateTypeParameterAST::lastToken() const
return candidate; return candidate;
if (less_token) if (less_token)
return less_token + 1; return less_token + 1;
if (typeConstraint)
return typeConstraint->lastToken();
if (template_token) if (template_token)
return template_token + 1; return template_token + 1;
return 1; return 1;

View File

@@ -184,6 +184,7 @@ public:
virtual ArrayInitializerAST *asArrayInitializer() { return nullptr; } virtual ArrayInitializerAST *asArrayInitializer() { return nullptr; }
virtual AsmDefinitionAST *asAsmDefinition() { return nullptr; } virtual AsmDefinitionAST *asAsmDefinition() { return nullptr; }
virtual AttributeSpecifierAST *asAttributeSpecifier() { return nullptr; } virtual AttributeSpecifierAST *asAttributeSpecifier() { return nullptr; }
virtual AwaitExpressionAST *asAwaitExpression() { return nullptr; }
virtual BaseSpecifierAST *asBaseSpecifier() { return nullptr; } virtual BaseSpecifierAST *asBaseSpecifier() { return nullptr; }
virtual BinaryExpressionAST *asBinaryExpression() { return nullptr; } virtual BinaryExpressionAST *asBinaryExpression() { return nullptr; }
virtual BoolLiteralAST *asBoolLiteral() { return nullptr; } virtual BoolLiteralAST *asBoolLiteral() { return nullptr; }
@@ -344,6 +345,7 @@ public:
virtual UsingAST *asUsing() { return nullptr; } virtual UsingAST *asUsing() { return nullptr; }
virtual UsingDirectiveAST *asUsingDirective() { return nullptr; } virtual UsingDirectiveAST *asUsingDirective() { return nullptr; }
virtual WhileStatementAST *asWhileStatement() { return nullptr; } virtual WhileStatementAST *asWhileStatement() { return nullptr; }
virtual YieldExpressionAST *asYieldExpression() { return nullptr; }
protected: protected:
virtual void accept0(ASTVisitor *visitor) = 0; virtual void accept0(ASTVisitor *visitor) = 0;
@@ -2826,6 +2828,44 @@ protected:
bool match0(AST *, ASTMatcher *) override; 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 class CPLUSPLUS_EXPORT NoExceptOperatorExpressionAST: public ExpressionAST
{ {
public: public:
@@ -2956,6 +2996,7 @@ class CPLUSPLUS_EXPORT TemplateTypeParameterAST: public DeclarationAST
{ {
public: public:
int template_token = 0; int template_token = 0;
TypeConstraintAST *typeConstraint = nullptr;
int less_token = 0; int less_token = 0;
DeclarationListAST *template_parameter_list = nullptr; DeclarationListAST *template_parameter_list = nullptr;
int greater_token = 0; int greater_token = 0;

View File

@@ -147,6 +147,8 @@ TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const
for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter; for (NestedNameSpecifierListAST *iter = nestedName, **ast_iter = &ast->nestedName; iter;
iter = iter->next, ast_iter = &(*ast_iter)->next) iter = iter->next, ast_iter = &(*ast_iter)->next)
*ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr); *ast_iter = new (pool) NestedNameSpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr);
if (conceptName)
ast->conceptName = conceptName->clone(pool);
ast->lessToken = lessToken; ast->lessToken = lessToken;
for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs; for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next) iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
@@ -1358,6 +1360,24 @@ ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const
return ast; 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 *NoExceptOperatorExpressionAST::clone(MemoryPool *pool) const
{ {
NoExceptOperatorExpressionAST *ast = new (pool) NoExceptOperatorExpressionAST; NoExceptOperatorExpressionAST *ast = new (pool) NoExceptOperatorExpressionAST;
@@ -1429,6 +1449,8 @@ TemplateTypeParameterAST *TemplateTypeParameterAST::clone(MemoryPool *pool) cons
{ {
TemplateTypeParameterAST *ast = new (pool) TemplateTypeParameterAST; TemplateTypeParameterAST *ast = new (pool) TemplateTypeParameterAST;
ast->template_token = template_token; ast->template_token = template_token;
if (typeConstraint)
ast->typeConstraint = typeConstraint->clone(pool);
ast->less_token = less_token; ast->less_token = less_token;
for (DeclarationListAST *iter = template_parameter_list, **ast_iter = &ast->template_parameter_list; for (DeclarationListAST *iter = template_parameter_list, **ast_iter = &ast->template_parameter_list;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next) iter; iter = iter->next, ast_iter = &(*ast_iter)->next)

View File

@@ -941,6 +941,20 @@ bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
return false; 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) bool NoExceptOperatorExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
{ {
if (NoExceptOperatorExpressionAST *_other = pattern->asNoExceptOperatorExpression()) if (NoExceptOperatorExpressionAST *_other = pattern->asNoExceptOperatorExpression())

View File

@@ -2277,6 +2277,26 @@ bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern)
return true; 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) bool ASTMatcher::match(NoExceptOperatorExpressionAST *node, NoExceptOperatorExpressionAST *pattern)
{ {
(void) node; (void) node;
@@ -2398,6 +2418,11 @@ bool ASTMatcher::match(TemplateTypeParameterAST *node, TemplateTypeParameterAST
pattern->template_token = node->template_token; 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; pattern->less_token = node->less_token;
if (! pattern->template_parameter_list) if (! pattern->template_parameter_list)

View File

@@ -38,6 +38,7 @@ public:
virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern); virtual bool match(ArrayAccessAST *node, ArrayAccessAST *pattern);
virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern); virtual bool match(ArrayDeclaratorAST *node, ArrayDeclaratorAST *pattern);
virtual bool match(ArrayInitializerAST *node, ArrayInitializerAST *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(AsmDefinitionAST *node, AsmDefinitionAST *pattern);
virtual bool match(BaseSpecifierAST *node, BaseSpecifierAST *pattern); virtual bool match(BaseSpecifierAST *node, BaseSpecifierAST *pattern);
virtual bool match(BinaryExpressionAST *node, BinaryExpressionAST *pattern); virtual bool match(BinaryExpressionAST *node, BinaryExpressionAST *pattern);
@@ -188,6 +189,7 @@ public:
virtual bool match(UsingAST *node, UsingAST *pattern); virtual bool match(UsingAST *node, UsingAST *pattern);
virtual bool match(UsingDirectiveAST *node, UsingDirectiveAST *pattern); virtual bool match(UsingDirectiveAST *node, UsingDirectiveAST *pattern);
virtual bool match(WhileStatementAST *node, WhileStatementAST *pattern); virtual bool match(WhileStatementAST *node, WhileStatementAST *pattern);
virtual bool match(YieldExpressionAST *node, YieldExpressionAST *pattern);
}; };
} // namespace CPlusPlus } // namespace CPlusPlus

View File

@@ -996,6 +996,20 @@ void ThrowExpressionAST::accept0(ASTVisitor *visitor)
visitor->endVisit(this); 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) void NoExceptOperatorExpressionAST::accept0(ASTVisitor *visitor)
{ {
if (visitor->visit(this)) { if (visitor->visit(this)) {
@@ -1051,6 +1065,7 @@ void TypenameTypeParameterAST::accept0(ASTVisitor *visitor)
void TemplateTypeParameterAST::accept0(ASTVisitor *visitor) void TemplateTypeParameterAST::accept0(ASTVisitor *visitor)
{ {
if (visitor->visit(this)) { if (visitor->visit(this)) {
accept(typeConstraint, visitor);
accept(template_parameter_list, visitor); accept(template_parameter_list, visitor);
accept(name, visitor); accept(name, visitor);
accept(type_id, visitor); accept(type_id, visitor);

View File

@@ -81,6 +81,7 @@ public:
virtual bool visit(ArrayDeclaratorAST *) { return true; } virtual bool visit(ArrayDeclaratorAST *) { return true; }
virtual bool visit(ArrayInitializerAST *) { return true; } virtual bool visit(ArrayInitializerAST *) { return true; }
virtual bool visit(AsmDefinitionAST *) { return true; } virtual bool visit(AsmDefinitionAST *) { return true; }
virtual bool visit(AwaitExpressionAST *) { return true; }
virtual bool visit(BaseSpecifierAST *) { return true; } virtual bool visit(BaseSpecifierAST *) { return true; }
virtual bool visit(BinaryExpressionAST *) { return true; } virtual bool visit(BinaryExpressionAST *) { return true; }
virtual bool visit(BoolLiteralAST *) { return true; } virtual bool visit(BoolLiteralAST *) { return true; }
@@ -230,6 +231,7 @@ public:
virtual bool visit(UsingAST *) { return true; } virtual bool visit(UsingAST *) { return true; }
virtual bool visit(UsingDirectiveAST *) { return true; } virtual bool visit(UsingDirectiveAST *) { return true; }
virtual bool visit(WhileStatementAST *) { return true; } virtual bool visit(WhileStatementAST *) { return true; }
virtual bool visit(YieldExpressionAST *) { return true; }
virtual void endVisit(AccessDeclarationAST *) {} virtual void endVisit(AccessDeclarationAST *) {}
virtual void endVisit(AliasDeclarationAST *) {} virtual void endVisit(AliasDeclarationAST *) {}
@@ -240,6 +242,7 @@ public:
virtual void endVisit(ArrayDeclaratorAST *) {} virtual void endVisit(ArrayDeclaratorAST *) {}
virtual void endVisit(ArrayInitializerAST *) {} virtual void endVisit(ArrayInitializerAST *) {}
virtual void endVisit(AsmDefinitionAST *) {} virtual void endVisit(AsmDefinitionAST *) {}
virtual void endVisit(AwaitExpressionAST *) {}
virtual void endVisit(BaseSpecifierAST *) {} virtual void endVisit(BaseSpecifierAST *) {}
virtual void endVisit(BinaryExpressionAST *) {} virtual void endVisit(BinaryExpressionAST *) {}
virtual void endVisit(BoolLiteralAST *) {} virtual void endVisit(BoolLiteralAST *) {}
@@ -389,6 +392,7 @@ public:
virtual void endVisit(UsingAST *) {} virtual void endVisit(UsingAST *) {}
virtual void endVisit(UsingDirectiveAST *) {} virtual void endVisit(UsingDirectiveAST *) {}
virtual void endVisit(WhileStatementAST *) {} virtual void endVisit(WhileStatementAST *) {}
virtual void endVisit(YieldExpressionAST *) {}
private: private:
TranslationUnit *_translationUnit; TranslationUnit *_translationUnit;

View File

@@ -40,6 +40,7 @@ class ArrayDeclaratorAST;
class ArrayInitializerAST; class ArrayInitializerAST;
class AsmDefinitionAST; class AsmDefinitionAST;
class AttributeSpecifierAST; class AttributeSpecifierAST;
class AwaitExpressionAST;
class BaseSpecifierAST; class BaseSpecifierAST;
class BinaryExpressionAST; class BinaryExpressionAST;
class BoolLiteralAST; class BoolLiteralAST;
@@ -200,6 +201,7 @@ class UnaryExpressionAST;
class UsingAST; class UsingAST;
class UsingDirectiveAST; class UsingDirectiveAST;
class WhileStatementAST; class WhileStatementAST;
class YieldExpressionAST;
typedef List<ExpressionAST *> ExpressionListAST; typedef List<ExpressionAST *> ExpressionListAST;
typedef List<DeclarationAST *> DeclarationListAST; typedef List<DeclarationAST *> DeclarationListAST;

View File

@@ -2532,6 +2532,11 @@ bool Bind::visit(TemplateTypeParameterAST *ast)
return false; return false;
} }
bool Bind::visit(TypeConstraintAST *)
{
return false;
}
bool Bind::visit(UsingAST *ast) bool Bind::visit(UsingAST *ast)
{ {
int sourceLocation = location(ast->name, ast->firstToken()); int sourceLocation = location(ast->name, ast->firstToken());

View File

@@ -230,6 +230,7 @@ protected:
bool visit(TemplateDeclarationAST *ast) override; bool visit(TemplateDeclarationAST *ast) override;
bool visit(TypenameTypeParameterAST *ast) override; bool visit(TypenameTypeParameterAST *ast) override;
bool visit(TemplateTypeParameterAST *ast) override; bool visit(TemplateTypeParameterAST *ast) override;
bool visit(TypeConstraintAST *ast) override;
bool visit(UsingAST *ast) override; bool visit(UsingAST *ast) override;
bool visit(UsingDirectiveAST *ast) override; bool visit(UsingDirectiveAST *ast) override;
bool visit(ObjCClassForwardDeclarationAST *ast) override; bool visit(ObjCClassForwardDeclarationAST *ast) override;

View File

@@ -413,6 +413,7 @@ bool Parser::skipUntilStatement()
case T_BREAK: case T_BREAK:
case T_CONTINUE: case T_CONTINUE:
case T_RETURN: case T_RETURN:
case T_CO_RETURN:
case T_GOTO: case T_GOTO:
case T_TRY: case T_TRY:
case T_CATCH: case T_CATCH:
@@ -1329,16 +1330,20 @@ bool Parser::parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node)
bool Parser::parseTypeConstraint(TypeConstraintAST *&node) bool Parser::parseTypeConstraint(TypeConstraintAST *&node)
{ {
if (!_languageFeatures.cxx20Enabled)
return false;
NestedNameSpecifierListAST *nestedName = nullptr; NestedNameSpecifierListAST *nestedName = nullptr;
parseNestedNameSpecifierOpt(nestedName, true); parseNestedNameSpecifierOpt(nestedName, true);
NameAST *conceptName = nullptr; NameAST *conceptName = nullptr;
if (!parseUnqualifiedName(conceptName, true)) if (!parseUnqualifiedName(conceptName, false))
return false; return false;
const auto typeConstraint = new (_pool) TypeConstraintAST; const auto typeConstraint = new (_pool) TypeConstraintAST;
typeConstraint->nestedName = nestedName; typeConstraint->nestedName = nestedName;
typeConstraint->conceptName = conceptName; typeConstraint->conceptName = conceptName;
if (LA() != T_LESS) if (LA() != T_LESS) {
node = typeConstraint;
return true; return true;
}
typeConstraint->lessToken = consumeToken(); typeConstraint->lessToken = consumeToken();
if (LA() != T_GREATER) { if (LA() != T_GREATER) {
if (!parseTemplateArgumentList(typeConstraint->templateArgs)) if (!parseTemplateArgumentList(typeConstraint->templateArgs))
@@ -2208,8 +2213,8 @@ bool Parser::parseTypenameTypeParameter(DeclarationAST *&node)
bool Parser::parseTemplateTypeParameter(DeclarationAST *&node) bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_TEMPLATE) {
TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST; TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
if (LA() == T_TEMPLATE) {
ast->template_token = consumeToken(); ast->template_token = consumeToken();
if (LA() == T_LESS) if (LA() == T_LESS)
ast->less_token = consumeToken(); ast->less_token = consumeToken();
@@ -2218,6 +2223,9 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
ast->greater_token = consumeToken(); ast->greater_token = consumeToken();
if (LA() == T_CLASS) if (LA() == T_CLASS)
ast->class_token = consumeToken(); ast->class_token = consumeToken();
} else if (!parseTypeConstraint(ast->typeConstraint)) {
return false;
}
if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT) if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT)
ast->dot_dot_dot_token = consumeToken(); ast->dot_dot_dot_token = consumeToken();
@@ -2231,8 +2239,6 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
node = ast; node = ast;
return true; return true;
} }
return false;
}
bool Parser::lookAtTypeParameter() bool Parser::lookAtTypeParameter()
{ {
@@ -2267,10 +2273,9 @@ bool Parser::parseTypeParameter(DeclarationAST *&node)
if (lookAtTypeParameter()) if (lookAtTypeParameter())
return parseTypenameTypeParameter(node); return parseTypenameTypeParameter(node);
else if (LA() == T_TEMPLATE) if (LA() == T_TEMPLATE)
return parseTemplateTypeParameter(node);
return parseTemplateTypeParameter(node); return parseTemplateTypeParameter(node);
else
return false;
} }
bool Parser::parseTypeId(ExpressionAST *&node) bool Parser::parseTypeId(ExpressionAST *&node)
@@ -3556,6 +3561,7 @@ bool Parser::parseStatement(StatementAST *&node, bool blockLabeledStatement)
return parseGotoStatement(node); return parseGotoStatement(node);
case T_RETURN: case T_RETURN:
case T_CO_RETURN:
return parseReturnStatement(node); return parseReturnStatement(node);
case T_LBRACE: case T_LBRACE:
@@ -3666,7 +3672,7 @@ bool Parser::parseGotoStatement(StatementAST *&node)
bool Parser::parseReturnStatement(StatementAST *&node) bool Parser::parseReturnStatement(StatementAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_RETURN) { if (LA() == T_RETURN || LA() == T_CO_RETURN) {
ReturnStatementAST *ast = new (_pool) ReturnStatementAST; ReturnStatementAST *ast = new (_pool) ReturnStatementAST;
ast->return_token = consumeToken(); ast->return_token = consumeToken();
if (_languageFeatures.cxx11Enabled && LA() == T_LBRACE) if (_languageFeatures.cxx11Enabled && LA() == T_LBRACE)
@@ -5637,6 +5643,11 @@ bool Parser::parseUnaryExpression(ExpressionAST *&node)
return parseNoExceptOperatorExpression(node); return parseNoExceptOperatorExpression(node);
} }
case T_CO_AWAIT:
if (!_languageFeatures.cxx20Enabled)
break;
return parseAwaitExpression(node);
default: default:
break; break;
} // switch } // switch
@@ -5895,6 +5906,8 @@ bool Parser::parseAssignmentExpression(ExpressionAST *&node)
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();
if (LA() == T_THROW) if (LA() == T_THROW)
return parseThrowExpression(node); return parseThrowExpression(node);
else if (LA() == T_CO_YIELD)
return parseYieldExpression(node);
else else
PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment) PARSE_EXPRESSION_WITH_OPERATOR_PRECEDENCE(node, Prec::Assignment)
} }
@@ -6023,6 +6036,34 @@ bool Parser::parseThrowExpression(ExpressionAST *&node)
return false; 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) bool Parser::parseNoExceptOperatorExpression(ExpressionAST *&node)
{ {
DEBUG_THIS_RULE(); DEBUG_THIS_RULE();

View File

@@ -152,6 +152,8 @@ public:
bool parseTemplateParameter(DeclarationAST *&node); bool parseTemplateParameter(DeclarationAST *&node);
bool parseTemplateParameterList(DeclarationListAST *&node); bool parseTemplateParameterList(DeclarationListAST *&node);
bool parseThrowExpression(ExpressionAST *&node); bool parseThrowExpression(ExpressionAST *&node);
bool parseYieldExpression(ExpressionAST *&node);
bool parseAwaitExpression(ExpressionAST *&node);
bool parseNoExceptOperatorExpression(ExpressionAST *&node); bool parseNoExceptOperatorExpression(ExpressionAST *&node);
bool parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder); bool parseTryBlockStatement(StatementAST *&node, CtorInitializerAST **placeholder);
bool parseCatchClause(CatchClauseListAST *&node); bool parseCatchClause(CatchClauseListAST *&node);

View File

@@ -924,6 +924,7 @@ bool CodeFormatter::tryStatement()
return true; return true;
switch (kind) { switch (kind) {
case T_RETURN: case T_RETURN:
case T_CO_RETURN:
enter(return_statement); enter(return_statement);
enter(expression); enter(expression);
return true; return true;
@@ -1651,6 +1652,7 @@ void QtStyleCodeFormatter::adjustIndent(const Tokens &tokens, int lexerState, in
case T_BREAK: case T_BREAK:
case T_CONTINUE: case T_CONTINUE:
case T_RETURN: case T_RETURN:
case T_CO_RETURN:
if (topState.type == case_cont) { if (topState.type == case_cont) {
*indentDepth = topState.savedIndentDepth; *indentDepth = topState.savedIndentDepth;
if (m_styleSettings.indentControlFlowRelativeToSwitchLabels) if (m_styleSettings.indentControlFlowRelativeToSwitchLabels)

View File

@@ -148,6 +148,7 @@ private Q_SLOTS:
void concepts(); void concepts();
void requiresClause(); void requiresClause();
void coroutines();
}; };
@@ -315,7 +316,7 @@ void *func2(IsPointer auto p)
processDocument(doc, source.toUtf8(), features, &errors); processDocument(doc, source.toUtf8(), features, &errors);
const bool hasErrors = !errors.isEmpty(); const bool hasErrors = !errors.isEmpty();
if (hasErrors) if (hasErrors)
qDebug() << errors; qDebug().noquote() << errors;
QVERIFY(!hasErrors); QVERIFY(!hasErrors);
} }
@@ -337,7 +338,186 @@ template<class T> void h(T) requires (is_purrable<T>());
processDocument(doc, source.toUtf8(), features, &errors); processDocument(doc, source.toUtf8(), features, &errors);
const bool hasErrors = !errors.isEmpty(); const bool hasErrors = !errors.isEmpty();
if (hasErrors) 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<promise>
{
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 <typename T>
struct Generator
{
struct promise_type;
using handle_type = std::coroutine_handle<promise_type>;
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 <std::convertible_to<T> From>
std::suspend_always yield_value(From&& from)
{
value_ = std::forward<From>(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<std::uint64_t>
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); QVERIFY(!hasErrors);
} }