diff options
author | Christian Kandeler <christian.kandeler@qt.io> | 2023-02-09 15:11:14 +0100 |
---|---|---|
committer | Christian Kandeler <christian.kandeler@qt.io> | 2023-02-28 08:32:40 +0000 |
commit | 61de69ea907bfd5e7d0b6eb97975194352c9c5f3 (patch) | |
tree | c3a974c9685153c63f65348e34117a0408f2d30b /src/libs/3rdparty/cplusplus/Parser.cpp | |
parent | 89a8631784dfee4a96bc32f92d49e9747f426f1f (diff) | |
download | qt-creator-61de69ea907bfd5e7d0b6eb97975194352c9c5f3.tar.gz |
CPlusPlus: Handle C++20 concepts in parser
Change-Id: I8c6b8b1ba3f36b83cd1d667bec9830271147b1ac
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>
Diffstat (limited to 'src/libs/3rdparty/cplusplus/Parser.cpp')
-rw-r--r-- | src/libs/3rdparty/cplusplus/Parser.cpp | 185 |
1 files changed, 184 insertions, 1 deletions
diff --git a/src/libs/3rdparty/cplusplus/Parser.cpp b/src/libs/3rdparty/cplusplus/Parser.cpp index cb7bfa3a1b..ed023b15f0 100644 --- a/src/libs/3rdparty/cplusplus/Parser.cpp +++ b/src/libs/3rdparty/cplusplus/Parser.cpp @@ -1255,6 +1255,8 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) ast->declaration = nullptr; if (parseDeclaration(ast->declaration)) break; + if (parseConceptDeclaration(ast->declaration)) + break; error(start_declaration, "expected a declaration"); rewind(start_declaration + 1); @@ -1265,6 +1267,173 @@ bool Parser::parseTemplateDeclaration(DeclarationAST *&node) return true; } +bool Parser::parseConceptDeclaration(DeclarationAST *&node) +{ + if (!_languageFeatures.cxx20Enabled) + return false; + if (LA() != T_CONCEPT) + return false; + + const auto ast = new (_pool) ConceptDeclarationAST; + ast->concept_token = consumeToken(); + if (!parseName(ast->name)) + return false; + parseAttributeSpecifier(ast->attributes); + if (LA() != T_EQUAL) + return false; + ast->equals_token = consumeToken(); + if (!parseLogicalOrExpression(ast->constraint)) + return false; + if (LA() != T_SEMICOLON) + return false; + ast->semicolon_token = consumeToken(); + node = ast; + return true; +} + +bool Parser::parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node) +{ + if ((lookAtBuiltinTypeSpecifier() || _translationUnit->tokenAt(_tokenIndex).isKeyword()) + && (LA() != T_AUTO && LA() != T_DECLTYPE)) { + return false; + } + + TypeConstraintAST *typeConstraint = nullptr; + const int savedCursor = cursor(); + parseTypeConstraint(typeConstraint); + if (LA() != T_AUTO && (LA() != T_DECLTYPE || LA(1) != T_LPAREN || LA(2) != T_AUTO)) { + rewind(savedCursor); + return false; + } + const auto spec = new (_pool) PlaceholderTypeSpecifierAST; + spec->typeConstraint = typeConstraint; + if (LA() == T_DECLTYPE) { + spec->declTypetoken = consumeToken(); + if (LA() != T_LPAREN) + return false; + spec->lparenToken = consumeToken(); + if (LA() != T_AUTO) + return false; + spec->autoToken = consumeToken(); + if (LA() != T_RPAREN) + return false; + spec->rparenToken = consumeToken(); + } else { + spec->autoToken = consumeToken(); + } + node = spec; + return true; +} + +bool Parser::parseTypeConstraint(TypeConstraintAST *&node) +{ + NestedNameSpecifierListAST *nestedName = nullptr; + parseNestedNameSpecifierOpt(nestedName, true); + NameAST *conceptName = nullptr; + if (!parseUnqualifiedName(conceptName, true)) + return false; + const auto typeConstraint = new (_pool) TypeConstraintAST; + typeConstraint->nestedName = nestedName; + typeConstraint->conceptName = conceptName; + if (LA() != T_LESS) + return true; + typeConstraint->lessToken = consumeToken(); + if (LA() != T_GREATER) { + if (!parseTemplateArgumentList(typeConstraint->templateArgs)) + return false; + } + if (LA() != T_GREATER) + return false; + typeConstraint->greaterToken = consumeToken(); + node = typeConstraint; + return true; +} + +bool Parser::parseRequirement() +{ + if (LA() == T_TYPENAME) { // type-requirement + consumeToken(); + NameAST *name = nullptr; + if (!parseName(name, true)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + if (LA() == T_LBRACE) { // compound-requirement + consumeToken(); + ExpressionAST *expr = nullptr; + if (!parseExpression(expr)) + return false; + if (LA() != T_RBRACE) + return false; + consumeToken(); + if (LA() == T_NOEXCEPT) + consumeToken(); + if (LA() == T_SEMICOLON) { + consumeToken(); + return true; + } + TypeConstraintAST *typeConstraint = nullptr; + if (!parseTypeConstraint(typeConstraint)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + if (LA() == T_REQUIRES) { // nested-requirement + consumeToken(); + ExpressionAST *constraintExpr = nullptr; + if (!parseLogicalOrExpression(constraintExpr)) + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; + } + ExpressionAST *simpleExpr; + if (!parseExpression(simpleExpr)) // simple-requirement + return false; + if (LA() != T_SEMICOLON) + return false; + consumeToken(); + return true; +} + +bool Parser::parseRequiresExpression(ExpressionAST *&node) +{ + if (!_languageFeatures.cxx20Enabled) + return false; + if (LA() != T_REQUIRES) + return false; + + const auto ast = new (_pool) RequiresExpressionAST; + ast->requires_token = consumeToken(); + if (LA() == T_LPAREN) { + ast->lparen_token = consumeToken(); + if (!parseParameterDeclarationClause(ast->parameters)) + return false; + if (LA() != T_RPAREN) + return false; + ast->rparen_token = consumeToken(); + } + if (LA() != T_LBRACE) + return false; + ast->lbrace_token = consumeToken(); + if (!parseRequirement()) + return false; + while (LA() != T_RBRACE) { + if (!parseRequirement()) + return false; + } + ast->rbrace_token = consumeToken(); + + node = ast; + return true; +} + bool Parser::parseOperator(OperatorAST *&node) // ### FIXME { DEBUG_THIS_RULE(); @@ -1500,6 +1669,14 @@ bool Parser::parseDeclSpecifierSeq(SpecifierListAST *&decl_specifier_seq, NameAST *named_type_specifier = nullptr; SpecifierListAST **decl_specifier_seq_ptr = &decl_specifier_seq; for (;;) { + PlaceholderTypeSpecifierAST *placeholderSpec = nullptr; + // A simple auto is also technically a placeholder-type-specifier, but for historical + // reasons, it is handled further below. + if (LA() != T_AUTO && parsePlaceholderTypeSpecifier(placeholderSpec)) { + *decl_specifier_seq_ptr = new (_pool) SpecifierListAST(placeholderSpec); + decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next; + continue; + } if (! noStorageSpecifiers && ! onlySimpleTypeSpecifiers && lookAtStorageClassSpecifier()) { // storage-class-specifier SimpleSpecifierAST *spec = new (_pool) SimpleSpecifierAST; @@ -1550,8 +1727,9 @@ bool Parser::parseDeclSpecifierSeq(SpecifierListAST *&decl_specifier_seq, } decl_specifier_seq_ptr = &(*decl_specifier_seq_ptr)->next; has_type_specifier = true; - } else + } else { break; + } } return decl_specifier_seq != nullptr; @@ -1694,6 +1872,8 @@ bool Parser::hasAuto(SpecifierListAST *decl_specifier_list) const if (_translationUnit->tokenKind(simpleSpec->specifier_token) == T_AUTO) return true; } + if (spec->asPlaceholderTypeSpecifier()) + return true; } return false; } @@ -4731,6 +4911,9 @@ bool Parser::parsePrimaryExpression(ExpressionAST *&node) case T_AT_SELECTOR: return parseObjCExpression(node); + case T_REQUIRES: + return parseRequiresExpression(node); + default: { NameAST *name = nullptr; if (parseNameId(name)) { |