changyu updated this revision to Diff 124319. changyu added a comment. - Fixed indent issues. - Moved TODO on boolean atomic constraints to ActOnConceptDefinition where we are currently checking for boolean constraint expression
https://reviews.llvm.org/D40381 Files: include/clang/AST/DeclTemplate.h include/clang/AST/RecursiveASTVisitor.h include/clang/Basic/DeclNodes.td include/clang/Basic/DiagnosticSemaKinds.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/CodeGen/CGDecl.cpp lib/Parse/ParseTemplate.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Serialization/ASTCommon.cpp lib/Serialization/ASTReaderDecl.cpp lib/Serialization/ASTWriter.cpp lib/Serialization/ASTWriterDecl.cpp test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp test/Parser/cxx-concept-declaration.cpp tools/libclang/CIndex.cpp
Index: tools/libclang/CIndex.cpp =================================================================== --- tools/libclang/CIndex.cpp +++ tools/libclang/CIndex.cpp @@ -5906,6 +5906,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,31 @@ // 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}} + +template<typename T> concept C2 = 0.f; // expected-error {{constraint expression must be 'bool'}} + +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. 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,5 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +// expected-no-diagnostics + +template<typename T> concept C = true; +static_assert(C<int>); 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/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); @@ -3521,6 +3527,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/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,18 @@ /*FoundD=*/nullptr, TemplateArgs); } +ExprResult +Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + // TODO: Do more stuff here, caller expects constraint + // expression to be returned. Works for non-dependent bool + // constraint expressions right now. + return Template->getConstraintExpr(); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -3905,14 +3920,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 +7685,57 @@ 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 (!ConstraintExpr->isTypeDependent() && + ConstraintExpr->getType() != Context.BoolTy) { + // C++2a [temp.constr.atomic]p3: + // E shall be a constant expression of type bool. + // TODO: Do this check for individual atomic constraints + // and not the constraint expression. Probably should do it in + // ParseConstraintExpression. + Diag(ConstraintExpr->getSourceRange().getBegin(), + diag::err_concept_initialized_with_non_bool_type) + << ConstraintExpr->getType(); + NewDecl->setInvalidDecl(); + } + + 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/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,52 @@ 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()) { + Diag(Tok.getLocation(), diag::err_expected_expression) + << "constraint-expression"; + 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 +1087,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/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/DeclTemplate.cpp =================================================================== --- lib/AST/DeclTemplate.cpp +++ lib/AST/DeclTemplate.cpp @@ -783,6 +783,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 //===----------------------------------------------------------------------===// void ClassTemplatePartialSpecializationDecl::anchor() { } 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, Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -6187,6 +6187,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 +6473,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/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2361,7 +2361,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< @@ -2387,6 +2387,14 @@ def err_concept_specialized : Error< "%select{function|variable}0 concept cannot be " "%select{explicitly instantiated|explicitly specialized|partially specialized}1">; +def err_concept_initialized_with_non_bool_type : Error< + "constraint expression must be 'bool' but found %0">; +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_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 @@ -67,6 +67,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 { }; Index: include/clang/AST/DeclTemplate.h =================================================================== --- include/clang/AST/DeclTemplate.h +++ include/clang/AST/DeclTemplate.h @@ -3004,6 +3004,46 @@ friend class ASTDeclWriter; }; +// \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; + } + + // TODO: Should do source range properly. + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getLocation(), getLocation()); + } + + // 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 cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits