changyu created this revision. Per p0734r0.
https://reviews.llvm.org/D40381 Files: include/clang/AST/DeclTemplate.h include/clang/AST/RecursiveASTVisitor.h include/clang/Basic/DeclNodes.td include/clang/Basic/TemplateKinds.h include/clang/Parse/Parser.h include/clang/Sema/Sema.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 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,7 @@ // 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; +template<typename T> concept C1 = true; + +template<concept T> concept D1 = true; // expected-error {{expected template parameter}} 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++1z -fconcepts-ts -fcxx-exceptions -x c++ -verify %s +// expected-no-diagnostics + +template<typename T> concept C = true; +static_assert(C<int>); 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,10 @@ return PatternID; } +void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) { + VisitTemplateDecl(D); +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); 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) { + // TODO: Do something here? + 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; } } @@ -3884,6 +3886,24 @@ /*FoundD=*/nullptr, TemplateArgs); } +ExprResult +Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + + // DeclResult Decl = CheckVarTemplateId(Template, TemplateLoc, NameInfo.getLoc(), + // *TemplateArgs); + // if (Decl.isInvalid()) + // return ExprError(); + + // // Build an ordinary singleton decl ref. + // return BuildDeclarationNameExpr(SS, NameInfo, cast<ConceptDecl>(Decl.get()), + // /*FoundD=*/nullptr, TemplateArgs); + return Template->getConstraintExpr(); + return true; +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -3913,6 +3933,12 @@ TemplateKWLoc, TemplateArgs); } + if (R.getAsSingle<ConceptDecl>()) { + return CheckConceptTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<ConceptDecl>(), + TemplateKWLoc, TemplateArgs); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -7663,6 +7689,21 @@ return NewDecl; } +Decl *Sema::ActOnConceptDefinition(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation L, + Expr *ConstraintExpr) { + DeclContext *DC = CurContext; + + // TODO: Maybe we should check TemplateParameterLists for nullptr? + Decl *NewDecl = ConceptDecl::Create(Context, DC, L, Name, + TemplateParameterLists[0], + ConstraintExpr); + 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: [Concepts TS] +/// template-head declaration +/// template-head concept-definition +/// +/// TODO: requires-clause +/// template-head: [Concepts TS] +/// 'export'[opt] 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl * @@ -149,12 +158,21 @@ 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); + } else { + return ParseConceptDefinition(Context, + ParsedTemplateInfo(&ParamLists, + isSpecialization, + LastParamListWasEmpty), + ParsingTemplateParams, + DeclEnd, AS, AccessAttrs); + } } /// \brief Parse a single declaration that declares a template, @@ -321,6 +339,49 @@ 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 ConstraintExpr = ParseConstraintExpression(); + + ExpectAndConsumeSemi(diag::err_expected_semi_declaration); + + Decl *ThisDecl = Actions.ActOnConceptDefinition(getCurScope(), + *TemplateInfo.TemplateParams, + Id, IdLoc, ConstraintExpr.get()); + + return ThisDecl; +} + /// 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 +1085,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,19 @@ } //===----------------------------------------------------------------------===// +// 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); +} + + +//===----------------------------------------------------------------------===// // 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/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -6187,6 +6187,12 @@ 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 +6472,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++ 17: 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/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,41 @@ 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); + + Expr *getConstraintExpr() const { + return ConstraintExpr; + } + + // 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