changyu updated this revision to Diff 128094.
changyu marked an inline comment as done.

https://reviews.llvm.org/D40381

Files:
  include/clang/AST/DeclTemplate.h
  include/clang/AST/RecursiveASTVisitor.h
  include/clang/Basic/DeclNodes.td
  include/clang/Basic/DiagnosticParseKinds.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/CodeGen/CodeGenModule.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
  test/Parser/cxx2a-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/cxx2a-concept-declaration.cpp
===================================================================
--- /dev/null
+++ test/Parser/cxx2a-concept-declaration.cpp
@@ -0,0 +1,37 @@
+
+// Support parsing of concepts
+
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+template<typename T> concept C1 = true;
+
+template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}
+
+template<concept T> concept D1 = true; // expected-error {{expected template parameter}}
+
+template<> concept D1 = true;  // expected-error {{expected template parameter}}
+
+// TODO:
+// 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}}
+
+struct C6 {};
+template<typename T> concept C6 = true; // expected-error {{redefinition of 'C6' as different kind of symbol}}
+
+namespace thing {};
+
+template<typename T> concept thing::C7 = true;  // expected-error {{concepts must be defined within their namespace}}
+
+
+// TODO: Add test to prevent explicit specialization, partial specialization
+// and explicit instantiation of concepts.
Index: test/Parser/cxx-concept-declaration.cpp
===================================================================
--- test/Parser/cxx-concept-declaration.cpp
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// 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;
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,6 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+// expected-no-diagnostics
+
+// TODO: Make this work.
+// 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,17 @@
                                   /*FoundD=*/nullptr, TemplateArgs);
 }
 
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+                             const DeclarationNameInfo &NameInfo,
+                             ConceptDecl *Template,
+                             SourceLocation TemplateLoc,
+                             const TemplateArgumentListInfo *TemplateArgs) {
+  // TODO: Do concept specialization here.
+  Diag(Template->getLocation(), diag::err_concept_not_implemented);
+  return ExprError();
+}
+
 ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
                                      SourceLocation TemplateKWLoc,
                                      LookupResult &R,
@@ -3905,14 +3919,21 @@
 
   // In C++1y, check variable template ids.
   bool InstantiationDependent;
-  if (R.getAsSingle<VarTemplateDecl>() &&
-      !TemplateSpecializationType::anyDependentTemplateArguments(
-           *TemplateArgs, InstantiationDependent)) {
+  const 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 +7684,57 @@
   return NewDecl;
 }
 
+Decl *Sema::ActOnConceptDefinition(Scope *S,
+    MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name,
+    SourceLocation NameLoc, Expr *ConstraintExpr) {
+  // C++2a [temp.concept]p3:
+  // A concept-definition shall appear in the global scope or in a namespace
+  // scope.
+  if (!CurContext->isFileContext()) {
+    Diag(NameLoc,
+      diag::err_concept_decls_may_only_appear_in_global_namespace_scope);
+    return nullptr;
+  }
+
+  LookupResult Previous(*this,
+                        DeclarationNameInfo(DeclarationName(Name), NameLoc),
+                        LookupOrdinaryName);
+  LookupName(Previous, S);
+  if (!Previous.empty()) {
+    if (Previous.isSingleResult() &&
+        isa<ConceptDecl>(Previous.getFoundDecl())) {
+      Diag(NameLoc, diag::err_redefinition) << Name;
+    } else {
+      Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+    }
+    return nullptr;
+  }
+
+  ConceptDecl *NewDecl = ConceptDecl::Create(Context, CurContext, NameLoc,
+                                             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(NameLoc, diag::err_concept_no_associated_constraints);
+    NewDecl->setInvalidDecl();
+  }
+
+  assert(S->isTemplateParamScope() && "Not in template param scope?");
+  assert(S->getParent() && !S->getParent()->isTemplateParamScope() &&
+         "Parent scope should exist and not be template parameter.");
+
+  ActOnDocumentableDecl(NewDecl);
+  PushOnScopeChains(NewDecl, S->getParent(), /*AddToContext=*/true);
+
+  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,43 @@
   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);
+
+  // C++2a [temp.concept]p3:
+  // A concept-definition shall appear in the global scope or in a namespace
+  // scope.
+  // More than one TPL wouldn't make sense here.
+  if (ParamLists.size() != 1) {
+    Diag(Tok.getLocation(), diag::err_concept_extra_headers);
+    SkipUntil(tok::semi);
+    return nullptr;
+  }
+
+  if (LastParamListWasEmpty) {
+    TemplateParameterList *TPL = ParamLists[0];
+    if (TPL->getLAngleLoc().getLocWithOffset(1) == TPL->getRAngleLoc()) {
+      Diag(TPL->getTemplateLoc(),
+           diag::err_expected_template_parameter);
+    }
+    // Otherwise, diagnostic should be printed during template parameter
+    // parsing.
+
+    SkipUntil(tok::semi);
+    return nullptr;
+  }
+
+  return ParseConceptDefinition(Context,
+                                ParsedTemplateInfo(&ParamLists,
+                                                isSpecialization,
+                                            LastParamListWasEmpty),
+                                ParsingTemplateParams,
+                                DeclEnd, AS, AccessAttrs);
 }
 
 /// \brief Parse a single declaration that declares a template,
@@ -321,6 +361,65 @@
   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");
+
+  CXXScopeSpec SS;
+  if (ParseOptionalCXXScopeSpecifier(SS, nullptr,
+                                     /*EnteringContext=*/false)) {
+    SkipUntil(tok::semi);
+    return nullptr;
+  }
+
+  if (SS.isNotEmpty()) {
+    Diag(Tok.getLocation(), diag::err_concept_unexpected_scope_spec);
+    SkipUntil(tok::semi);
+    return nullptr;
+  }
+
+  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 +1123,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/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -4058,6 +4058,7 @@
   case Decl::TypeAliasTemplate:
   case Decl::Block:
   case Decl::Empty:
+  case Decl::Concept:
     break;
   case Decl::Using:          // using X; [C++]
     if (CGDebugInfo *DI = getModuleDebugInfo())
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
@@ -713,8 +713,13 @@
     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.
+
+      // Put concepts in tags namespace so that we get the following error:
+      // template<typename T> concept C5 = true;
+      // struct C5 {}; // expected-error {{redefinition}}
       return IDNS_Ordinary | IDNS_Tag;
 
     case ObjCCompatibleAlias:
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 NameLoc,
+      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_no_associated_constraints : Error<
+  "concept may not have associated constraints">;
+def err_concept_not_implemented : Error<
+  "this part's not implemented yet">;
 
 def err_template_different_associated_constraints : Error<
   "associated constraints differ in template redeclaration">;
Index: include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- include/clang/Basic/DiagnosticParseKinds.td
+++ include/clang/Basic/DiagnosticParseKinds.td
@@ -1127,6 +1127,13 @@
   "force_cuda_host_device begin">;
 } // end of Parse Issue category.
 
+let CategoryName = "Concepts Issue" in {
+def err_concept_extra_headers : Error<
+  "extraneous template parameter list in concept definition">;
+def err_concept_unexpected_scope_spec : Error<
+  "concepts must be defined within their namespace">;
+}
+
 let CategoryName = "Modules Issue" in {
 def err_unexpected_module_decl : Error<
   "module declaration can only appear at the top level">;
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,12 @@
 DEF_TRAVERSE_TMPL_DECL(Var)
 DEF_TRAVERSE_TMPL_DECL(Function)
 
+DEF_TRAVERSE_DECL(ConceptDecl, {
+  TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+  TRY_TO(TraverseStmt(D->getConstraintExpr()));
+  // FIXME: Traverse all the concept specializations (one we implement forming template-ids with them).
+})
+
 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,45 @@
   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;
+  }
+
+  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
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to