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>
This commit is contained in:
Christian Kandeler
2023-02-09 15:11:14 +01:00
parent 89a8631784
commit 61de69ea90
15 changed files with 547 additions and 1 deletions

View File

@@ -4634,3 +4634,33 @@ int NoExceptOperatorExpressionAST::lastToken() const
return noexcept_token + 1;
return 1;
}
int TypeConstraintAST::firstToken() const
{
if (nestedName)
return nestedName->firstToken();
return conceptName->firstToken();
}
int TypeConstraintAST::lastToken() const
{
if (greaterToken)
return greaterToken + 1;
return conceptName->lastToken();
}
int PlaceholderTypeSpecifierAST::firstToken() const
{
if (typeConstraint)
return typeConstraint->firstToken();
if (declTypetoken)
return declTypetoken;
return autoToken;
}
int PlaceholderTypeSpecifierAST::lastToken() const
{
if (rparenToken)
return rparenToken + 1;
return autoToken + 1;
}

View File

@@ -290,6 +290,7 @@ public:
virtual OperatorFunctionIdAST *asOperatorFunctionId() { return nullptr; }
virtual ParameterDeclarationAST *asParameterDeclaration() { return nullptr; }
virtual ParameterDeclarationClauseAST *asParameterDeclarationClause() { return nullptr; }
virtual PlaceholderTypeSpecifierAST *asPlaceholderTypeSpecifier() { return nullptr; }
virtual PointerAST *asPointer() { return nullptr; }
virtual PointerLiteralAST *asPointerLiteral() { return nullptr; }
virtual PointerToMemberAST *asPointerToMember() { return nullptr; }
@@ -322,6 +323,7 @@ public:
virtual StringLiteralAST *asStringLiteral() { return nullptr; }
virtual SwitchStatementAST *asSwitchStatement() { return nullptr; }
virtual TemplateDeclarationAST *asTemplateDeclaration() { return nullptr; }
virtual ConceptDeclarationAST *asConceptDeclaration() { return nullptr; }
virtual TemplateIdAST *asTemplateId() { return nullptr; }
virtual TemplateTypeParameterAST *asTemplateTypeParameter() { return nullptr; }
virtual ThisExpressionAST *asThisExpression() { return nullptr; }
@@ -329,6 +331,7 @@ public:
virtual TrailingReturnTypeAST *asTrailingReturnType() { return nullptr; }
virtual TranslationUnitAST *asTranslationUnit() { return nullptr; }
virtual TryBlockStatementAST *asTryBlockStatement() { return nullptr; }
virtual TypeConstraintAST *asTypeConstraint() { return nullptr; }
virtual TypeConstructorCallAST *asTypeConstructorCall() { return nullptr; }
virtual TypeIdAST *asTypeId() { return nullptr; }
virtual TypeidExpressionAST *asTypeidExpression() { return nullptr; }
@@ -336,6 +339,7 @@ public:
virtual TypenameTypeParameterAST *asTypenameTypeParameter() { return nullptr; }
virtual TypeofSpecifierAST *asTypeofSpecifier() { return nullptr; }
virtual UnaryExpressionAST *asUnaryExpression() { return nullptr; }
virtual RequiresExpressionAST *asRequiresExpression() { return nullptr; }
virtual UsingAST *asUsing() { return nullptr; }
virtual UsingDirectiveAST *asUsingDirective() { return nullptr; }
virtual WhileStatementAST *asWhileStatement() { return nullptr; }
@@ -636,6 +640,49 @@ protected:
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT TypeConstraintAST: public AST
{
public:
NestedNameSpecifierListAST *nestedName = nullptr;
NameAST *conceptName = nullptr;
int lessToken = 0;
ExpressionListAST *templateArgs = nullptr;
int greaterToken = 0;
TypeConstraintAST *asTypeConstraint() override { return this; }
int firstToken() const override;
int lastToken() const override;
TypeConstraintAST *clone(MemoryPool *pool) const override;
void accept0(ASTVisitor *visitor) override;
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT PlaceholderTypeSpecifierAST: public SpecifierAST
{
public:
TypeConstraintAST *typeConstraint = nullptr;
int declTypetoken = 0;
int lparenToken = 0;
int decltypeToken = 0;
int autoToken = 0;
int rparenToken = 0;
public:
PlaceholderTypeSpecifierAST *asPlaceholderTypeSpecifier() override { return this; }
int firstToken() const override;
int lastToken() const override;
PlaceholderTypeSpecifierAST *clone(MemoryPool *pool) const override;
protected:
void accept0(ASTVisitor *visitor) override;
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT DeclaratorAST: public AST
{
public:
@@ -2734,6 +2781,29 @@ protected:
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT ConceptDeclarationAST: public DeclarationAST
{
public:
int concept_token = 0;
NameAST *name = nullptr;
SpecifierListAST *attributes = nullptr;
int equals_token = 0;
ExpressionAST *constraint = nullptr;
int semicolon_token = 0;
public:
ConceptDeclarationAST *asConceptDeclaration() override { return this; }
int firstToken() const override { return concept_token; }
int lastToken() const override { return semicolon_token + 1; }
ConceptDeclarationAST *clone(MemoryPool *pool) const override;
protected:
void accept0(ASTVisitor *visitor) override;
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT ThrowExpressionAST: public ExpressionAST
{
public:
@@ -2927,6 +2997,29 @@ protected:
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT RequiresExpressionAST: public ExpressionAST
{
public:
int requires_token = 0;
int lparen_token = 0;
ParameterDeclarationClauseAST *parameters = nullptr;
int rparen_token = 0;
int lbrace_token = 0;
int rbrace_token = 0;
public:
RequiresExpressionAST *asRequiresExpression() override { return this; }
int firstToken() const override { return requires_token; }
int lastToken() const override { return rbrace_token + 1; }
RequiresExpressionAST *clone(MemoryPool *pool) const override;
protected:
void accept0(ASTVisitor *visitor) override;
bool match0(AST *, ASTMatcher *) override;
};
class CPLUSPLUS_EXPORT UsingAST: public DeclarationAST
{
public:

View File

@@ -141,6 +141,32 @@ DecltypeSpecifierAST *DecltypeSpecifierAST::clone(MemoryPool *pool) const
return ast;
}
TypeConstraintAST *TypeConstraintAST::clone(MemoryPool *pool) const
{
const auto ast = new (pool) TypeConstraintAST;
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);
ast->lessToken = lessToken;
for (ExpressionListAST *iter = templateArgs, **ast_iter = &ast->templateArgs;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next)
*ast_iter = new (pool) ExpressionListAST((iter->value) ? iter->value->clone(pool) : nullptr);
ast->greaterToken = greaterToken;
return ast;
}
PlaceholderTypeSpecifierAST *PlaceholderTypeSpecifierAST::clone(MemoryPool *pool) const
{
const auto ast = new (pool) PlaceholderTypeSpecifierAST;
if (typeConstraint)
ast->typeConstraint = typeConstraint->clone(pool);
ast->lparenToken = lparenToken;
ast->declTypetoken = declTypetoken;
ast->autoToken = autoToken;
ast->rparenToken = rparenToken;
return ast;
}
DeclaratorAST *DeclaratorAST::clone(MemoryPool *pool) const
{
DeclaratorAST *ast = new (pool) DeclaratorAST;
@@ -1284,6 +1310,34 @@ TemplateDeclarationAST *TemplateDeclarationAST::clone(MemoryPool *pool) const
return ast;
}
ConceptDeclarationAST *ConceptDeclarationAST::clone(MemoryPool *pool) const
{
const auto ast = new (pool) ConceptDeclarationAST;
ast->concept_token = concept_token;
ast->name = name->clone(pool);
ast->equals_token = equals_token;
ast->semicolon_token = semicolon_token;
for (SpecifierListAST *iter = attributes, **ast_iter = &ast->attributes;
iter; iter = iter->next, ast_iter = &(*ast_iter)->next) {
*ast_iter = new (pool) SpecifierListAST((iter->value) ? iter->value->clone(pool) : nullptr);
}
ast->constraint = constraint->clone(pool);
return ast;
}
RequiresExpressionAST *RequiresExpressionAST::clone(MemoryPool *pool) const
{
const auto ast = new (pool) RequiresExpressionAST;
ast->requires_token = requires_token;
ast->lparen_token = lparen_token;
if (parameters)
ast->parameters = parameters->clone(pool);
ast->rparen_token = rparen_token;
ast->lbrace_token = lbrace_token;
ast->rbrace_token = rbrace_token;
return ast;
}
ThrowExpressionAST *ThrowExpressionAST::clone(MemoryPool *pool) const
{
ThrowExpressionAST *ast = new (pool) ThrowExpressionAST;

View File

@@ -112,6 +112,21 @@ bool DecltypeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher)
return false;
}
bool TypeConstraintAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (const auto _other = pattern->asTypeConstraint())
return matcher->match(this, _other);
return false;
}
bool PlaceholderTypeSpecifierAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (const auto _other = pattern->asPlaceholderTypeSpecifier())
return matcher->match(this, _other);
return false;
}
bool DeclaratorAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (DeclaratorAST *_other = pattern->asDeclarator())
@@ -896,6 +911,21 @@ bool TemplateDeclarationAST::match0(AST *pattern, ASTMatcher *matcher)
return false;
}
bool ConceptDeclarationAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (ConceptDeclarationAST *_other = pattern->asConceptDeclaration())
return matcher->match(this, _other);
return false;
}
bool RequiresExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (const auto other = pattern->asRequiresExpression())
return matcher->match(this, other);
return false;
}
bool ThrowExpressionAST::match0(AST *pattern, ASTMatcher *matcher)
{
if (ThrowExpressionAST *_other = pattern->asThrowExpression())

View File

@@ -216,6 +216,25 @@ bool ASTMatcher::match(DecltypeSpecifierAST *node, DecltypeSpecifierAST *pattern
return true;
}
bool ASTMatcher::match(TypeConstraintAST *node, TypeConstraintAST *pattern)
{
if (!pattern->nestedName)
pattern->nestedName = node->nestedName;
else if (!AST::match(node->nestedName, pattern->nestedName, this))
return false;
if (!pattern->conceptName)
pattern->conceptName = node->conceptName;
else if (!AST::match(node->conceptName, pattern->conceptName, this))
return false;
pattern->lessToken = node->lessToken;
if (!pattern->templateArgs)
pattern->templateArgs = node->templateArgs;
else if (!AST::match(node->templateArgs, pattern->templateArgs, this))
return false;
pattern->greaterToken = node->greaterToken;
return true;
}
bool ASTMatcher::match(DeclaratorAST *node, DeclaratorAST *pattern)
{
(void) node;
@@ -1749,6 +1768,19 @@ bool ASTMatcher::match(ParameterDeclarationClauseAST *node, ParameterDeclaration
return true;
}
bool ASTMatcher::match(PlaceholderTypeSpecifierAST *node, PlaceholderTypeSpecifierAST *pattern)
{
if (!pattern->typeConstraint)
pattern->typeConstraint = node->typeConstraint;
else if (!AST::match(node->typeConstraint, pattern->typeConstraint, this))
return false;
pattern->declTypetoken = node->declTypetoken;
pattern->lparenToken = node->lparenToken;
pattern->autoToken = node->autoToken;
pattern->rparenToken = node->rparenToken;
return true;
}
bool ASTMatcher::match(CallAST *node, CallAST *pattern)
{
(void) node;
@@ -2181,6 +2213,40 @@ bool ASTMatcher::match(TemplateDeclarationAST *node, TemplateDeclarationAST *pat
return true;
}
bool ASTMatcher::match(ConceptDeclarationAST *node, ConceptDeclarationAST *pattern)
{
pattern->concept_token = node->concept_token;
pattern->equals_token = node->equals_token;
pattern->semicolon_token = node->semicolon_token;
if (!pattern->attributes)
pattern->attributes = node->attributes;
else if (!AST::match(node->attributes, pattern->attributes, this))
return false;
if (!pattern->constraint)
pattern->constraint = node->constraint;
else if (! AST::match(node->constraint, pattern->constraint, this))
return false;
return true;
}
bool ASTMatcher::match(RequiresExpressionAST *node, RequiresExpressionAST *pattern)
{
pattern->requires_token = node->requires_token;
pattern->lparen_token = node->lparen_token;
pattern->lbrace_token = node->lbrace_token;
pattern->rbrace_token = node->rbrace_token;
if (!pattern->parameters)
pattern->parameters = node->parameters;
else if (!AST::match(node->parameters, pattern->parameters, this))
return false;
return true;
}
bool ASTMatcher::match(ThrowExpressionAST *node, ThrowExpressionAST *pattern)
{
(void) node;

View File

@@ -54,6 +54,7 @@ public:
virtual bool match(CompoundExpressionAST *node, CompoundExpressionAST *pattern);
virtual bool match(CompoundLiteralAST *node, CompoundLiteralAST *pattern);
virtual bool match(CompoundStatementAST *node, CompoundStatementAST *pattern);
virtual bool match(ConceptDeclarationAST *node, ConceptDeclarationAST *pattern);
virtual bool match(ConditionAST *node, ConditionAST *pattern);
virtual bool match(ConditionalExpressionAST *node, ConditionalExpressionAST *pattern);
virtual bool match(ContinueStatementAST *node, ContinueStatementAST *pattern);
@@ -139,6 +140,7 @@ public:
virtual bool match(OperatorFunctionIdAST *node, OperatorFunctionIdAST *pattern);
virtual bool match(ParameterDeclarationAST *node, ParameterDeclarationAST *pattern);
virtual bool match(ParameterDeclarationClauseAST *node, ParameterDeclarationClauseAST *pattern);
virtual bool match(PlaceholderTypeSpecifierAST *node, PlaceholderTypeSpecifierAST *pattern);
virtual bool match(PointerAST *node, PointerAST *pattern);
virtual bool match(PointerLiteralAST *node, PointerLiteralAST *pattern);
virtual bool match(PointerToMemberAST *node, PointerToMemberAST *pattern);
@@ -156,6 +158,7 @@ public:
virtual bool match(QualifiedNameAST *node, QualifiedNameAST *pattern);
virtual bool match(RangeBasedForStatementAST *node, RangeBasedForStatementAST *pattern);
virtual bool match(ReferenceAST *node, ReferenceAST *pattern);
virtual bool match(RequiresExpressionAST *node, RequiresExpressionAST *pattern);
virtual bool match(ReturnStatementAST *node, ReturnStatementAST *pattern);
virtual bool match(SimpleDeclarationAST *node, SimpleDeclarationAST *pattern);
virtual bool match(SimpleNameAST *node, SimpleNameAST *pattern);
@@ -173,6 +176,7 @@ public:
virtual bool match(TrailingReturnTypeAST *node, TrailingReturnTypeAST *pattern);
virtual bool match(TranslationUnitAST *node, TranslationUnitAST *pattern);
virtual bool match(TryBlockStatementAST *node, TryBlockStatementAST *pattern);
virtual bool match(TypeConstraintAST *node, TypeConstraintAST *pattern);
virtual bool match(TypeConstructorCallAST *node, TypeConstructorCallAST *pattern);
virtual bool match(TypeIdAST *node, TypeIdAST *pattern);
virtual bool match(TypeidExpressionAST *node, TypeidExpressionAST *pattern);

View File

@@ -110,6 +110,23 @@ void DecltypeSpecifierAST::accept0(ASTVisitor *visitor)
visitor->endVisit(this);
}
void TypeConstraintAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
accept(nestedName, visitor);
accept(conceptName, visitor);
accept(templateArgs, visitor);
}
visitor->endVisit(this);
}
void PlaceholderTypeSpecifierAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this))
accept(typeConstraint, visitor);
visitor->endVisit(this);
}
void DeclaratorAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
@@ -946,6 +963,23 @@ void TemplateDeclarationAST::accept0(ASTVisitor *visitor)
visitor->endVisit(this);
}
void ConceptDeclarationAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {
accept(name, visitor);
accept(attributes, visitor);
accept(constraint, visitor);
}
visitor->endVisit(this);
}
void RequiresExpressionAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this))
accept(parameters, visitor);
visitor->endVisit(this);
}
void ThrowExpressionAST::accept0(ASTVisitor *visitor)
{
if (visitor->visit(this)) {

View File

@@ -96,6 +96,7 @@ public:
virtual bool visit(CompoundExpressionAST *) { return true; }
virtual bool visit(CompoundLiteralAST *) { return true; }
virtual bool visit(CompoundStatementAST *) { return true; }
virtual bool visit(ConceptDeclarationAST *) { return true; }
virtual bool visit(ConditionAST *) { return true; }
virtual bool visit(ConditionalExpressionAST *) { return true; }
virtual bool visit(ContinueStatementAST *) { return true; }
@@ -181,6 +182,7 @@ public:
virtual bool visit(OperatorFunctionIdAST *) { return true; }
virtual bool visit(ParameterDeclarationAST *) { return true; }
virtual bool visit(ParameterDeclarationClauseAST *) { return true; }
virtual bool visit(PlaceholderTypeSpecifierAST *) { return true; }
virtual bool visit(PointerAST *) { return true; }
virtual bool visit(PointerLiteralAST *) { return true; }
virtual bool visit(PointerToMemberAST *) { return true; }
@@ -198,6 +200,7 @@ public:
virtual bool visit(QualifiedNameAST *) { return true; }
virtual bool visit(RangeBasedForStatementAST *) { return true; }
virtual bool visit(ReferenceAST *) { return true; }
virtual bool visit(RequiresExpressionAST *) { return true; }
virtual bool visit(ReturnStatementAST *) { return true; }
virtual bool visit(SimpleDeclarationAST *) { return true; }
virtual bool visit(SimpleNameAST *) { return true; }
@@ -215,6 +218,7 @@ public:
virtual bool visit(TrailingReturnTypeAST *) { return true; }
virtual bool visit(TranslationUnitAST *) { return true; }
virtual bool visit(TryBlockStatementAST *) { return true; }
virtual bool visit(TypeConstraintAST *) { return true; }
virtual bool visit(TypeConstructorCallAST *) { return true; }
virtual bool visit(TypeIdAST *) { return true; }
virtual bool visit(TypeidExpressionAST *) { return true; }
@@ -250,6 +254,7 @@ public:
virtual void endVisit(CompoundExpressionAST *) {}
virtual void endVisit(CompoundLiteralAST *) {}
virtual void endVisit(CompoundStatementAST *) {}
virtual void endVisit(ConceptDeclarationAST *) {}
virtual void endVisit(ConditionAST *) {}
virtual void endVisit(ConditionalExpressionAST *) {}
virtual void endVisit(ContinueStatementAST *) {}
@@ -335,6 +340,7 @@ public:
virtual void endVisit(OperatorFunctionIdAST *) {}
virtual void endVisit(ParameterDeclarationAST *) {}
virtual void endVisit(ParameterDeclarationClauseAST *) {}
virtual void endVisit(PlaceholderTypeSpecifierAST *) {}
virtual void endVisit(PointerAST *) {}
virtual void endVisit(PointerLiteralAST *) {}
virtual void endVisit(PointerToMemberAST *) {}
@@ -352,6 +358,7 @@ public:
virtual void endVisit(QualifiedNameAST *) {}
virtual void endVisit(RangeBasedForStatementAST *) {}
virtual void endVisit(ReferenceAST *) {}
virtual void endVisit(RequiresExpressionAST *) {}
virtual void endVisit(ReturnStatementAST *) {}
virtual void endVisit(SimpleDeclarationAST *) {}
virtual void endVisit(SimpleNameAST *) {}
@@ -369,6 +376,7 @@ public:
virtual void endVisit(TrailingReturnTypeAST *) {}
virtual void endVisit(TranslationUnitAST *) {}
virtual void endVisit(TryBlockStatementAST *) {}
virtual void endVisit(TypeConstraintAST *) {}
virtual void endVisit(TypeConstructorCallAST *) {}
virtual void endVisit(TypeIdAST *) {}
virtual void endVisit(TypeidExpressionAST *) {}

View File

@@ -146,6 +146,7 @@ class OperatorAST;
class OperatorFunctionIdAST;
class ParameterDeclarationAST;
class ParameterDeclarationClauseAST;
class PlaceholderTypeSpecifierAST;
class PointerAST;
class PointerLiteralAST;
class PointerToMemberAST;
@@ -166,6 +167,7 @@ class QtPropertyDeclarationItemAST;
class QualifiedNameAST;
class RangeBasedForStatementAST;
class ReferenceAST;
class RequiresExpressionAST;
class ReturnStatementAST;
class SimpleDeclarationAST;
class SimpleNameAST;
@@ -178,6 +180,7 @@ class StdAttributeSpecifierAST;
class StringLiteralAST;
class SwitchStatementAST;
class TemplateDeclarationAST;
class ConceptDeclarationAST;
class TemplateIdAST;
class TemplateTypeParameterAST;
class ThisExpressionAST;
@@ -185,6 +188,7 @@ class ThrowExpressionAST;
class TrailingReturnTypeAST;
class TranslationUnitAST;
class TryBlockStatementAST;
class TypeConstraintAST;
class TypeConstructorCallAST;
class TypeIdAST;
class TypeidExpressionAST;

View File

@@ -933,6 +933,11 @@ bool Bind::visit(ParameterDeclarationClauseAST *ast)
return false;
}
bool Bind::visit(RequiresExpressionAST *)
{
return false;
}
void Bind::parameterDeclarationClause(ParameterDeclarationClauseAST *ast, int lparen_token, Function *fun)
{
if (! ast)

View File

@@ -128,6 +128,7 @@ protected:
bool visit(NewTypeIdAST *ast) override;
bool visit(OperatorAST *ast) override;
bool visit(ParameterDeclarationClauseAST *ast) override;
bool visit(RequiresExpressionAST *ast) override;
bool visit(TranslationUnitAST *ast) override;
bool visit(ObjCProtocolRefsAST *ast) override;
bool visit(ObjCMessageArgumentAST *ast) override;

View File

@@ -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,9 +1727,10 @@ 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)) {

View File

@@ -143,6 +143,11 @@ public:
bool parseTemplateArgument(ExpressionAST *&node);
bool parseTemplateArgumentList(ExpressionListAST *&node);
bool parseTemplateDeclaration(DeclarationAST *&node);
bool parseConceptDeclaration(DeclarationAST *&node);
bool parsePlaceholderTypeSpecifier(PlaceholderTypeSpecifierAST *&node);
bool parseTypeConstraint(TypeConstraintAST *&node);
bool parseRequirement();
bool parseRequiresExpression(ExpressionAST *&node);
bool parseTemplateParameter(DeclarationAST *&node);
bool parseTemplateParameterList(DeclarationListAST *&node);
bool parseThrowExpression(ExpressionAST *&node);

View File

@@ -70,6 +70,10 @@ public:
// Get Document
const Document::Ptr document = waitForFileInGlobalSnapshot(filePath);
QVERIFY(document);
if (!document->diagnosticMessages().isEmpty()) {
for (const Document::DiagnosticMessage &m : document->diagnosticMessages())
qDebug().noquote() << m.text();
}
QVERIFY(document->diagnosticMessages().isEmpty());
m_snapshot.insert(document);

View File

@@ -145,6 +145,8 @@ private Q_SLOTS:
void lambdaType_data();
void lambdaType();
void concepts();
};
@@ -293,5 +295,28 @@ void tst_cxx11::lambdaType()
QCOMPARE(oo.prettyType(function->type()), expectedType);
}
void tst_cxx11::concepts()
{
LanguageFeatures features;
features.cxxEnabled = true;
features.cxx11Enabled = features.cxx14Enabled = features.cxx20Enabled = true;
const QString source = R"(
template<typename T> concept IsPointer = requires(T p) { *p; };
template<IsPointer T> void* func(T p) { return p; }
void *func2(IsPointer auto p)
{
return p;
}
)";
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() << errors;
QVERIFY(!hasErrors);
}
QTEST_APPLESS_MAIN(tst_cxx11)
#include "tst_cxx11.moc"