summaryrefslogtreecommitdiff
path: root/src/libs/3rdparty/cplusplus/Parser.cpp
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2023-02-09 15:11:14 +0100
committerChristian Kandeler <christian.kandeler@qt.io>2023-02-28 08:32:40 +0000
commit61de69ea907bfd5e7d0b6eb97975194352c9c5f3 (patch)
treec3a974c9685153c63f65348e34117a0408f2d30b /src/libs/3rdparty/cplusplus/Parser.cpp
parent89a8631784dfee4a96bc32f92d49e9747f426f1f (diff)
downloadqt-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.cpp185
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)) {