forked from qt-creator/qt-creator
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:
4
src/libs/3rdparty/cplusplus/AST.cpp
vendored
4
src/libs/3rdparty/cplusplus/AST.cpp
vendored
@@ -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;
|
||||
|
41
src/libs/3rdparty/cplusplus/AST.h
vendored
41
src/libs/3rdparty/cplusplus/AST.h
vendored
@@ -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;
|
||||
|
22
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
22
src/libs/3rdparty/cplusplus/ASTClone.cpp
vendored
@@ -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)
|
||||
|
14
src/libs/3rdparty/cplusplus/ASTMatch0.cpp
vendored
14
src/libs/3rdparty/cplusplus/ASTMatch0.cpp
vendored
@@ -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())
|
||||
|
25
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
25
src/libs/3rdparty/cplusplus/ASTMatcher.cpp
vendored
@@ -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)
|
||||
|
2
src/libs/3rdparty/cplusplus/ASTMatcher.h
vendored
2
src/libs/3rdparty/cplusplus/ASTMatcher.h
vendored
@@ -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
|
||||
|
15
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
15
src/libs/3rdparty/cplusplus/ASTVisit.cpp
vendored
@@ -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);
|
||||
|
4
src/libs/3rdparty/cplusplus/ASTVisitor.h
vendored
4
src/libs/3rdparty/cplusplus/ASTVisitor.h
vendored
@@ -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;
|
||||
|
2
src/libs/3rdparty/cplusplus/ASTfwd.h
vendored
2
src/libs/3rdparty/cplusplus/ASTfwd.h
vendored
@@ -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<ExpressionAST *> ExpressionListAST;
|
||||
typedef List<DeclarationAST *> DeclarationListAST;
|
||||
|
5
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
5
src/libs/3rdparty/cplusplus/Bind.cpp
vendored
@@ -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());
|
||||
|
1
src/libs/3rdparty/cplusplus/Bind.h
vendored
1
src/libs/3rdparty/cplusplus/Bind.h
vendored
@@ -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;
|
||||
|
59
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
59
src/libs/3rdparty/cplusplus/Parser.cpp
vendored
@@ -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();
|
||||
if (LA() == T_TEMPLATE) {
|
||||
TemplateTypeParameterAST *ast = new (_pool) TemplateTypeParameterAST;
|
||||
if (LA() == T_TEMPLATE) {
|
||||
ast->template_token = consumeToken();
|
||||
if (LA() == T_LESS)
|
||||
ast->less_token = consumeToken();
|
||||
@@ -2218,6 +2223,9 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
|
||||
ast->greater_token = consumeToken();
|
||||
if (LA() == T_CLASS)
|
||||
ast->class_token = consumeToken();
|
||||
} else if (!parseTypeConstraint(ast->typeConstraint)) {
|
||||
return false;
|
||||
}
|
||||
if (_languageFeatures.cxx11Enabled && LA() == T_DOT_DOT_DOT)
|
||||
ast->dot_dot_dot_token = consumeToken();
|
||||
|
||||
@@ -2231,8 +2239,6 @@ bool Parser::parseTemplateTypeParameter(DeclarationAST *&node)
|
||||
node = ast;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
return parseTemplateTypeParameter(node);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
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();
|
||||
|
2
src/libs/3rdparty/cplusplus/Parser.h
vendored
2
src/libs/3rdparty/cplusplus/Parser.h
vendored
@@ -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);
|
||||
|
@@ -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)
|
||||
|
@@ -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<class T> void h(T) requires (is_purrable<T>());
|
||||
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<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);
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user