Author: saar.raz Date: Wed Jul 10 14:25:49 2019 New Revision: 365699 URL: http://llvm.org/viewvc/llvm-project?rev=365699&view=rev Log: [Concepts] Concept definitions (D40381)
First in a series of patches to land C++2a Concepts support. This patch adds AST and parsing support for concept-declarations. Added: cfe/trunk/test/CXX/concepts-ts/expr/ cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/ cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/ cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Modified: cfe/trunk/include/clang/AST/ASTNodeTraverser.h cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/AST/TextNodeDumper.h cfe/trunk/include/clang/Basic/DeclNodes.td cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/TemplateKinds.h cfe/trunk/include/clang/Parse/Parser.h cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/include/clang/Serialization/ASTBitCodes.h cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp cfe/trunk/lib/AST/DeclBase.cpp cfe/trunk/lib/AST/DeclPrinter.cpp cfe/trunk/lib/AST/DeclTemplate.cpp cfe/trunk/lib/AST/TextNodeDumper.cpp cfe/trunk/lib/CodeGen/CGDecl.cpp cfe/trunk/lib/CodeGen/CodeGenModule.cpp cfe/trunk/lib/Index/IndexDecl.cpp cfe/trunk/lib/Parse/ParseTemplate.cpp cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclCXX.cpp cfe/trunk/lib/Sema/SemaLookup.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp cfe/trunk/lib/Serialization/ASTCommon.cpp cfe/trunk/lib/Serialization/ASTReaderDecl.cpp cfe/trunk/lib/Serialization/ASTWriter.cpp cfe/trunk/lib/Serialization/ASTWriterDecl.cpp cfe/trunk/tools/libclang/CIndex.cpp Modified: cfe/trunk/include/clang/AST/ASTNodeTraverser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTNodeTraverser.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/ASTNodeTraverser.h (original) +++ cfe/trunk/include/clang/AST/ASTNodeTraverser.h Wed Jul 10 14:25:49 2019 @@ -529,6 +529,11 @@ public: D->defaultArgumentWasInherited() ? "inherited from" : "previous"); } + void VisitConceptDecl(const ConceptDecl *D) { + dumpTemplateParameters(D->getTemplateParameters()); + Visit(D->getConstraintExpr()); + } + void VisitUsingShadowDecl(const UsingShadowDecl *D) { if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) Visit(TD->getTypeForDecl()); Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Jul 10 14:25:49 2019 @@ -3090,6 +3090,42 @@ public: static bool classofKind(Kind K) { return K == VarTemplate; } }; +// \brief Declaration of a C++2a concept. +class ConceptDecl : public TemplateDecl, public Mergeable<ConceptDecl> { +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; + } + + SourceRange getSourceRange() const override LLVM_READONLY { + return SourceRange(getTemplateParameters()->getTemplateLoc(), + ConstraintExpr->getEndLoc()); + } + + // 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; Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Wed Jul 10 14:25:49 2019 @@ -1800,6 +1800,11 @@ DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); }) +DEF_TRAVERSE_DECL(ConceptDecl, { + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + TRY_TO(TraverseStmt(D->getConstraintExpr())); +}) + DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, { // A dependent using declaration which was marked with 'typename'. // template<class T> class A : public B<T> { using typename B<T>::foo; }; Modified: cfe/trunk/include/clang/AST/TextNodeDumper.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TextNodeDumper.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/TextNodeDumper.h (original) +++ cfe/trunk/include/clang/AST/TextNodeDumper.h Wed Jul 10 14:25:49 2019 @@ -347,6 +347,7 @@ public: void VisitObjCPropertyDecl(const ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D); void VisitBlockDecl(const BlockDecl *D); + void VisitConceptDecl(const ConceptDecl *D); }; } // namespace clang Modified: cfe/trunk/include/clang/Basic/DeclNodes.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DeclNodes.td?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DeclNodes.td (original) +++ cfe/trunk/include/clang/Basic/DeclNodes.td Wed Jul 10 14:25:49 2019 @@ -70,6 +70,7 @@ def Named : Decl<"named declarations", 1 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>; Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Wed Jul 10 14:25:49 2019 @@ -684,7 +684,7 @@ def warn_cxx14_compat_template_template_ def err_template_spec_syntax_non_template : Error< "identifier followed by '<' indicates a class template specialization but " "%0 %select{does not refer to a template|refers to a function template|" - "<unused>|refers to a variable template|<unused>}1">; + "<unused>|refers to a variable template|<unused>|refers to a concept}1">; def err_id_after_template_in_nested_name_spec : Error< "expected template name after 'template' keyword in nested name specifier">; def err_unexpected_template_in_unqualified_id : Error< @@ -1287,4 +1287,12 @@ def err_for_co_await_not_range_for : Err "'co_await' modifier can only be applied to range-based for loop">; } +let CategoryName = "Concepts Issue" in { +def err_concept_definition_not_identifier : Error< + "name defined in concept definition must be an identifier">; +def ext_concept_legacy_bool_keyword : ExtWarn< + "ISO C++2a does not permit the 'bool' keyword after 'concept'">, + InGroup<DiagGroup<"concepts-ts-compat">>; +} + } // end of Parser diagnostics Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Jul 10 14:25:49 2019 @@ -2010,8 +2010,8 @@ def err_auto_not_allowed : Error< "%select{'auto'|'decltype(auto)'|'__auto_type'|" "use of " "%select{class template|function template|variable template|alias template|" - "template template parameter|template}2 %3 requires template arguments; " - "argument deduction}0 not allowed " + "template template parameter|concept|template}2 %3 requires template " + "arguments; argument deduction}0 not allowed " "%select{in function prototype" "|in non-static struct member|in struct member" "|in non-static union member|in union member" @@ -2100,8 +2100,8 @@ def err_deduced_class_template_compound_ "deduced class template specialization type">; def err_deduced_non_class_template_specialization_type : Error< "%select{<error>|function template|variable template|alias template|" - "template template parameter|template}0 %1 requires template arguments; " - "argument deduction only allowed for class templates">; + "template template parameter|concept|template}0 %1 requires template " + "arguments; argument deduction only allowed for class templates">; def err_deduced_class_template_ctor_ambiguous : Error< "ambiguous deduction for template arguments of %0">; def err_deduced_class_template_ctor_no_viable : Error< @@ -2128,7 +2128,7 @@ def err_deduction_guide_invalid_specifie def err_deduction_guide_name_not_class_template : Error< "cannot specify deduction guide for " "%select{<error>|function template|variable template|alias template|" - "template template parameter|dependent template name}0 %1">; + "template template parameter|concept|dependent template name}0 %1">; def err_deduction_guide_wrong_scope : Error< "deduction guide must be declared in the same scope as template %q0">; def err_deduction_guide_defines_function : Error< @@ -2456,32 +2456,20 @@ def warn_private_extern : Warning< def note_private_extern : Note< "use __attribute__((visibility(\"hidden\"))) attribute instead">; -// C++ Concepts TS -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< - "concept declarations may only appear in namespace scope">; -def err_function_concept_not_defined : Error< - "function concept declaration must be a definition">; -def err_var_concept_not_initialized : Error< - "variable concept declaration must be initialized">; -def err_function_concept_exception_spec : Error< - "function concept cannot have exception specification">; -def err_concept_decl_invalid_specifiers : Error< - "%select{variable|function}0 concept cannot be declared " - "'%select{thread_local|inline|friend|constexpr}1'">; -def err_function_concept_with_params : Error< - "function concept cannot have any parameters">; -def err_function_concept_bool_ret : Error< - "declared return type of function concept must be 'bool'">; -def err_variable_concept_bool_decl : Error< - "declared type of variable concept must be 'bool'">; -def err_concept_specified_specialization : Error< - "'concept' cannot be applied on an " - "%select{explicit instantiation|explicit specialization|partial specialization}0">; -def err_concept_specialized : Error< - "%select{function|variable}0 concept cannot be " - "%select{explicitly instantiated|explicitly specialized|partially specialized}1">; +// C++ Concepts +def err_concept_initialized_with_non_bool_type : Error< + "constraint expression must be of type 'bool' but is of type %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_no_parameters : Error< + "concept template parameter list must have at least one parameter; explicit " + "specialization of concepts is not allowed">; +def err_concept_extra_headers : Error< + "extraneous template parameter list in concept definition">; +def err_concept_no_associated_constraints : Error< + "concept cannot have associated constraints">; +def err_concept_not_implemented : Error< + "sorry, unimplemented concepts feature %0 used">; def err_template_different_associated_constraints : Error< "associated constraints differ in template redeclaration">; @@ -4019,11 +4007,12 @@ def ext_adl_only_template_id : ExtWarn< def err_template_missing_args : Error< "use of " "%select{class template|function template|variable template|alias template|" - "template template parameter|template}0 %1 requires template arguments">; + "template template parameter|concept|template}0 %1 requires template " + "arguments">; def err_template_arg_list_different_arity : Error< "%select{too few|too many}0 template arguments for " "%select{class template|function template|variable template|alias template|" - "template template parameter|template}1 %2">; + "template template parameter|concept|template}1 %2">; def note_template_decl_here : Note<"template is declared here">; def err_template_arg_must_be_type : Error< "template argument for template type parameter must be a type">; Modified: cfe/trunk/include/clang/Basic/TemplateKinds.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/TemplateKinds.h (original) +++ cfe/trunk/include/clang/Basic/TemplateKinds.h Wed Jul 10 14:25:49 2019 @@ -48,9 +48,9 @@ enum TemplateNameKind { /// anyway. In C++20, this is mandatory in order to parse ADL-only function /// template specialization calls. TNK_Undeclared_template, + /// The name refers to a concept. + TNK_Concept_template, }; } #endif - - Modified: cfe/trunk/include/clang/Parse/Parser.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Parse/Parser.h (original) +++ cfe/trunk/include/clang/Parse/Parser.h Wed Jul 10 14:25:49 2019 @@ -3024,6 +3024,10 @@ private: SourceLocation &DeclEnd, ParsedAttributes &AccessAttrs, AccessSpecifier AS = AS_none); + // C++2a: Template, concept definition [temp] + Decl * + ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd); //===--------------------------------------------------------------------===// // Modules Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Wed Jul 10 14:25:49 2019 @@ -1973,6 +1973,7 @@ public: VarTemplate, AliasTemplate, TemplateTemplateParam, + Concept, DependentTemplate }; TemplateNameKindForDiagnostics @@ -6551,6 +6552,13 @@ public: SourceLocation TemplateLoc, const TemplateArgumentListInfo *TemplateArgs); + ExprResult + CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs); + void diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc); ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -6818,6 +6826,11 @@ public: const TemplateArgument *Args, unsigned NumArgs); + // Concepts + Decl *ActOnConceptDefinition( + Scope *S, MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation NameLoc, Expr *ConstraintExpr); + //===--------------------------------------------------------------------===// // C++ Variadic Templates (C++0x [temp.variadic]) //===--------------------------------------------------------------------===// Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original) +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Wed Jul 10 14:25:49 2019 @@ -1489,7 +1489,10 @@ namespace serialization { /// A TypeAliasTemplateDecl record. DECL_TYPE_ALIAS_TEMPLATE, - /// A StaticAssertDecl record. + /// \brief A ConceptDecl record. + DECL_CONCEPT, + + /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, /// A record containing CXXBaseSpecifiers. Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original) +++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed Jul 10 14:25:49 2019 @@ -1513,6 +1513,18 @@ static bool IsStructurallyEquivalent(Str } static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ConceptDecl *D1, + ConceptDecl *D2) { + // Check template parameters. + if (!IsTemplateDeclCommonStructurallyEquivalent(Context, D1, D2)) + return false; + + // Check the constraint expression. + return IsStructurallyEquivalent(Context, D1->getConstraintExpr(), + D2->getConstraintExpr()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FriendDecl *D1, FriendDecl *D2) { if ((D1->getFriendType() && D2->getFriendDecl()) || (D1->getFriendDecl() && D2->getFriendType())) { @@ -1771,6 +1783,14 @@ bool StructuralEquivalenceContext::Check // Class template/non-class-template mismatch. return false; } + } else if (auto *ConceptDecl1 = dyn_cast<ConceptDecl>(D1)) { + if (auto *ConceptDecl2 = dyn_cast<ConceptDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, ConceptDecl1, ConceptDecl2)) + return false; + } else { + // Concept/non-concept mismatch. + return false; + } } else if (auto *TTP1 = dyn_cast<TemplateTypeParmDecl>(D1)) { if (auto *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) Modified: cfe/trunk/lib/AST/DeclBase.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclBase.cpp (original) +++ cfe/trunk/lib/AST/DeclBase.cpp Wed Jul 10 14:25:49 2019 @@ -710,6 +710,7 @@ unsigned Decl::getIdentifierNamespaceFor case Binding: case NonTypeTemplateParm: case VarTemplate: + case Concept: // These (C++-only) declarations are found by redeclaration lookup for // tag types, so we include them in the tag namespace. return IDNS_Ordinary | IDNS_Tag; Modified: cfe/trunk/lib/AST/DeclPrinter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclPrinter.cpp (original) +++ cfe/trunk/lib/AST/DeclPrinter.cpp Wed Jul 10 14:25:49 2019 @@ -1123,8 +1123,13 @@ void DeclPrinter::VisitTemplateDecl(cons if (TTP->isParameterPack()) Out << "..."; Out << D->getName(); - } else { - Visit(D->getTemplatedDecl()); + } else if (auto *TD = D->getTemplatedDecl()) + Visit(TD); + else if (const auto *Concept = dyn_cast<ConceptDecl>(D)) { + Out << "concept " << Concept->getName() << " = " ; + Concept->getConstraintExpr()->printPretty(Out, nullptr, Policy, + Indentation); + Out << ";"; } } Modified: cfe/trunk/lib/AST/DeclTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/AST/DeclTemplate.cpp (original) +++ cfe/trunk/lib/AST/DeclTemplate.cpp Wed Jul 10 14:25:49 2019 @@ -822,6 +822,26 @@ ClassTemplateSpecializationDecl::getSour } //===----------------------------------------------------------------------===// +// ConceptDecl Implementation +//===----------------------------------------------------------------------===// +ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, + Expr *ConstraintExpr) { + AdoptTemplateParameterList(Params, DC); + 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() {} Modified: cfe/trunk/lib/AST/TextNodeDumper.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TextNodeDumper.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/AST/TextNodeDumper.cpp (original) +++ cfe/trunk/lib/AST/TextNodeDumper.cpp Wed Jul 10 14:25:49 2019 @@ -1936,3 +1936,7 @@ void TextNodeDumper::VisitBlockDecl(cons if (D->capturesCXXThis()) OS << " captures_this"; } + +void TextNodeDumper::VisitConceptDecl(const ConceptDecl *D) { + dumpName(D); +} \ No newline at end of file Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original) +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Wed Jul 10 14:25:49 2019 @@ -108,6 +108,7 @@ void CodeGenFunction::EmitDecl(const Dec case Decl::OMPCapturedExpr: case Decl::OMPRequires: case Decl::Empty: + case Decl::Concept: // None of these decls require codegen support. return; Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original) +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Wed Jul 10 14:25:49 2019 @@ -5162,6 +5162,7 @@ void CodeGenModule::EmitTopLevelDecl(Dec case Decl::UsingShadow: case Decl::ClassTemplate: case Decl::VarTemplate: + case Decl::Concept: case Decl::VarTemplatePartialSpecialization: case Decl::FunctionTemplate: case Decl::TypeAliasTemplate: Modified: cfe/trunk/lib/Index/IndexDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Index/IndexDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Index/IndexDecl.cpp (original) +++ cfe/trunk/lib/Index/IndexDecl.cpp Wed Jul 10 14:25:49 2019 @@ -652,10 +652,10 @@ public: } static bool shouldIndexTemplateParameterDefaultValue(const NamedDecl *D) { - if (!D) - return false; // We want to index the template parameters only once when indexing the // canonical declaration. + if (!D) + return false; if (const auto *FD = dyn_cast<FunctionDecl>(D)) return FD->getCanonicalDecl() == FD; else if (const auto *TD = dyn_cast<TagDecl>(D)) Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseTemplate.cpp (original) +++ cfe/trunk/lib/Parse/ParseTemplate.cpp Wed Jul 10 14:25:49 2019 @@ -49,6 +49,15 @@ Decl *Parser::ParseDeclarationStartingWi /// 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] +/// 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +/// /// explicit-specialization: [ C++ temp.expl.spec] /// 'template' '<' '>' declaration Decl *Parser::ParseTemplateDeclarationOrSpecialization( @@ -142,6 +151,12 @@ Decl *Parser::ParseTemplateDeclarationOr ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization); // Parse the actual template declaration. + if (Tok.is(tok::kw_concept)) + return ParseConceptDefinition( + ParsedTemplateInfo(&ParamLists, isSpecialization, + LastParamListWasEmpty), + DeclEnd); + return ParseSingleDeclarationAfterTemplate( Context, ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty), @@ -315,6 +330,85 @@ Decl *Parser::ParseSingleDeclarationAfte 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. +/// +/// \returns the new declaration. +Decl * +Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, + SourceLocation &DeclEnd) { + assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && + "Template information required"); + assert(Tok.is(tok::kw_concept) && + "ParseConceptDefinition must be called when at a 'concept' keyword"); + + ConsumeToken(); // Consume 'concept' + + SourceLocation BoolKWLoc; + if (TryConsumeToken(tok::kw_bool, BoolKWLoc)) + Diag(Tok.getLocation(), diag::ext_concept_legacy_bool_keyword) << + FixItHint::CreateRemoval(SourceLocation(BoolKWLoc)); + + DiagnoseAndSkipCXX11Attributes(); + + CXXScopeSpec SS; + if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false, /*MayBePseudoDestructor=*/nullptr, + /*IsTypename=*/false, /*LastII=*/nullptr, /*OnlyNamespace=*/true) || + SS.isInvalid()) { + SkipUntil(tok::semi); + return nullptr; + } + + if (SS.isNotEmpty()) + Diag(SS.getBeginLoc(), + diag::err_concept_definition_not_identifier); + + UnqualifiedId Result; + if (ParseUnqualifiedId(SS, /*EnteringContext=*/false, + /*AllowDestructorName=*/false, + /*AllowConstructorName=*/false, + /*AllowDeductionGuide=*/false, + /*ObjectType=*/ParsedType(), /*TemplateKWLoc=*/nullptr, + Result)) { + SkipUntil(tok::semi); + return nullptr; + } + + if (Result.getKind() != UnqualifiedIdKind::IK_Identifier) { + Diag(Result.getBeginLoc(), diag::err_concept_definition_not_identifier); + SkipUntil(tok::semi); + return nullptr; + } + + IdentifierInfo *Id = Result.Identifier; + SourceLocation IdLoc = Result.getBeginLoc(); + + DiagnoseAndSkipCXX11Attributes(); + + if (!TryConsumeToken(tok::equal)) { + Diag(Tok.getLocation(), diag::err_expected) << tok::equal; + SkipUntil(tok::semi); + return nullptr; + } + + ExprResult ConstraintExprResult = + Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + if (ConstraintExprResult.isInvalid()) { + SkipUntil(tok::semi); + return nullptr; + } + + DeclEnd = Tok.getLocation(); + 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. Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Jul 10 14:25:49 2019 @@ -1189,6 +1189,8 @@ Sema::getTemplateNameKindForDiagnostics( return TemplateNameKindForDiagnostics::AliasTemplate; if (isa<TemplateTemplateParmDecl>(TD)) return TemplateNameKindForDiagnostics::TemplateTemplateParam; + if (isa<ConceptDecl>(TD)) + return TemplateNameKindForDiagnostics::Concept; return TemplateNameKindForDiagnostics::DependentTemplate; } Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Wed Jul 10 14:25:49 2019 @@ -9802,7 +9802,7 @@ UsingShadowDecl *Sema::BuildUsingShadowD NonTemplateTarget = TargetTD->getTemplatedDecl(); UsingShadowDecl *Shadow; - if (isa<CXXConstructorDecl>(NonTemplateTarget)) { + if (NonTemplateTarget && isa<CXXConstructorDecl>(NonTemplateTarget)) { bool IsVirtualBase = isVirtualDirectBase(cast<CXXRecordDecl>(CurContext), UD->getQualifier()->getAsRecordDecl()); Modified: cfe/trunk/lib/Sema/SemaLookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) +++ cfe/trunk/lib/Sema/SemaLookup.cpp Wed Jul 10 14:25:49 2019 @@ -5169,7 +5169,8 @@ static NamedDecl *getDefinitionToImport( if (ObjCProtocolDecl *PD = dyn_cast<ObjCProtocolDecl>(D)) return PD->getDefinition(); if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) - return getDefinitionToImport(TD->getTemplatedDecl()); + if (NamedDecl *TTD = TD->getTemplatedDecl()) + return getDefinitionToImport(TTD); return nullptr; } Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jul 10 14:25:49 2019 @@ -271,9 +271,11 @@ TemplateNameKind Sema::isTemplateName(Sc } 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; } } @@ -3227,7 +3229,8 @@ QualType Sema::CheckTemplateIdType(Templ 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()) @@ -4234,6 +4237,18 @@ void Sema::diagnoseMissingTemplateArgume } } +ExprResult +Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, + const DeclarationNameInfo &NameInfo, + ConceptDecl *Template, + SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + // TODO: Do concept specialization here. + Diag(NameInfo.getBeginLoc(), diag::err_concept_not_implemented) << + "concept specialization"; + return ExprError(); +} + ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -4274,6 +4289,12 @@ ExprResult Sema::BuildTemplateIdExpr(con TemplateKWLoc, TemplateArgs); } + if (R.getAsSingle<ConceptDecl>() && !AnyDependentArguments()) { + return CheckConceptTemplateId(SS, R.getLookupNameInfo(), + R.getAsSingle<ConceptDecl>(), + TemplateKWLoc, TemplateArgs); + } + // We don't want lookup warnings at this point. R.suppressDiagnostics(); @@ -7974,7 +7995,74 @@ Decl *Sema::ActOnTemplateDeclarator(Scop return NewDecl; } -/// Strips various properties off an implicit instantiation +Decl *Sema::ActOnConceptDefinition(Scope *S, + MultiTemplateParamsArg TemplateParameterLists, + IdentifierInfo *Name, SourceLocation NameLoc, + Expr *ConstraintExpr) { + DeclContext *DC = CurContext; + + if (!DC->getRedeclContext()->isFileContext()) { + Diag(NameLoc, + diag::err_concept_decls_may_only_appear_in_global_namespace_scope); + return nullptr; + } + + if (TemplateParameterLists.size() > 1) { + Diag(NameLoc, diag::err_concept_extra_headers); + return nullptr; + } + + if (TemplateParameterLists.front()->size() == 0) { + Diag(NameLoc, diag::err_concept_no_parameters); + return nullptr; + } + + ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, + TemplateParameterLists.front(), + ConstraintExpr); + + 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(NameLoc, diag::err_concept_no_associated_constraints); + NewDecl->setInvalidDecl(); + } + + // Check for conflicting previous declaration. + DeclarationNameInfo NameInfo(NewDecl->getDeclName(), NameLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); + LookupName(Previous, S); + + FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace*/false); + if (!Previous.empty()) { + auto *Old = Previous.getRepresentativeDecl(); + Diag(NameLoc, isa<ConceptDecl>(Old) ? diag::err_redefinition : + diag::err_redefinition_different_kind) << NewDecl->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } + + ActOnDocumentableDecl(NewDecl); + PushOnScopeChains(NewDecl, S); + return NewDecl; +} + +/// \brief Strips various properties off an implicit instantiation /// that has just been explicitly specialized. static void StripImplicitInstantiation(NamedDecl *D) { D->dropAttr<DLLImportAttr>(); Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Jul 10 14:25:49 2019 @@ -3401,6 +3401,10 @@ Decl *TemplateDeclInstantiator::VisitFri return nullptr; } +Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { + llvm_unreachable("Concept definitions cannot reside inside a template"); +} + Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) { llvm_unreachable("Unexpected decl"); } Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTCommon.cpp (original) +++ cfe/trunk/lib/Serialization/ASTCommon.cpp Wed Jul 10 14:25:49 2019 @@ -395,6 +395,7 @@ bool serialization::isRedeclarableDeclKi case Decl::BuiltinTemplate: case Decl::Decomposition: case Decl::Binding: + case Decl::Concept: return false; // These indirectly derive from Redeclarable<T> but are not actually Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Wed Jul 10 14:25:49 2019 @@ -382,6 +382,7 @@ namespace clang { 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); @@ -2089,6 +2090,12 @@ DeclID ASTDeclReader::VisitTemplateDecl( return PatternID; } +void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) { + VisitTemplateDecl(D); + D->ConstraintExpr = Record.readExpr(); + mergeMergeable(D); +} + ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); @@ -3829,6 +3836,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID I 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; Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriter.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriter.cpp Wed Jul 10 14:25:49 2019 @@ -1293,6 +1293,7 @@ void ASTWriter::WriteBlockInfoBlock() { 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); Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original) +++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Wed Jul 10 14:25:49 2019 @@ -102,6 +102,7 @@ namespace clang { 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); @@ -1432,6 +1433,12 @@ void ASTDeclWriter::VisitTemplateDecl(Te 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); Added: cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp?rev=365699&view=auto ============================================================================== --- cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp (added) +++ cfe/trunk/test/CXX/concepts-ts/expr/expr.prim/expr.prim.id/p3.cpp Wed Jul 10 14:25:49 2019 @@ -0,0 +1,4 @@ +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s + +template<typename T> concept C = true; +static_assert(C<int>); // expected-error{{sorry, unimplemented concepts feature concept specialization used}} Added: cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp?rev=365699&view=auto ============================================================================== --- cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp (added) +++ cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Wed Jul 10 14:25:49 2019 @@ -0,0 +1,73 @@ +// Support parsing of concepts + +// RUN: %clang_cc1 -std=c++2a -fconcepts-ts -verify %s +template<typename T> concept C1 = true; // expected-note 2{{previous}} + +template<typename T> concept C1 = true; // expected-error{{redefinition}} + +template<concept T> concept D1 = true; +// expected-error@-1{{expected template parameter}} +// expected-error@-2{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}} + +template<template<typename> concept T> concept D2 = true; +// expected-error@-1{{expected identifier}} +// expected-error@-2{{template template parameter requires 'class' after the parameter list}} +// expected-error@-3{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}} + +template<typename T> concept C2 = 0.f; // expected-error {{constraint expression must be of type 'bool' but is of type 'float'}} + +struct S1 { + template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}} +}; + +extern "C++" { + template<typename T> concept C1 = true; // expected-error{{redefinition}} +} + +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}} + +struct C6 {}; // expected-note{{previous definition is here}} +template<typename T> concept C6 = true; +// expected-error@-1{{redefinition of 'C6' as different kind of symbol}} + +// TODO: Add test to prevent explicit specialization, partial specialization +// and explicit instantiation of concepts. + +template<typename T, T v> +struct integral_constant { static constexpr T value = v; }; + +namespace N { + template<typename T> concept C7 = true; +} +using N::C7; + +template <bool word> concept C8 = integral_constant<bool, wor>::value; +// expected-error@-1{{use of undeclared identifier 'wor'; did you mean 'word'?}} +// expected-note@-2{{'word' declared here}} + +template<typename T> concept bool C9 = true; +// expected-warning@-1{{ISO C++2a does not permit the 'bool' keyword after 'concept'}} + +template<> concept C10 = false; +// expected-error@-1{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}} + +template<> concept C9<int> = false; +// expected-error@-1{{name defined in concept definition must be an identifier}} + +template<typename T> concept N::C11 = false; +// expected-error@-1{{name defined in concept definition must be an identifier}} + +class A { }; +// expected-note@-1{{'A' declared here}} + +template<typename T> concept A::C12 = false; +// expected-error@-1{{expected namespace name}} + +template<typename T> concept operator int = false; +// expected-error@-1{{name defined in concept definition must be an identifier}} Modified: cfe/trunk/tools/libclang/CIndex.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=365699&r1=365698&r2=365699&view=diff ============================================================================== --- cfe/trunk/tools/libclang/CIndex.cpp (original) +++ cfe/trunk/tools/libclang/CIndex.cpp Wed Jul 10 14:25:49 2019 @@ -6271,6 +6271,7 @@ CXCursor clang_getCursorDefinition(CXCur 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits