saar.raz updated this revision to Diff 126950.
saar.raz added a comment.
- Fixed indentation problems
Repository:
rC Clang
https://reviews.llvm.org/D41217
Files:
include/clang/AST/DeclTemplate.h
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DeclNodes.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/StmtNodes.td
include/clang/Basic/TemplateKinds.h
include/clang/Parse/Parser.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ASTDumper.cpp
lib/AST/DeclBase.cpp
lib/AST/DeclTemplate.cpp
lib/AST/Expr.cpp
lib/AST/ExprCXX.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/ItaniumMangle.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/CodeGen/CGDecl.cpp
lib/CodeGen/CGExprScalar.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseTemplate.cpp
lib/Sema/SemaExceptionSpec.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaTemplate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriter.cpp
lib/Serialization/ASTWriterDecl.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
test/Parser/cxx-concept-declaration.cpp
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp
Index: tools/libclang/CXCursor.cpp
===================================================================
--- tools/libclang/CXCursor.cpp
+++ tools/libclang/CXCursor.cpp
@@ -231,6 +231,7 @@
case Stmt::TypeTraitExprClass:
case Stmt::CoroutineBodyStmtClass:
case Stmt::CoawaitExprClass:
+ case Stmt::ConceptSpecializationExprClass:
case Stmt::DependentCoawaitExprClass:
case Stmt::CoreturnStmtClass:
case Stmt::CoyieldExprClass:
Index: tools/libclang/CIndex.cpp
===================================================================
--- tools/libclang/CIndex.cpp
+++ tools/libclang/CIndex.cpp
@@ -5951,6 +5951,7 @@
case Decl::PragmaComment:
case Decl::PragmaDetectMismatch:
case Decl::UsingPack:
+ case Decl::Concept:
return C;
// Declaration kinds that don't make any sense here, but are
Index: test/Parser/cxx-concept-declaration.cpp
===================================================================
--- test/Parser/cxx-concept-declaration.cpp
+++ test/Parser/cxx-concept-declaration.cpp
@@ -1,7 +1,38 @@
// Support parsing of concepts
-// Disabled for now.
-// expected-no-diagnostics
-// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-// template<typename T> concept C1 = true;
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+template<typename T> concept C1 = true;
+
+// TODO: Following line should fail.
+template<typename T> concept C1 = true;
+
+template<concept T> concept D1 = true; // expected-error {{expected template parameter}}
+
+struct S1 {
+ template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}}
+};
+
+template<typename A>
+template<typename B>
+concept C4 = true; // expected-error {{extraneous template parameter list in concept definition}}
+
+template<typename T> concept C5 = true; // expected-note {{previous}} expected-note {{previous}}
+int C5; // expected-error {{redefinition}}
+struct C5 {}; // expected-error {{redefinition}}
+
+// TODO: Last of the following two lines should fail.
+struct C6 {};
+template<typename T> concept C6 = true;
+
+// TODO: Add test to prevent explicit specialization, partial specialization
+// and explicit instantiation of concepts.
+
+template<bool x> concept C7 = 2; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C8 = 2 && x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C9 = x || 2 || x; // expected-error {{atomic constraint '2' must be of type 'bool' (found 'int')}}
+template<bool x> concept C10 = 8ull && x || x; // expected-error {{atomic constraint '8ULL' must be of type 'bool' (found 'unsigned long long')}}
+template<typename T> concept C11 = sizeof(T); // expected-error {{atomic constraint 'sizeof(T)' must be of type 'bool' (found 'unsigned long')}}
+template<typename T> concept C12 = T{};
+template<typename T> concept C13 = (bool&&)true;
+template<typename T> concept C14 = (const bool&)true;
Index: test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
===================================================================
--- /dev/null
+++ test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+
+template<typename T> concept C1 = true;
+static_assert(C1<int>);
+
+template<typename T> concept C2 = sizeof(T) == 4;
+static_assert(C2<int>);
+static_assert(!C2<long long int>);
+static_assert(C2<char[4]>);
+static_assert(!C2<char[5]>);
+
+template<typename T> concept C3 = sizeof(*T{}) == 4;
+static_assert(C3<int*>);
+static_assert(!C3<long long int>);
+
+struct A {
+ static constexpr int add(int a, int b) {
+ return a + b;
+ }
+};
+struct B {
+ static int add(int a, int b) {
+ return a + b;
+ }
+};
+template<typename U>
+concept C4 = U::add(1, 2) == 3;
+static_assert(C4<A>);
+static_assert(!C4<B>); // expected-error {{concept specialization 'C4<B>' resulted in a non-constant expression 'B::add(1, 2) == 3'}}
+
+template<typename T, typename U>
+constexpr bool is_same_v = false;
+
+template<typename T>
+constexpr bool is_same_v<T, T> = true;
+
+template<typename T, typename U>
+concept Same = is_same_v<T, U>;
+
+static_assert(Same<int, int>);
+static_assert(Same<int, decltype(1)>);
+static_assert(!Same<int, unsigned int>);
+static_assert(!Same<A, B>);
+static_assert(Same<A, A>);
+
+static_assert(Same<bool, decltype(C1<int>)>);
+static_assert(Same<bool, decltype(C2<int>)>);
+static_assert(Same<bool, decltype(C3<int*>)>);
+static_assert(Same<bool, decltype(C4<A>)>);
+
+template<typename T> concept C5 = T{}; // expected-error {{atomic constraint 'int{}' must be of type 'bool' (found 'int')}}
+constexpr bool x = C5<int>; // expected-note {{in concept specialization 'C5<int>'}}
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1018,6 +1018,7 @@
case Stmt::CUDAKernelCallExprClass:
case Stmt::OpaqueValueExprClass:
case Stmt::AsTypeExprClass:
+ case Stmt::ConceptSpecializationExprClass:
// Fall through.
// Cases we intentionally don't evaluate, since they don't need
Index: lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- lib/Serialization/ASTWriterStmt.cpp
+++ lib/Serialization/ASTWriterStmt.cpp
@@ -344,6 +344,23 @@
Code = serialization::EXPR_DEPENDENT_COAWAIT;
}
+void ASTStmtWriter::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ Record.AddDeclRef(E->getSpecializedConcept());
+ Record.AddSourceLocation(E->getConceptNameLoc());
+ const TemplateArgumentListInfo *TALI = E->getTemplateArgumentListInfo();
+ Record.push_back(TALI->size());
+ Record.AddSourceLocation(TALI->getLAngleLoc());
+ Record.AddSourceLocation(TALI->getRAngleLoc());
+ for (unsigned i = 0; i < TALI->size(); ++i) {
+ Record.AddTemplateArgumentLoc(TALI->getArgumentArray()[i]);
+ }
+ Record.push_back(E->isSatisfied());
+ Code = serialization::EXPR_CONCEPT_SPECIALIZATION;
+}
+
+
void ASTStmtWriter::VisitCapturedStmt(CapturedStmt *S) {
VisitStmt(S);
// NumCaptures
Index: lib/Serialization/ASTWriterDecl.cpp
===================================================================
--- lib/Serialization/ASTWriterDecl.cpp
+++ lib/Serialization/ASTWriterDecl.cpp
@@ -101,6 +101,7 @@
void VisitBindingDecl(BindingDecl *D);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
void VisitTemplateDecl(TemplateDecl *D);
+ void VisitConceptDecl(ConceptDecl *D);
void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -1385,6 +1386,12 @@
Record.AddTemplateParameterList(D->getTemplateParameters());
}
+void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
+ VisitTemplateDecl(D);
+ Record.AddStmt(D->getConstraintExpr());
+ Code = serialization::DECL_CONCEPT;
+}
+
void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
VisitRedeclarable(D);
Index: lib/Serialization/ASTWriter.cpp
===================================================================
--- lib/Serialization/ASTWriter.cpp
+++ lib/Serialization/ASTWriter.cpp
@@ -1277,6 +1277,7 @@
RECORD(DECL_TEMPLATE_TYPE_PARM);
RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
+ RECORD(DECL_CONCEPT);
RECORD(DECL_TYPE_ALIAS_TEMPLATE);
RECORD(DECL_STATIC_ASSERT);
RECORD(DECL_CXX_BASE_SPECIFIERS);
Index: lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- lib/Serialization/ASTReaderStmt.cpp
+++ lib/Serialization/ASTReaderStmt.cpp
@@ -610,6 +610,22 @@
E->setRParenLoc(ReadSourceLocation());
}
+void ASTStmtReader::VisitConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ VisitExpr(E);
+ E->setSpecializedConcept(ReadDeclAs<ConceptDecl>());
+ E->setConceptNameLoc(Record.readSourceLocation());
+
+ TemplateArgumentListInfo ArgInfo;
+ unsigned NumTemplateArgs = Record.readInt();
+ ArgInfo.setLAngleLoc(Record.readSourceLocation());
+ ArgInfo.setRAngleLoc(Record.readSourceLocation());
+ for (unsigned i = 0; i != NumTemplateArgs; ++i)
+ ArgInfo.addArgument(Record.readTemplateArgumentLoc());
+ E->setTemplateArguments(/*Sema=*/nullptr, &ArgInfo);
+ E->setSatisfied(Record.readInt() == 1);
+}
+
void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) {
VisitExpr(E);
E->setLHS(Record.readSubExpr());
@@ -4033,6 +4049,9 @@
S = new (Context) DependentCoawaitExpr(Empty);
break;
+ case EXPR_CONCEPT_SPECIALIZATION:
+ S = new (Context) ConceptSpecializationExpr(Context);
+ break;
}
// We hit a STMT_STOP, so we're done with this expression.
Index: lib/Serialization/ASTReaderDecl.cpp
===================================================================
--- lib/Serialization/ASTReaderDecl.cpp
+++ lib/Serialization/ASTReaderDecl.cpp
@@ -337,6 +337,7 @@
void VisitBindingDecl(BindingDecl *BD);
void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
DeclID VisitTemplateDecl(TemplateDecl *D);
+ void VisitConceptDecl(ConceptDecl *D);
RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
void VisitClassTemplateDecl(ClassTemplateDecl *D);
void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
@@ -1970,6 +1971,11 @@
return PatternID;
}
+void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
+ VisitTemplateDecl(D);
+ D->setConstraintExpr(Record.readExpr());
+}
+
ASTDeclReader::RedeclarableResult
ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
RedeclarableResult Redecl = VisitRedeclarable(D);
@@ -3522,6 +3528,9 @@
case DECL_TYPE_ALIAS_TEMPLATE:
D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
break;
+ case DECL_CONCEPT:
+ D = ConceptDecl::CreateDeserialized(Context, ID);
+ break;
case DECL_STATIC_ASSERT:
D = StaticAssertDecl::CreateDeserialized(Context, ID);
break;
Index: lib/Serialization/ASTCommon.cpp
===================================================================
--- lib/Serialization/ASTCommon.cpp
+++ lib/Serialization/ASTCommon.cpp
@@ -313,6 +313,7 @@
case Decl::BuiltinTemplate:
case Decl::Decomposition:
case Decl::Binding:
+ case Decl::Concept:
return false;
// These indirectly derive from Redeclarable<T> but are not actually
Index: lib/Sema/TreeTransform.h
===================================================================
--- lib/Sema/TreeTransform.h
+++ lib/Sema/TreeTransform.h
@@ -2940,7 +2940,22 @@
RParenLoc, Length, PartialArgs);
}
- /// \brief Build a new Objective-C boxed expression.
+ /// \brief Build a new concept specialization expression.
+ ///
+ /// By default, performs semantic analysis to build the new expression.
+ /// Subclasses may override this routine to provide different behavior.
+ ExprResult RebuildConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+ ConceptDecl *CTD,
+ TemplateArgumentListInfo *TALI) {
+ ExprResult Result
+ = getSema().CreateConceptSpecializationExpr(ConceptNameLoc, CTD,
+ TALI);
+ if (Result.isInvalid())
+ return ExprError();
+ return Result;
+ }
+
+ /// \brief Build a new Objective-C boxed expression.
///
/// By default, performs semantic analysis to build the new expression.
/// Subclasses may override this routine to provide different behavior.
@@ -10616,6 +10631,23 @@
E->getLocEnd());
}
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformConceptSpecializationExpr(
+ ConceptSpecializationExpr *E) {
+ const TemplateArgumentListInfo *Old = E->getTemplateArgumentListInfo();
+ TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc());
+ if (getDerived().TransformTemplateArguments(Old->getArgumentArray(),
+ Old->size(), TransArgs)) {
+ return ExprError();
+ }
+
+ return getDerived().RebuildConceptSpecializationExpr(E->getConceptNameLoc(),
+ E->getSpecializedConcept(),
+ &TransArgs);
+}
+
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformArrayTypeTraitExpr(ArrayTypeTraitExpr *E) {
Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3095,6 +3095,11 @@
return nullptr;
}
+Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
+ llvm_unreachable("Concept definitions cannot reside inside a template");
+ return nullptr;
+}
+
Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
llvm_unreachable("Unexpected decl");
}
Index: lib/Sema/SemaTemplate.cpp
===================================================================
--- lib/Sema/SemaTemplate.cpp
+++ lib/Sema/SemaTemplate.cpp
@@ -232,9 +232,11 @@
} else {
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
- isa<BuiltinTemplateDecl>(TD));
+ isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
TemplateKind =
- isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
+ isa<VarTemplateDecl>(TD) ? TNK_Var_template :
+ isa<ConceptDecl>(TD) ? TNK_Concept_template :
+ TNK_Type_template;
}
}
@@ -2930,7 +2932,8 @@
TemplateDecl *Template = Name.getAsTemplateDecl();
if (!Template || isa<FunctionTemplateDecl>(Template) ||
- isa<VarTemplateDecl>(Template)) {
+ isa<VarTemplateDecl>(Template) ||
+ isa<ConceptDecl>(Template)) {
// We might have a substituted template template parameter pack. If so,
// build a template specialization type for it.
if (Name.getAsSubstTemplateTemplateParmPack())
@@ -3884,6 +3887,25 @@
/*FoundD=*/nullptr, TemplateArgs);
}
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ ConceptDecl *Template,
+ SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(Template && "A concept template id without template?");
+
+ // Check that the template argument list is well-formed for this template.
+ SmallVector<TemplateArgument, 4> Converted;
+ if (CheckTemplateArgumentList(Template, TemplateLoc,
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs), false,
+ Converted, /*UpdateArgsWithConversions=*/false))
+ return ExprError();
+
+ return CreateConceptSpecializationExpr(NameInfo.getLoc(), Template,
+ TemplateArgs);
+}
+
ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -3905,14 +3927,21 @@
// In C++1y, check variable template ids.
bool InstantiationDependent;
- if (R.getAsSingle<VarTemplateDecl>() &&
- !TemplateSpecializationType::anyDependentTemplateArguments(
- *TemplateArgs, InstantiationDependent)) {
+ bool DependentArguments =
+ TemplateSpecializationType::anyDependentTemplateArguments(
+ *TemplateArgs, InstantiationDependent);
+ if (R.getAsSingle<VarTemplateDecl>() && !DependentArguments) {
return CheckVarTemplateId(SS, R.getLookupNameInfo(),
R.getAsSingle<VarTemplateDecl>(),
TemplateKWLoc, TemplateArgs);
}
+ if (R.getAsSingle<ConceptDecl>() && !DependentArguments) {
+ return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
+ R.getAsSingle<ConceptDecl>(),
+ TemplateKWLoc, TemplateArgs);
+ }
+
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
@@ -7663,6 +7692,44 @@
return NewDecl;
}
+#include <iostream>
+using namespace std;
+Decl *Sema::ActOnConceptDefinition(Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ IdentifierInfo *Name, SourceLocation L,
+ Expr *ConstraintExpr) {
+ DeclContext *DC = CurContext;
+
+ if (!DC->isFileContext()) {
+ Diag(L,
+ diag::err_concept_decls_may_only_appear_in_global_namespace_scope);
+ return nullptr;
+ }
+
+ if (TemplateParameterLists.size() != 1) {
+ Diag(L, diag::err_concept_extra_headers);
+ return nullptr;
+ }
+
+ ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, L, Name,
+ TemplateParameterLists[0],
+ ConstraintExpr);
+ if (!NewDecl)
+ return nullptr;
+
+ if (NewDecl->getAssociatedConstraints()) {
+ // C++2a [temp.concept]p4:
+ // A concept shall not have associated constraints.
+ // TODO: Make a test once we have actual associated constraints.
+ Diag(L, diag::err_concept_no_associated_constraints);
+ NewDecl->setInvalidDecl();
+ }
+
+ ActOnDocumentableDecl(NewDecl);
+ CurContext->addDecl(NewDecl);
+ return NewDecl;
+}
+
/// \brief Strips various properties off an implicit instantiation
/// that has just been explicitly specialized.
static void StripImplicitInstantiation(NamedDecl *D) {
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -7678,3 +7678,38 @@
return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo);
}
+
+
+ExprResult Sema::CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+ ConceptDecl *CTD,
+ const TemplateArgumentListInfo *TALI) {
+ return new (Context) ConceptSpecializationExpr(Context, *this, ConceptNameLoc,
+ CTD, TALI);
+}
+
+bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) {
+ // C++2a [temp.constr.atomic]p1
+ // ..E shall be a constant expression of type bool.
+
+ if (BinaryOperator* BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) {
+ if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) {
+ return CheckConstraintExpression(BinOp->getLHS())
+ && CheckConstraintExpression(BinOp->getRHS());
+ }
+ }
+ // An atomic constraint!
+ if (!ConstraintExpression->isTypeDependent()) {
+ if (ConstraintExpression->getType().getLocalUnqualifiedType()
+ != Context.BoolTy) {
+ Diag(ConstraintExpression->getExprLoc(),
+ diag::err_non_bool_atomic_constraint)
+ << ConstraintExpression << ConstraintExpression->getType();
+ return false;
+ } else if (ImplicitCastExpr *E =
+ dyn_cast<ImplicitCastExpr>(ConstraintExpression)) {
+ // This will catch expressions such as '2 && true'
+ return CheckConstraintExpression(E->getSubExpr());
+ }
+ }
+ return true;
+}
\ No newline at end of file
Index: lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- lib/Sema/SemaExceptionSpec.cpp
+++ lib/Sema/SemaExceptionSpec.cpp
@@ -1271,6 +1271,7 @@
case Expr::PredefinedExprClass:
case Expr::SizeOfPackExprClass:
case Expr::StringLiteralClass:
+ case Expr::ConceptSpecializationExprClass:
// These expressions can never throw.
return CT_Cannot;
Index: lib/Parse/ParseTemplate.cpp
===================================================================
--- lib/Parse/ParseTemplate.cpp
+++ lib/Parse/ParseTemplate.cpp
@@ -54,6 +54,15 @@
/// template-declaration: [C++ temp]
/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
///
+/// template-declaration: [C++2a]
+/// template-head declaration
+/// template-head concept-definition
+///
+/// TODO: requires-clause
+/// template-head: [C++2a]
+/// 'export'[opt] 'template' '<' template-parameter-list '>'
+/// requires-clause[opt]
+///
/// explicit-specialization: [ C++ temp.expl.spec]
/// 'template' '<' '>' declaration
Decl *
@@ -149,12 +158,20 @@
ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
// Parse the actual template declaration.
- return ParseSingleDeclarationAfterTemplate(Context,
- ParsedTemplateInfo(&ParamLists,
- isSpecialization,
- LastParamListWasEmpty),
- ParsingTemplateParams,
- DeclEnd, AS, AccessAttrs);
+ if (!TryConsumeToken(tok::kw_concept))
+ return ParseSingleDeclarationAfterTemplate(Context,
+ ParsedTemplateInfo(&ParamLists,
+ isSpecialization,
+ LastParamListWasEmpty),
+ ParsingTemplateParams,
+ DeclEnd, AS, AccessAttrs);
+
+ return ParseConceptDefinition(Context,
+ ParsedTemplateInfo(&ParamLists,
+ isSpecialization,
+ LastParamListWasEmpty),
+ ParsingTemplateParams,
+ DeclEnd, AS, AccessAttrs);
}
/// \brief Parse a single declaration that declares a template,
@@ -321,6 +338,51 @@
return ThisDecl;
}
+/// \brief Parse a single declaration that declares a concept.
+///
+/// \param DeclEnd will receive the source location of the last token
+/// within this declaration.
+///
+/// \param AS the access specifier associated with this
+/// declaration. Will be AS_none for namespace-scope declarations.
+///
+/// \returns the new declaration.
+Decl *
+Parser::ParseConceptDefinition(unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ ParsingDeclRAIIObject &DiagsFromTParams,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs) {
+ assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate &&
+ "Template information required");
+
+ if (!Tok.is(tok::identifier)) {
+ Diag(Tok.getLocation(), diag::err_expected) << tok::identifier;
+ return nullptr;
+ }
+
+ IdentifierInfo *Id = Tok.getIdentifierInfo();
+ SourceLocation IdLoc = ConsumeToken();
+
+ if (!TryConsumeToken(tok::equal)) {
+ Diag(Tok.getLocation(), diag::err_expected) << "equal";
+ return nullptr;
+ }
+
+ ExprResult ConstraintExprResult = ParseConstraintExpression();
+ if (ConstraintExprResult.isInvalid()) {
+ // ParseConstraintExpression will have given a sufficient diagnostic.
+ return nullptr;
+ }
+
+ ExpectAndConsumeSemi(diag::err_expected_semi_declaration);
+ Expr *ConstraintExpr = ConstraintExprResult.get();
+ return Actions.ActOnConceptDefinition(getCurScope(),
+ *TemplateInfo.TemplateParams,
+ Id, IdLoc, ConstraintExpr);
+}
+
/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
/// angle brackets. Depth is the depth of this template-parameter-list, which
/// is the number of template headers directly enclosing this template header.
@@ -1024,8 +1086,8 @@
? OO_None
: TemplateName.OperatorFunctionId.Operator;
- TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
- SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
+ TemplateIdAnnotation *TemplateId = TemplateIdAnnotation::Create(
+ SS, TemplateKWLoc, TemplateNameLoc, TemplateII, OpKind, Template, TNK,
LAngleLoc, RAngleLoc, TemplateArgs, TemplateIds);
Tok.setAnnotationValue(TemplateId);
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp
+++ lib/Parse/ParseExpr.cpp
@@ -216,18 +216,14 @@
/// \brief Parse a constraint-expression.
///
/// \verbatim
-/// constraint-expression: [Concepts TS temp.constr.decl p1]
+/// constraint-expression: C++2a[temp.constr.decl]p1
/// logical-or-expression
/// \endverbatim
ExprResult Parser::ParseConstraintExpression() {
- // FIXME: this may erroneously consume a function-body as the braced
- // initializer list of a compound literal
- //
- // FIXME: this may erroneously consume a parenthesized rvalue reference
- // declarator as a parenthesized address-of-label expression
- ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false));
- ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr));
-
+ ExprResult Res(ParseExpression());
+ if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) {
+ return ExprError();
+ }
return Res;
}
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -602,6 +602,10 @@
return llvm::ConstantInt::get(ConvertType(E->getType()), E->getValue());
}
+ Value *VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E) {
+ return Builder.getInt1(E->isSatisfied());
+ }
+
Value *VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) {
return llvm::ConstantInt::get(Builder.getInt32Ty(), E->getValue());
}
Index: lib/CodeGen/CGDecl.cpp
===================================================================
--- lib/CodeGen/CGDecl.cpp
+++ lib/CodeGen/CGDecl.cpp
@@ -105,6 +105,7 @@
case Decl::OMPThreadPrivate:
case Decl::OMPCapturedExpr:
case Decl::Empty:
+ case Decl::Concept:
// None of these decls require codegen support.
return;
Index: lib/AST/StmtProfile.cpp
===================================================================
--- lib/AST/StmtProfile.cpp
+++ lib/AST/StmtProfile.cpp
@@ -1233,6 +1233,14 @@
ID.AddInteger(S->getOp());
}
+void StmtProfiler::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *S) {
+ VisitExpr(S);
+ VisitDecl(S->getSpecializedConcept());
+ VisitTemplateArguments(S->getTemplateArgumentListInfo()->getArgumentArray(),
+ S->getTemplateArgumentListInfo()->size());
+}
+
static Stmt::StmtClass DecodeOperatorCall(const CXXOperatorCallExpr *S,
UnaryOperatorKind &UnaryOp,
BinaryOperatorKind &BinaryOp) {
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp
+++ lib/AST/StmtPrinter.cpp
@@ -2549,6 +2549,12 @@
OS << ")";
}
+void StmtPrinter::VisitConceptSpecializationExpr(ConceptSpecializationExpr *E) {
+ OS << E->getSpecializedConcept()->getName();
+ printTemplateArgumentList(OS, E->getTemplateArgumentListInfo()->arguments(),
+ Policy);
+}
+
// C++ Coroutines TS
void StmtPrinter::VisitCoroutineBodyStmt(CoroutineBodyStmt *S) {
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -3464,6 +3464,7 @@
case Expr::ConvertVectorExprClass:
case Expr::StmtExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::ConceptSpecializationExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::VAArgExprClass:
Index: lib/AST/ExprConstant.cpp
===================================================================
--- lib/AST/ExprConstant.cpp
+++ lib/AST/ExprConstant.cpp
@@ -7074,6 +7074,7 @@
bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
+ bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);
// FIXME: Missing: array subscript of vector, member of vector
};
} // end anonymous namespace
@@ -9079,6 +9080,15 @@
return Success(E->getValue(), E);
}
+bool IntExprEvaluator::VisitConceptSpecializationExpr(
+ const ConceptSpecializationExpr *E) {
+ if (E->isValueDependent()) {
+ return Error(E);
+ }
+ return Success(E->isSatisfied(), E);
+}
+
+
//===----------------------------------------------------------------------===//
// Float Evaluation
//===----------------------------------------------------------------------===//
@@ -10368,6 +10378,7 @@
case Expr::CXXBoolLiteralExprClass:
case Expr::CXXScalarValueInitExprClass:
case Expr::TypeTraitExprClass:
+ case Expr::ConceptSpecializationExprClass:
case Expr::ArrayTypeTraitExprClass:
case Expr::ExpressionTraitExprClass:
case Expr::CXXNoexceptExprClass:
Index: lib/AST/ExprClassification.cpp
===================================================================
--- lib/AST/ExprClassification.cpp
+++ lib/AST/ExprClassification.cpp
@@ -190,6 +190,7 @@
case Expr::ArrayInitIndexExprClass:
case Expr::NoInitExprClass:
case Expr::DesignatedInitUpdateExprClass:
+ case Expr::ConceptSpecializationExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp
+++ lib/AST/ExprCXX.cpp
@@ -29,6 +29,9 @@
#include "clang/Basic/OperatorKinds.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
+#include "clang/Sema/Template.h"
+#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/Sema.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
@@ -1433,3 +1436,97 @@
}
void ArrayTypeTraitExpr::anchor() {}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, Sema &S,
+ SourceLocation ConceptNameLoc,
+ ConceptDecl *CD,
+ const TemplateArgumentListInfo *TALI)
+ : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary,
+ /*TypeDependent=*/false,
+ // All the flags below are set in setTemplateArguments.
+ /*ValueDependent=*/false, /*InstantiationDependent=*/false,
+ /*ContainsUnexpandedParameterPacks=*/false), SpecializedConcept(CD),
+ ConceptNameLoc(ConceptNameLoc) {
+ setTemplateArguments(&S, TALI);
+}
+
+ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C)
+ : Expr(ConceptSpecializationExprClass, EmptyShell()) { }
+
+bool ConceptSpecializationExpr::evaluate(Sema &S)
+{
+ llvm::SmallVector<TemplateArgument, 4> Converted;
+ if (S.CheckTemplateArgumentList(SpecializedConcept,
+ SpecializedConcept->getLocStart(),
+ TemplateArgInfo,
+ /*PartialTemplateArgs=*/false, Converted,
+ /*UpdateArgsWithConversion=*/false)) {
+ // We converted these arguments back in CheckConceptTemplateId, this should
+ // work.
+ return true;
+ }
+ EnterExpressionEvaluationContext ConstantEvaluated(
+ S, Sema::ExpressionEvaluationContext::ConstantEvaluated);
+
+
+ MultiLevelTemplateArgumentList MLTAL;
+ MLTAL.addOuterTemplateArguments(Converted);
+
+ ExprResult E;
+ {
+ // We do not want error diagnostics escaping here.
+ Sema::SFINAETrap Trap(S);
+ E = S.SubstExpr(SpecializedConcept->getConstraintExpr(), MLTAL);
+ if (E.isInvalid() || Trap.hasErrorOccurred()) {
+ // C++2a [temp.constr.atomic]p1
+ // ...If substitution results in an invalid type or expression, the
+ // constraint is not satisfied.
+ IsSatisfied = false;
+ return true;
+ }
+ }
+
+ if (!S.CheckConstraintExpression(E.get())) {
+ S.Diag(getLocStart(), diag::note_in_concept_specialization) << this;
+ return true;
+ }
+
+ bool Satisfied = false;
+ if (!E.get()->EvaluateAsBooleanCondition(Satisfied, S.Context)) {
+ // C++2a [temp.constr.atomic]p1
+ // ...E shall be a constant expression of type bool.
+ S.Diag(getLocStart(), diag::err_concept_non_constant_constraint_expression)
+ << this << E.get();
+ return true;
+ }
+ IsSatisfied = Satisfied;
+ return false;
+}
+
+bool ConceptSpecializationExpr::setTemplateArguments(Sema *S,
+ const TemplateArgumentListInfo *TALI){
+ bool IsDependent = false;
+ bool ContainsUnexpandedParameterPack = false;
+ TemplateArgInfo = *TALI;
+ for (const TemplateArgumentLoc& LocInfo : TALI->arguments()) {
+ if (LocInfo.getArgument().isInstantiationDependent()) {
+ IsDependent = true;
+ if (ContainsUnexpandedParameterPack) {
+ break;
+ }
+ }
+ if (LocInfo.getArgument().containsUnexpandedParameterPack()) {
+ ContainsUnexpandedParameterPack = true;
+ if (IsDependent) {
+ break;
+ }
+ }
+ }
+ setValueDependent(IsDependent);
+ setInstantiationDependent(IsDependent);
+ setContainsUnexpandedParameterPack(ContainsUnexpandedParameterPack);
+ if (!IsDependent && S) {
+ return evaluate(*S);
+ }
+ return false;
+}
\ No newline at end of file
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp
+++ lib/AST/Expr.cpp
@@ -2998,6 +2998,7 @@
case ObjCAvailabilityCheckExprClass:
case CXXUuidofExprClass:
case OpaqueValueExprClass:
+ case ConceptSpecializationExprClass:
// These never have a side-effect.
return false;
Index: lib/AST/DeclTemplate.cpp
===================================================================
--- lib/AST/DeclTemplate.cpp
+++ lib/AST/DeclTemplate.cpp
@@ -798,6 +798,27 @@
}
}
+//===----------------------------------------------------------------------===//
+// ConceptDecl Implementation
+//===----------------------------------------------------------------------===//
+ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr) {
+ // TODO: Do we need this?
+ // AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
+ return new (C, DC) ConceptDecl(DC, L, Name, Params, ConstraintExpr);
+}
+
+ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
+ unsigned ID) {
+ ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(),
+ DeclarationName(),
+ nullptr, nullptr);
+
+ return Result;
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplatePartialSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -768,6 +768,9 @@
case OMPDeclareReduction:
return IDNS_OMPReduction;
+ case Concept:
+ return IDNS_Ordinary | IDNS_Tag;
+
// Never have names.
case Friend:
case FriendTemplate:
Index: lib/AST/ASTDumper.cpp
===================================================================
--- lib/AST/ASTDumper.cpp
+++ lib/AST/ASTDumper.cpp
@@ -458,6 +458,7 @@
bool DumpRefOnly);
template<typename TemplateDecl>
void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);
+ void VisitConceptDecl(const ConceptDecl *D);
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
void VisitClassTemplateDecl(const ClassTemplateDecl *D);
void VisitClassTemplateSpecializationDecl(
@@ -1570,6 +1571,12 @@
!D->isCanonicalDecl());
}
+void ASTDumper::VisitConceptDecl(const ConceptDecl *D) {
+ dumpName(D);
+ dumpTemplateParameters(D->getTemplateParameters());
+ dumpStmt(D->getConstraintExpr());
+}
+
void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
// FIXME: We don't add a declaration of a function template specialization
// to its context when it's explicitly instantiated, so dump explicit
Index: include/clang/Serialization/ASTBitCodes.h
===================================================================
--- include/clang/Serialization/ASTBitCodes.h
+++ include/clang/Serialization/ASTBitCodes.h
@@ -1386,6 +1386,9 @@
/// \brief A TypeAliasTemplateDecl record.
DECL_TYPE_ALIAS_TEMPLATE,
+ /// \brief A ConceptDecl record.
+ DECL_CONCEPT,
+
/// \brief A StaticAssertDecl record.
DECL_STATIC_ASSERT,
@@ -1786,6 +1789,7 @@
EXPR_FUNCTION_PARM_PACK, // FunctionParmPackExpr
EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
EXPR_CXX_FOLD, // CXXFoldExpr
+ EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
// CUDA
EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -5572,7 +5572,15 @@
CXXConversionDecl *Conv,
Expr *Src);
- // ParseObjCStringLiteral - Parse Objective-C string literals.
+ ExprResult CreateConceptSpecializationExpr(SourceLocation ConceptNameLoc,
+ ConceptDecl *CTD,
+ const TemplateArgumentListInfo *TALI);
+
+ /// Check whether the given expression is a valid constraint expression.
+ /// A diagnostic is emmited if it is not, and false is returned.
+ bool CheckConstraintExpression(Expr *CE);
+
+ // ParseObjCStringLiteral - Parse Objective-C string literals.
ExprResult ParseObjCStringLiteral(SourceLocation *AtLocs,
ArrayRef<Expr *> Strings);
@@ -6187,6 +6195,13 @@
SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs);
+ ExprResult
+ CheckConceptTemplateId(const CXXScopeSpec &SS,
+ const DeclarationNameInfo &NameInfo,
+ ConceptDecl *Template,
+ SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
+
ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
LookupResult &R,
@@ -6466,6 +6481,13 @@
const TemplateArgument *Args,
unsigned NumArgs);
+ // Concepts
+ Decl *ActOnConceptDefinition(
+ Scope *S,
+ MultiTemplateParamsArg TemplateParameterLists,
+ IdentifierInfo *Name, SourceLocation L,
+ Expr *ConstraintExpr);
+
//===--------------------------------------------------------------------===//
// C++ Variadic Templates (C++0x [temp.variadic])
//===--------------------------------------------------------------------===//
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -2784,6 +2784,14 @@
SourceLocation TemplateLoc,
SourceLocation &DeclEnd,
AccessSpecifier AS = AS_none);
+ // C++2a: Template, concept definition [temp]
+ Decl *
+ ParseConceptDefinition(unsigned Context,
+ const ParsedTemplateInfo &TemplateInfo,
+ ParsingDeclRAIIObject &DiagsFromTParams,
+ SourceLocation &DeclEnd,
+ AccessSpecifier AS,
+ AttributeList *AccessAttrs);
//===--------------------------------------------------------------------===//
// Modules
Index: include/clang/Basic/TemplateKinds.h
===================================================================
--- include/clang/Basic/TemplateKinds.h
+++ include/clang/Basic/TemplateKinds.h
@@ -43,10 +43,9 @@
/// whether the template name is assumed to refer to a type template or a
/// function template depends on the context in which the template
/// name occurs.
- TNK_Dependent_template_name
+ TNK_Dependent_template_name,
+ TNK_Concept_template
};
}
#endif
-
-
Index: include/clang/Basic/StmtNodes.td
===================================================================
--- include/clang/Basic/StmtNodes.td
+++ include/clang/Basic/StmtNodes.td
@@ -153,6 +153,9 @@
def DependentCoawaitExpr : DStmt<Expr>;
def CoyieldExpr : DStmt<CoroutineSuspendExpr>;
+// C++2a Concepts expressions
+def ConceptSpecializationExpr : DStmt<Expr>;
+
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
def ObjCBoxedExpr : DStmt<Expr>;
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -2368,7 +2368,7 @@
def note_private_extern : Note<
"use __attribute__((visibility(\"hidden\"))) attribute instead">;
-// C++ Concepts TS
+// C++ Concepts
def err_concept_wrong_decl_kind : Error<
"'concept' can only appear on the definition of a function template or variable template">;
def err_concept_decls_may_only_appear_in_namespace_scope : Error<
@@ -2394,6 +2394,18 @@
def err_concept_specialized : Error<
"%select{function|variable}0 concept cannot be "
"%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
+def err_concept_decls_may_only_appear_in_global_namespace_scope : Error<
+ "concept declarations may only appear in global or namespace scope">;
+def err_concept_extra_headers : Error<
+ "extraneous template parameter list in concept definition">;
+def err_concept_no_associated_constraints : Error<
+ "concept may not have associated constraints">;
+def err_concept_non_constant_constraint_expression : Error<
+ "concept specialization '%0' resulted in a non-constant expression '%1'.">;
+def err_non_bool_atomic_constraint : Error<
+ "atomic constraint '%0' must be of type 'bool' (found %1)">;
+def note_in_concept_specialization : Note<
+ "in concept specialization '%0'">;
def err_template_different_associated_constraints : Error<
"associated constraints differ in template redeclaration">;
Index: include/clang/Basic/DeclNodes.td
===================================================================
--- include/clang/Basic/DeclNodes.td
+++ include/clang/Basic/DeclNodes.td
@@ -69,6 +69,7 @@
def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
def TemplateTemplateParm : DDecl<Template>;
def BuiltinTemplate : DDecl<Template>;
+ def Concept : DDecl<Template>;
def Using : DDecl<Named>;
def UsingPack : DDecl<Named>;
def UsingShadow : DDecl<Named>;
Index: include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- include/clang/AST/RecursiveASTVisitor.h
+++ include/clang/AST/RecursiveASTVisitor.h
@@ -1722,6 +1722,8 @@
DEF_TRAVERSE_TMPL_DECL(Var)
DEF_TRAVERSE_TMPL_DECL(Function)
+DEF_TRAVERSE_DECL(ConceptDecl, {})
+
DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
// D is the "T" in something like
// template <template <typename> class T> class container { };
@@ -2583,6 +2585,12 @@
}
})
+DEF_TRAVERSE_STMT(ConceptSpecializationExpr, {
+ TRY_TO(TraverseTemplateArgumentLocsHelper(
+ S->getTemplateArgumentListInfo()->getArgumentArray(),
+ S->getTemplateArgumentListInfo()->size()));
+})
+
// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, {})
DEF_TRAVERSE_STMT(CharacterLiteral, {})
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h
+++ include/clang/AST/ExprCXX.h
@@ -57,6 +57,8 @@
class LambdaCapture;
class NonTypeTemplateParmDecl;
class TemplateParameterList;
+class ConceptDecl;
+class Sema;
//===--------------------------------------------------------------------===//
// C++ Expressions.
@@ -4407,6 +4409,96 @@
}
};
+/// \brief Represents the specialization of a concept - evaluates to a prvalue
+/// of type bool.
+///
+/// According to C++2a [expr.prim.id]p3 an id-expression that denotes the
+/// specialization of a concepts results in a prvalue of type bool.
+class ConceptSpecializationExpr final : public Expr {
+protected:
+ /// \brief The concept specialization this represents.
+ ConceptDecl *SpecializedConcept;
+
+ /// \brief The template argument list used to specialize the concept.
+ TemplateArgumentList *TemplateArgs;
+ TemplateArgumentListInfo TemplateArgInfo;
+
+ /// \brief The location of the concept name in the expression.
+ SourceLocation ConceptNameLoc;
+
+ /// \brief Whether or not the concept with the given arguments was satisfied
+ /// when the expression was created. If any of the template arguments are
+ /// dependent (this expr would then be isValueDependent()), this is to be
+ /// ignored.
+ bool IsSatisfied : 1;
+
+ /// \brief Evaluates this concept specialization to determine whether or not
+ /// the concept is satisfied. Returns true if an error occured and the concept
+ /// could not be checked for satisfaction.
+ bool evaluate(Sema &S);
+
+public:
+ ConceptSpecializationExpr(ASTContext &C, Sema &S,
+ SourceLocation ConceptNameLoc, ConceptDecl *CD,
+ const TemplateArgumentListInfo *TALI);
+
+ ConceptSpecializationExpr(ASTContext &C);
+
+ ConceptDecl *getSpecializedConcept() {
+ return SpecializedConcept;
+ }
+ const ConceptDecl *getSpecializedConcept() const {
+ return SpecializedConcept;
+ }
+ void setSpecializedConcept(ConceptDecl *C) {
+ SpecializedConcept = C;
+ }
+
+ const TemplateArgumentList *getTemplateArguments() const {
+ return TemplateArgs;
+ }
+ const TemplateArgumentListInfo *getTemplateArgumentListInfo() const {
+ return &TemplateArgInfo;
+ }
+
+ /// \brief Set new template arguments for this concept specialization. Returns
+ /// true if an error occured (the template arguments do not match the concept,
+ /// probably)
+ bool setTemplateArguments(Sema *S, const TemplateArgumentListInfo *TALI);
+
+ /// \brief Whether or not the concept with the given arguments was satisfied
+ /// when the expression was created. This method assumes that the expression
+ /// is not dependent!
+ bool isSatisfied() const {
+ assert(!isValueDependent()
+ && "isSatisfied called on a dependent ConceptSpecializationExpr");
+ return IsSatisfied;
+ }
+
+ void setSatisfied(bool Satisfied) {
+ IsSatisfied = Satisfied;
+ }
+
+ SourceLocation getConceptNameLoc() const { return ConceptNameLoc; }
+ void setConceptNameLoc(SourceLocation Loc) {
+ ConceptNameLoc = Loc;
+ }
+
+ static bool classof(const Stmt *T) {
+ return T->getStmtClass() == ConceptSpecializationExprClass;
+ }
+
+ SourceLocation getLocStart() const LLVM_READONLY { return ConceptNameLoc; }
+ SourceLocation getLocEnd() const LLVM_READONLY {
+ return TemplateArgInfo.getRAngleLoc();
+ }
+
+ // Iterators
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+};
+
} // namespace clang
#endif // LLVM_CLANG_AST_EXPRCXX_H
Index: include/clang/AST/DeclTemplate.h
===================================================================
--- include/clang/AST/DeclTemplate.h
+++ include/clang/AST/DeclTemplate.h
@@ -3032,6 +3032,46 @@
static bool classofKind(Kind K) { return K == VarTemplate; }
};
+// \brief Definition of concept, not just declaration actually.
+class ConceptDecl : public TemplateDecl {
+protected:
+ Expr *ConstraintExpr;
+
+ ConceptDecl(DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr)
+ : TemplateDecl(nullptr, Concept, DC, L, Name, Params),
+ ConstraintExpr(ConstraintExpr) {};
+public:
+ static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, DeclarationName Name,
+ TemplateParameterList *Params,
+ Expr *ConstraintExpr);
+ static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+ Expr *getConstraintExpr() const {
+ return ConstraintExpr;
+ }
+
+ void setConstraintExpr(Expr *CE) {
+ ConstraintExpr = CE;
+ }
+
+
+ SourceRange getSourceRange() const override LLVM_READONLY {
+ return SourceRange(getLocation(), getConstraintExpr()->getLocEnd());
+ }
+
+ // Implement isa/cast/dyncast/etc.
+ static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+ static bool classofKind(Kind K) { return K == Concept; }
+
+ friend class ASTReader;
+ friend class ASTDeclReader;
+ friend class ASTDeclWriter;
+};
+
inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
if (auto *PD = P.dyn_cast<TemplateTypeParmDecl*>())
return PD;
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits