<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On 24 April 2018 at 19:42, Faisal Vali via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: faisalv<br>
Date: Tue Apr 24 19:42:26 2018<br>
New Revision: 330794<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=330794&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project?rev=330794&view=rev</a><br>
Log:<br>
[c++2a] [concepts] Add rudimentary parsing support for template concept declarations<br>
<br>
<br>
This patch is a tweak of changyu's patch: <a href="https://reviews.llvm.org/D40381" rel="noreferrer" target="_blank">https://reviews.llvm.org/<wbr>D40381</a>. It differs in that the recognition of the 'concept' token is moved into the machinery that recognizes declaration-specifiers - this allows us to leverage the attribute handling machinery more seamlessly.<br></blockquote><div><br></div><div>Is that really worth it? This seems to add complexity to decl-specifier-seq / declarator parsing for a construct that has nothing to do with those things. I prefer the simpler approach in changyu's patch. I don't think the diagnostics you're producing are worthwhile -- the problem is not that "concept" can't be combined with other specifiers, it's that it's a fundamentally different kind of construct (just like "using X = ...", which it's much more like than it is like a declarator declaration).</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
See the test file to get a sense of the basic parsing that this patch supports. <br>
<br>
There is much more work to be done before concepts are usable...<br>
<br>
Thanks Changyu!<br>
<br>
Added:<br>
    cfe/trunk/test/Parser/cxx2a-<wbr>concept-declaration.cpp<br>
Removed:<br>
    cfe/trunk/test/Parser/cxx-<wbr>concept-declaration.cpp<br>
Modified:<br>
    cfe/trunk/include/clang/AST/<wbr>DeclTemplate.h<br>
    cfe/trunk/include/clang/AST/<wbr>RecursiveASTVisitor.h<br>
    cfe/trunk/include/clang/Basic/<wbr>DeclNodes.td<br>
    cfe/trunk/include/clang/Basic/<wbr>DiagnosticParseKinds.td<br>
    cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
    cfe/trunk/include/clang/Basic/<wbr>TemplateKinds.h<br>
    cfe/trunk/include/clang/Parse/<wbr>Parser.h<br>
    cfe/trunk/include/clang/Sema/<wbr>DeclSpec.h<br>
    cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
    cfe/trunk/include/clang/<wbr>Serialization/ASTBitCodes.h<br>
    cfe/trunk/lib/AST/ASTDumper.<wbr>cpp<br>
    cfe/trunk/lib/AST/DeclBase.cpp<br>
    cfe/trunk/lib/AST/<wbr>DeclTemplate.cpp<br>
    cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp<br>
    cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp<br>
    cfe/trunk/lib/Parse/ParseDecl.<wbr>cpp<br>
    cfe/trunk/lib/Parse/<wbr>ParseDeclCXX.cpp<br>
    cfe/trunk/lib/Parse/ParseObjc.<wbr>cpp<br>
    cfe/trunk/lib/Parse/<wbr>ParseTemplate.cpp<br>
    cfe/trunk/lib/Parse/<wbr>ParseTentative.cpp<br>
    cfe/trunk/lib/Parse/Parser.cpp<br>
    cfe/trunk/lib/Sema/DeclSpec.<wbr>cpp<br>
    cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
    cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTCommon.cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTReaderDecl.cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
    cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp<br>
    cfe/trunk/tools/libclang/<wbr>CIndex.cpp<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>DeclTemplate.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/DeclTemplate.h?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>DeclTemplate.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>DeclTemplate.h Tue Apr 24 19:42:26 2018<br>
@@ -3015,6 +3015,46 @@ public:<br>
   static bool classofKind(Kind K) { return K == VarTemplate; }<br>
 };<br>
<br>
+/// \brief Represents a C++2a ([temp] p1) concept-definition.<br>
+class ConceptDecl : public TemplateDecl {<br>
+protected:<br>
+  Expr *ConstraintExpr;<br>
+<br>
+  ConceptDecl(DeclContext *DC,<br>
+              SourceLocation NameLoc, DeclarationName Name,<br>
+              TemplateParameterList *Params,<br>
+              Expr *ConstraintExpr)<br>
+      : TemplateDecl(nullptr, Concept, DC, NameLoc, Name, Params),<br>
+        ConstraintExpr(ConstraintExpr) {};<br>
+public:<br>
+  static ConceptDecl *Create(ASTContext &C, DeclContext *DC,<br>
+                             SourceLocation NameLoc, DeclarationName Name,<br>
+                             TemplateParameterList *Params,<br>
+                             Expr *ConstraintExpr);<br>
+  static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);<br>
+<br>
+  Expr *getConstraintExpr() const {<br>
+    return ConstraintExpr;<br>
+  }<br>
+<br>
+  void setConstraintExpr(Expr *CE) {<br>
+    ConstraintExpr = CE;<br>
+  }<br>
+<br>
+  SourceRange getSourceRange() const override LLVM_READONLY {<br>
+    return SourceRange(<wbr>getTemplateParameters()-><wbr>getTemplateLoc(),<br>
+                       getConstraintExpr()-><wbr>getLocEnd());<br>
+  }<br>
+<br>
+  // Implement isa/cast/dyncast/etc.<br>
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }<br>
+  static bool classofKind(Kind K) { return K == Concept; }<br>
+<br>
+  friend class ASTReader;<br>
+  friend class ASTDeclReader;<br>
+  friend class ASTDeclWriter;<br>
+};<br>
+<br>
 inline NamedDecl *getAsNamedDecl(<wbr>TemplateParameter P) {<br>
   if (auto *PD = P.dyn_cast<<wbr>TemplateTypeParmDecl *>())<br>
     return PD;<br>
<br>
Modified: cfe/trunk/include/clang/AST/<wbr>RecursiveASTVisitor.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/AST/RecursiveASTVisitor.<wbr>h?rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/AST/<wbr>RecursiveASTVisitor.h (original)<br>
+++ cfe/trunk/include/clang/AST/<wbr>RecursiveASTVisitor.h Tue Apr 24 19:42:26 2018<br>
@@ -1722,6 +1722,13 @@ DEF_TRAVERSE_TMPL_DECL(Class)<br>
 DEF_TRAVERSE_TMPL_DECL(Var)<br>
 DEF_TRAVERSE_TMPL_DECL(<wbr>Function)<br>
<br>
+DEF_TRAVERSE_DECL(<wbr>ConceptDecl, {<br>
+  TRY_TO(<wbr>TraverseTemplateParameterListH<wbr>elper(D-><wbr>getTemplateParameters()));<br>
+  TRY_TO(TraverseStmt(D-><wbr>getConstraintExpr()));<br>
+  // FIXME: Traverse all the concept specializations (once we implement forming<br>
+  // template-ids with them).<br>
+})<br>
+<br>
 DEF_TRAVERSE_DECL(<wbr>TemplateTemplateParmDecl, {<br>
   // D is the "T" in something like<br>
   //   template <template <typename> class T> class container { };<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DeclNodes.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DeclNodes.td?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/DeclNodes.td?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DeclNodes.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DeclNodes.td Tue Apr 24 19:42:26 2018<br>
@@ -69,6 +69,7 @@ def Named : Decl<"named declarations", 1<br>
       def TypeAliasTemplate : DDecl<RedeclarableTemplate>;<br>
     def TemplateTemplateParm : DDecl<Template>;<br>
     def BuiltinTemplate : DDecl<Template>;<br>
+    def Concept : DDecl<Template>;<br>
   def Using : DDecl<Named>;<br>
   def UsingPack : DDecl<Named>;<br>
   def UsingShadow : DDecl<Named>;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticParseKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticParseKinds.td?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticParseKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticParseKinds.td Tue Apr 24 19:42:26 2018<br>
@@ -1150,6 +1150,24 @@ def err_pragma_cannot_end_force_<wbr>cuda_hos<br>
   "force_cuda_host_device begin">;<br>
 } // end of Parse Issue category.<br>
<br>
+let CategoryName = "Concepts Issue" in {<br>
+def err_concept_at_non_namespace_<wbr>scope : Error<<br>
+  "'concept' can only appear in namespace scope">;<br>
+<br>
+def err_concept_extra_headers : Error<<br>
+  "extraneous template parameter list in concept definition">;<br>
+def err_concept_unexpected_scope_<wbr>spec : Error<<br>
+  "invalid nested name specifier; concepts must be defined in their own namespace">;<br>
+def err_concept_nontemplate : Error<"concept definition must be a template; "<br>
+                                    "missing template parameter list">;<br>
+def err_concept_specialized : Error<<br>
+  "'concept' cannot be "<br>
+  "%select{explicitly specialized|partially specialized}0">;<br>
+def note_concept_specialized : Note<<br>
+  "'concept' cannot be "<br>
+  "%select{explicitly specialized|partially specialized}0">;<br>
+}<br>
+<br>
 let CategoryName = "Modules Issue" in {<br>
 def err_unexpected_module_decl : Error<<br>
   "module declaration can only appear at the top level">;<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/<wbr>DiagnosticSemaKinds.td?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>DiagnosticSemaKinds.td Tue Apr 24 19:42:26 2018<br>
@@ -2387,33 +2387,16 @@ def warn_private_extern : Warning<<br>
 def note_private_extern : Note<<br>
   "use __attribute__((visibility(\"<wbr>hidden\"))) attribute instead">;<br>
<br>
-// C++ Concepts TS<br>
-def err_concept_wrong_decl_kind : Error<<br>
-  "'concept' can only appear on the definition of a function template or variable template">;<br>
-def err_concept_decls_may_only_<wbr>appear_in_namespace_scope : Error<<br>
-  "concept declarations may only appear in namespace scope">;<br>
-def err_function_concept_not_<wbr>defined : Error<<br>
-  "function concept declaration must be a definition">;<br>
-def err_var_concept_not_<wbr>initialized : Error<<br>
-  "variable concept declaration must be initialized">;<br>
-def err_function_concept_<wbr>exception_spec : Error<<br>
-  "function concept cannot have exception specification">;<br>
-def err_concept_decl_invalid_<wbr>specifiers : Error<<br>
-  "%select{variable|function}0 concept cannot be declared "<br>
-  "'%select{thread_local|inline|<wbr>friend|constexpr}1'">;<br>
-def err_function_concept_with_<wbr>params : Error<<br>
-  "function concept cannot have any parameters">;<br>
-def err_function_concept_bool_ret : Error<<br>
-  "declared return type of function concept must be 'bool'">;<br>
-def err_variable_concept_bool_decl : Error<<br>
-  "declared type of variable concept must be 'bool'">;<br>
-def err_concept_specified_<wbr>specialization : Error<<br>
-  "'concept' cannot be applied on an "<br>
-  "%select{explicit instantiation|explicit specialization|partial specialization}0">;<br>
-def err_concept_specialized : Error<<br>
-  "%select{function|variable}0 concept cannot be "<br>
-  "%select{explicitly instantiated|explicitly specialized|partially specialized}1">;<br>
+// C++ Concepts<br>
<br>
+<br>
+<br>
+def err_concept_initialized_with_<wbr>non_bool_type : Error<<br>
+  "type of constraint expression must be 'bool' - not '%0'">;<br>
+def err_concept_no_associated_<wbr>constraints : Error<<br>
+  "concept may not have associated constraints">;<br>
+def err_concept_feature_<wbr>unimplemented : Error<<br>
+  "unimplemented concept feature: %0 (coming soon)">;<br>
 def err_template_different_<wbr>associated_constraints : Error<<br>
   "associated constraints differ in template redeclaration">;<br>
<br>
<br>
Modified: cfe/trunk/include/clang/Basic/<wbr>TemplateKinds.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Basic/TemplateKinds.h?<wbr>rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Basic/<wbr>TemplateKinds.h (original)<br>
+++ cfe/trunk/include/clang/Basic/<wbr>TemplateKinds.h Tue Apr 24 19:42:26 2018<br>
@@ -43,10 +43,10 @@ enum TemplateNameKind {<br>
   /// whether the template name is assumed to refer to a type template or a<br>
   /// function template depends on the context in which the template<br>
   /// name occurs.<br>
-  TNK_Dependent_template_name<br>
+  TNK_Dependent_template_name,<br>
+  /// The name refers to a concept definition.<br>
+  TNK_Concept_template<br>
 };<br>
<br>
 }<br>
 #endif<br>
-<br>
-<br>
<br>
Modified: cfe/trunk/include/clang/Parse/<wbr>Parser.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Parse/Parser.h?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Parse/<wbr>Parser.h (original)<br>
+++ cfe/trunk/include/clang/Parse/<wbr>Parser.h Tue Apr 24 19:42:26 2018<br>
@@ -1959,7 +1959,16 @@ private:<br>
                         ParsedAttributesWithRange &Attrs);<br>
   DeclSpecContext<br>
   getDeclSpecContextFromDeclarat<wbr>orContext(DeclaratorContext Context);<br>
-  void ParseDeclarationSpecifiers(<br>
+<br>
+  /// \brief Parses declaration-specifiers upto a declarator or ';' emitting<br>
+  /// diagnostics as necessary and storing parsed information within DS.<br>
+  ///<br>
+  /// Note: Asides from parsing the routine C/C++ decl-specifiers (which could<br>
+  /// include entire class or enum definitions), this also parses a concept<br>
+  /// definition and stores the appropriate AST representations (for<br>
+  /// class/enum/concept declarations/definitions, decltype<br>
+  /// expression-operands or types, where appropriate) within DS.<br>
+  void ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(<br>
       DeclSpec &DS,<br>
       const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),<br>
       AccessSpecifier AS = AS_none,<br>
@@ -2811,6 +2820,11 @@ private:<br>
                                    SourceLocation &DeclEnd,<br>
                                    AccessSpecifier AS = AS_none);<br>
<br>
+  /// \brief Parse a single template declaration that declares a concept [c++2a]<br>
+  /// and store the AST node within DS.<br>
+  void ParseConceptDefinition(<wbr>SourceLocation ConceptLoc, DeclSpec &DS,<br>
+                              const ParsedTemplateInfo &TemplateInfo,<br>
+                              AccessSpecifier AS, DeclSpecContext DSC);<br>
   //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
   // Modules<br>
   DeclGroupPtrTy ParseModuleDecl();<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>DeclSpec.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/DeclSpec.h?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>DeclSpec.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>DeclSpec.h Tue Apr 24 19:42:26 2018<br>
@@ -38,6 +38,7 @@<br>
 namespace clang {<br>
   class ASTContext;<br>
   class CXXRecordDecl;<br>
+  class ConceptDecl;<br>
   class TypeLoc;<br>
   class LangOptions;<br>
   class IdentifierInfo;<br>
@@ -221,10 +222,13 @@ public:<br>
   unsigned location_size() const { return Builder.getBuffer().second; }<br>
 };<br>
<br>
-/// \brief Captures information about "declaration specifiers".<br>
+/// \brief Captures information about "decl-specifiers" and also concept<br>
+/// definitions.<br>
 ///<br>
 /// "Declaration specifiers" encompasses storage-class-specifiers,<br>
-/// type-specifiers, type-qualifiers, and function-specifiers.<br>
+/// type-specifiers, type-qualifiers, and function-specifiers. This includes<br>
+/// class and enum definitions whose AST representations must be stored - same<br>
+/// with the expression-operands of decltype.<br>
 class DeclSpec {<br>
 public:<br>
   /// \brief storage-class-specifier<br>
@@ -363,8 +367,14 @@ private:<br>
   unsigned Constexpr_specified : 1;<br>
<br>
   union {<br>
+       // Valid if isTypeRep is true.<br>
     UnionParsedType TypeRep;<br>
+    // If we parsed a concept, class, enum (etc.) defintion or elaborated type<br>
+    // specifier, this stores the AST representation.  This is valid if either<br>
+    // isDeclRep or isConceptSpecified returns true.<br>
     Decl *DeclRep;<br>
+    // If we parsed a typeof(e) or decltype(e) operator, this stores the<br>
+    // expression 'e'.  Valid if isExprRep is true.<br>
     Expr *ExprRep;<br>
   };<br>
<br>
@@ -393,6 +403,11 @@ private:<br>
   SourceLocation FS_forceinlineLoc;<br>
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;<br>
   SourceLocation TQ_pipeLoc;<br>
+  <br>
+  // Even though 'concept' is not a specifier, we handle it here. This allows us<br>
+  // to reuse infrastructure for diagnosing attributes and invalid<br>
+  // decl-specifiers.<br>
+  SourceLocation ConceptLoc;<br>
<br>
   WrittenBuiltinSpecs writtenBS;<br>
   void SaveWrittenBuiltinSpecs();<br>
@@ -482,7 +497,10 @@ public:<br>
   bool isTypeSpecOwned() const { return TypeSpecOwned; }<br>
   bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }<br>
   bool isTypeSpecPipe() const { return TypeSpecPipe; }<br>
-<br>
+  bool isDeclRep() const {<br>
+    return isDeclRep((TST)TypeSpecType);<br>
+  }<br>
+  <br>
   ParsedType getRepAsType() const {<br>
     assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");<br>
     return TypeRep;<br>
@@ -491,6 +509,17 @@ public:<br>
     assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");<br>
     return DeclRep;<br>
   }<br>
+  // This is a template that should only be instantiated with the type<br>
+  // ConceptDecl.  By making it a template we only require ConceptDecl to be a<br>
+  // complete type where this function is called.<br>
+  template<class ConceptDeclTy = ConceptDecl><br>
+  ConceptDeclTy *getRepAsConcept() const {<br>
+    static_assert(std::is_same<<wbr>ConceptDeclTy, ConceptDecl>::value,<br>
+                  "Must only be instantiated with ConceptDecl");<br>
+    assert(isConceptSpecified() && "DeclSpec does not store a concept");<br>
+<br>
+    return cast_or_null<ConceptDeclTy>(<wbr>DeclRep);<br>
+  }<br>
   Expr *getRepAsExpr() const {<br>
     assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");<br>
     return ExprRep;<br>
@@ -665,6 +694,19 @@ public:<br>
     assert(isDeclRep((TST) TypeSpecType));<br>
     DeclRep = Rep;<br>
   }<br>
+  // This function can only be instantiated with ConceptDecl.  We made it a<br>
+  // template so that ConceptDecl only has to be defined where this is called.<br>
+  template <class ConceptDeclTy = ConceptDecl><br>
+  void setConceptRep(ConceptDecl *Rep) {<br>
+    static_assert(std::is_same<<wbr>ConceptDeclTy, ConceptDecl>::value,<br>
+                  "Must only be instantiated with ConceptDecl");<br>
+    assert(isConceptSpecified() && "DeclSpec does not store a concept");<br>
+    assert(!DeclRep &&<br>
+           "why is this not null? We expect this function to be called only "<br>
+           "once, and usually right after DeclRep was set to null");<br>
+    DeclRep = Rep;<br>
+  }<br>
+  <br>
   void UpdateTypeRep(ParsedType Rep) {<br>
     assert(isTypeRep((TST) TypeSpecType));<br>
     TypeRep = Rep;<br>
@@ -694,6 +736,8 @@ public:<br>
                             unsigned &DiagID);<br>
   bool SetConstexprSpec(<wbr>SourceLocation Loc, const char *&PrevSpec,<br>
                         unsigned &DiagID);<br>
+  bool setConceptSpec(SourceLocation Loc, const char *&PrevSpec,<br>
+                      unsigned &DiagID, const PrintingPolicy &P);<br>
<br>
   bool isFriendSpecified() const { return Friend_specified; }<br>
   SourceLocation getFriendSpecLoc() const { return FriendLoc; }<br>
@@ -704,6 +748,8 @@ public:<br>
   bool isConstexprSpecified() const { return Constexpr_specified; }<br>
   SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }<br>
<br>
+  bool isConceptSpecified() const { return ConceptLoc.isValid(); }<br>
+  SourceLocation getConceptLoc() const { return ConceptLoc; }<br>
   void ClearConstexprSpec() {<br>
     Constexpr_specified = false;<br>
     ConstexprLoc = SourceLocation();<br>
<br>
Modified: cfe/trunk/include/clang/Sema/<wbr>Sema.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Sema/Sema.h?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/Sema/<wbr>Sema.h (original)<br>
+++ cfe/trunk/include/clang/Sema/<wbr>Sema.h Tue Apr 24 19:42:26 2018<br>
@@ -2126,6 +2126,7 @@ public:<br>
<br>
   Decl *ParsedFreeStandingDeclSpec(<wbr>Scope *S, AccessSpecifier AS, DeclSpec &DS,<br>
                                    RecordDecl *&AnonRecord);<br>
+<br>
   Decl *ParsedFreeStandingDeclSpec(<wbr>Scope *S, AccessSpecifier AS, DeclSpec &DS,<br>
                                    MultiTemplateParamsArg TemplateParams,<br>
                                    bool IsExplicitInstantiation,<br>
@@ -6229,6 +6230,13 @@ public:<br>
                                 SourceLocation TemplateLoc,<br>
                                 const TemplateArgumentListInfo *TemplateArgs);<br>
<br>
+  ExprResult<br>
+  CheckConceptTemplateId(const CXXScopeSpec &SS,<br>
+                         const DeclarationNameInfo &NameInfo,<br>
+                         ConceptDecl *Template,<br>
+                         SourceLocation TemplateLoc,<br>
+                         const TemplateArgumentListInfo *TemplateArgs);<br>
+<br>
   ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,<br>
                                  SourceLocation TemplateKWLoc,<br>
                                  LookupResult &R,<br>
@@ -6507,6 +6515,13 @@ public:<br>
                                   const TemplateArgument *Args,<br>
                                   unsigned NumArgs);<br>
<br>
+  // Concepts<br>
+  ConceptDecl *ActOnConceptDefinition(<br>
+      Scope *S,<br>
+      MultiTemplateParamsArg TemplateParameterLists,<br>
+      IdentifierInfo *Name, SourceLocation NameLoc,<br>
+      Expr *ConstraintExpr);<br>
+<br>
   //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
   // C++ Variadic Templates (C++0x [temp.variadic])<br>
   //===-------------------------<wbr>------------------------------<wbr>-------------===//<br>
<br>
Modified: cfe/trunk/include/clang/<wbr>Serialization/ASTBitCodes.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/include/<wbr>clang/Serialization/<wbr>ASTBitCodes.h?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/include/clang/<wbr>Serialization/ASTBitCodes.h (original)<br>
+++ cfe/trunk/include/clang/<wbr>Serialization/ASTBitCodes.h Tue Apr 24 19:42:26 2018<br>
@@ -1408,6 +1408,9 @@ namespace serialization {<br>
       /// \brief A TypeAliasTemplateDecl record.<br>
       DECL_TYPE_ALIAS_TEMPLATE,<br>
<br>
+      /// \brief A ConceptDecl record.<br>
+      DECL_CONCEPT,<br>
+<br>
       /// \brief A StaticAssertDecl record.<br>
       DECL_STATIC_ASSERT,<br>
<br>
<br>
Modified: cfe/trunk/lib/AST/ASTDumper.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>ASTDumper.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/ASTDumper.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/AST/ASTDumper.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -466,6 +466,7 @@ namespace  {<br>
                                          bool DumpRefOnly);<br>
     template<typename TemplateDecl><br>
     void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);<br>
+    void VisitConceptDecl(const ConceptDecl *D);<br>
     void VisitFunctionTemplateDecl(<wbr>const FunctionTemplateDecl *D);<br>
     void VisitClassTemplateDecl(const ClassTemplateDecl *D);<br>
     void VisitClassTemplateSpecializati<wbr>onDecl(<br>
@@ -1577,6 +1578,12 @@ void ASTDumper::VisitTemplateDecl(<wbr>const<br>
                                     !D->isCanonicalDecl());<br>
 }<br>
<br>
+void ASTDumper::VisitConceptDecl(<wbr>const ConceptDecl *D) {<br>
+  dumpName(D);<br>
+  dumpTemplateParameters(D-><wbr>getTemplateParameters());<br>
+  dumpStmt(D->getConstraintExpr(<wbr>));<br>
+}<br>
+<br>
 void ASTDumper::<wbr>VisitFunctionTemplateDecl(<wbr>const FunctionTemplateDecl *D) {<br>
   // FIXME: We don't add a declaration of a function template specialization<br>
   // to its context when it's explicitly instantiated, so dump explicit<br>
<br>
Modified: cfe/trunk/lib/AST/DeclBase.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>DeclBase.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/DeclBase.cpp (original)<br>
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Apr 24 19:42:26 2018<br>
@@ -724,6 +724,7 @@ unsigned Decl::<wbr>getIdentifierNamespaceFor<br>
     case Binding:<br>
     case NonTypeTemplateParm:<br>
     case VarTemplate:<br>
+    case Concept:<br>
       // These (C++-only) declarations are found by redeclaration lookup for<br>
       // tag types, so we include them in the tag namespace.<br>
       return IDNS_Ordinary | IDNS_Tag;<br>
<br>
Modified: cfe/trunk/lib/AST/<wbr>DeclTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/AST/<wbr>DeclTemplate.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/AST/<wbr>DeclTemplate.cpp (original)<br>
+++ cfe/trunk/lib/AST/<wbr>DeclTemplate.cpp Tue Apr 24 19:42:26 2018<br>
@@ -789,6 +789,27 @@ ClassTemplateSpecializationDec<wbr>l::getSour<br>
 }<br>
<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
+// ConceptDecl Implementation<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
+ConceptDecl *ConceptDecl::Create(<wbr>ASTContext &C, DeclContext *DC,<br>
+                                 SourceLocation NameLoc, DeclarationName Name,<br>
+                                 TemplateParameterList *Params,<br>
+                                 Expr *ConstraintExpr) {<br>
+  // TODO: Do we need this?<br>
+  //  AdoptTemplateParameterList(<wbr>Params, cast<DeclContext>(Decl));<br>
+  return new (C, DC) ConceptDecl(DC, NameLoc, Name, Params, ConstraintExpr);<br>
+}<br>
+<br>
+ConceptDecl *ConceptDecl::<wbr>CreateDeserialized(ASTContext &C,<br>
+                                             unsigned ID) {<br>
+  ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(),<br>
+                                                DeclarationName(),<br>
+                                                nullptr, nullptr);<br>
+<br>
+  return Result;<br>
+}<br>
+<br>
+//===------------------------<wbr>------------------------------<wbr>----------------===//<br>
 // ClassTemplatePartialSpecializa<wbr>tionDecl Implementation<br>
 //===-------------------------<wbr>------------------------------<wbr>---------------===//<br>
 void ClassTemplatePartialSpecializa<wbr>tionDecl::anchor() {}<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CGDecl.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDecl.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -105,6 +105,7 @@ void CodeGenFunction::EmitDecl(<wbr>const Dec<br>
   case Decl::OMPThreadPrivate:<br>
   case Decl::OMPCapturedExpr:<br>
   case Decl::Empty:<br>
+  case Decl::Concept:<br>
     // None of these decls require codegen support.<br>
     return;<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/<wbr>CodeGenModule.cpp Tue Apr 24 19:42:26 2018<br>
@@ -4423,6 +4423,7 @@ void CodeGenModule::<wbr>EmitTopLevelDecl(Dec<br>
   case Decl::TypeAliasTemplate:<br>
   case Decl::Block:<br>
   case Decl::Empty:<br>
+  case Decl::Concept:<br>
     break;<br>
   case Decl::Using:          // using X; [C++]<br>
     if (CGDebugInfo *DI = getModuleDebugInfo())<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>ParseDecl.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/ParseDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseDecl.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -1739,7 +1739,8 @@ Parser::<wbr>ParseSimpleDeclaration(<wbr>Declarato<br>
   ParsingDeclSpec DS(*this);<br>
<br>
   DeclSpecContext DSContext = getDeclSpecContextFromDeclarat<wbr>orContext(Context);<br>
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS, ParsedTemplateInfo(),<br>
+                                                       AS_none, DSContext);<br>
<br>
   // If we had a free-standing type definition with a missing semicolon, we<br>
   // may get this far before the problem becomes obvious.<br>
@@ -2386,7 +2387,8 @@ void Parser::<wbr>ParseSpecifierQualifierList<br>
   /// specifier-qualifier-list is a subset of declaration-specifiers.  Just<br>
   /// parse declaration-specifiers and complain about extra stuff.<br>
   /// TODO: diagnose attribute-specifiers and alignment-specifiers.<br>
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS, ParsedTemplateInfo(), AS,<br>
+                                                DSC);<br>
<br>
   // Validate declspec for type-name.<br>
   unsigned Specs = DS.getParsedSpecifiers();<br>
@@ -2871,11 +2873,12 @@ Parser::<wbr>DiagnoseMissingSemiAfterTagDef<wbr>in<br>
   // and call ParsedFreeStandingDeclSpec as appropriate.<br>
   DS.ClearTypeSpecType();<br>
   ParsedTemplateInfo NotATemplate;<br>
-  ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS, NotATemplate, AS, DSContext,<br>
+                                      LateAttrs);<br>
   return false;<br>
 }<br>
<br>
-/// ParseDeclarationSpecifiers<br>
+/// ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition<br>
 ///       declaration-specifiers: [C99 6.7]<br>
 ///         storage-class-specifier declaration-specifiers[opt]<br>
 ///         type-specifier declaration-specifiers[opt]<br>
@@ -2902,7 +2905,8 @@ Parser::<wbr>DiagnoseMissingSemiAfterTagDef<wbr>in<br>
 /// [OpenCL] '__kernel'<br>
 ///       'friend': [C++ dcl.friend]<br>
 ///       'constexpr': [C++0x dcl.constexpr]<br>
-void Parser::<wbr>ParseDeclarationSpecifiers(<wbr>DeclSpec &DS,<br>
+/// [C++2a] 'concept'<br>
+void Parser::<wbr>ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DeclSpec &DS,<br>
                                         const ParsedTemplateInfo &TemplateInfo,<br>
                                         AccessSpecifier AS,<br>
                                         DeclSpecContext DSContext,<br>
@@ -3680,7 +3684,11 @@ void Parser::<wbr>ParseDeclarationSpecifiers(<br>
       ConsumeToken();<br>
       ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);<br>
       continue;<br>
-<br>
+    <br>
+    case tok::kw_concept:<br>
+      ConsumeToken();<br>
+      ParseConceptDefinition(Loc, DS, TemplateInfo, AS, DSContext);<br>
+      continue;<br>
     // cv-qualifier:<br>
     case tok::kw_const:<br>
       isInvalid = DS.SetTypeQual(DeclSpec::TQ_<wbr>const, Loc, PrevSpec, DiagID,<br>
@@ -6366,7 +6374,7 @@ void Parser::<wbr>ParseParameterDeclarationCl<br>
     // too much hassle.<br>
     DS.takeAttributesFrom(<wbr>FirstArgAttrs);<br>
<br>
-    ParseDeclarationSpecifiers(DS)<wbr>;<br>
+    ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS);<br>
<br>
<br>
     // Parse the declarator.  This is "PrototypeContext" or <br>
<br>
Modified: cfe/trunk/lib/Parse/<wbr>ParseDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>ParseDeclCXX.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/<wbr>ParseDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Parse/<wbr>ParseDeclCXX.cpp Tue Apr 24 19:42:26 2018<br>
@@ -2561,8 +2561,8 @@ Parser::<wbr>ParseCXXClassMemberDeclaration<wbr>(A<br>
   if (MalformedTypeSpec)<br>
     DS.SetTypeSpecError();<br>
<br>
-  ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_class,<br>
-                             &CommonLateParsedAttrs);<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(<br>
+      DS, TemplateInfo, AS, DeclSpecContext::DSC_class, &CommonLateParsedAttrs);<br>
<br>
   // Turn off colon protection that was set for declspec.<br>
   X.restore();<br>
<br>
Modified: cfe/trunk/lib/Parse/ParseObjc.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>ParseObjc.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/ParseObjc.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Parse/ParseObjc.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -1490,7 +1490,7 @@ Decl *Parser::ParseObjCMethodDecl(<wbr>Source<br>
       cStyleParamWarned = true;<br>
     }<br>
     DeclSpec DS(AttrFactory);<br>
-    ParseDeclarationSpecifiers(DS)<wbr>;<br>
+    ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS);<br>
     // Parse the declarator.<br>
     Declarator ParmDecl(DS, DeclaratorContext::<wbr>PrototypeContext);<br>
     ParseDeclarator(ParmDecl);<br>
@@ -2541,7 +2541,7 @@ StmtResult Parser::ParseObjCTryStmt(Sour<br>
                                         Scope::AtCatchScope);<br>
         if (Tok.isNot(tok::ellipsis)) {<br>
           DeclSpec DS(AttrFactory);<br>
-          ParseDeclarationSpecifiers(DS)<wbr>;<br>
+          ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS);<br>
           Declarator ParmDecl(DS, DeclaratorContext::<wbr>ObjCCatchContext);<br>
           ParseDeclarator(ParmDecl);<br>
<br>
<br>
Modified: cfe/trunk/lib/Parse/<wbr>ParseTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>ParseTemplate.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/<wbr>ParseTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Parse/<wbr>ParseTemplate.cpp Tue Apr 24 19:42:26 2018<br>
@@ -54,6 +54,15 @@ Parser::<wbr>ParseDeclarationStartingWithTe<wbr>mp<br>
 ///       template-declaration: [C++ temp]<br>
 ///         'export'[opt] 'template' '<' template-parameter-list '>' declaration<br>
 ///<br>
+///       template-declaration: [C++2a]<br>
+///         template-head declaration<br>
+///         template-head concept-definition<br>
+///<br>
+///       TODO: requires-clause<br>
+///       template-head: [C++2a]<br>
+///         'export'[opt] 'template' '<' template-parameter-list '>'<br>
+///             requires-clause[opt]<br>
+///<br>
 ///       explicit-specialization: [ C++ temp.expl.spec]<br>
 ///         'template' '<' '>' declaration<br>
 Decl *<br>
@@ -148,13 +157,10 @@ Parser::<wbr>ParseTemplateDeclarationOrSpec<wbr>ia<br>
   unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;<br>
   ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);<br>
<br>
-  // Parse the actual template declaration.<br>
-  return ParseSingleDeclarationAfterTem<wbr>plate(Context,<br>
-                                             ParsedTemplateInfo(&<wbr>ParamLists,<br>
-                                                             isSpecialization,<br>
-                                                         LastParamListWasEmpty),<br>
-                                             ParsingTemplateParams,<br>
-                                             DeclEnd, AS, AccessAttrs);<br>
+  return ParseSingleDeclarationAfterTem<wbr>plate(<br>
+      Context,<br>
+      ParsedTemplateInfo(&<wbr>ParamLists, isSpecialization, LastParamListWasEmpty),<br>
+      ParsingTemplateParams, DeclEnd, AS, AccessAttrs);<br>
 }<br>
<br>
 /// \brief Parse a single declaration that declares a template,<br>
@@ -208,7 +214,7 @@ Parser::<wbr>ParseSingleDeclarationAfterTem<wbr>pl<br>
   // the template parameters.<br>
   ParsingDeclSpec DS(*this, &DiagsFromTParams);<br>
<br>
-  ParseDeclarationSpecifiers(DS, TemplateInfo, AS,<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS, TemplateInfo, AS,<br>
                              getDeclSpecContextFromDeclarat<wbr>orContext(Context));<br>
<br>
   if (Tok.is(tok::semi)) {<br>
@@ -322,6 +328,149 @@ Parser::<wbr>ParseSingleDeclarationAfterTem<wbr>pl<br>
   return ThisDecl;<br>
 }<br>
<br>
+<br>
+void<br>
+Parser::<wbr>ParseConceptDefinition(<wbr>SourceLocation ConceptLoc,<br>
+                           DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,<br>
+                           AccessSpecifier AS, <br>
+                           DeclSpecContext DSC) {<br>
+<br>
+  <br>
+  auto DiagnoseAttributes = [this] {<br>
+    ParsedAttributesWithRange attrs(this->AttrFactory);<br>
+    this->MaybeParseGNUAttributes(<wbr>attrs);<br>
+    this-><wbr>MaybeParseCXX11Attributes(<wbr>attrs);<br>
+    this-><wbr>MaybeParseMicrosoftDeclSpecs(<wbr>attrs);<br>
+    this->ProhibitAttributes(<wbr>attrs);<br>
+  };<br>
+<br>
+<br>
+  // If attributes exist after 'concept' kw but before the concept name,<br>
+  // prohibit them for now (if CWG approves attributes on concepts, this is<br>
+  // likely where they will go...).<br>
+  DiagnoseAttributes();<br>
+<br>
+  // Set the concept specifier at ConceptLoc within 'DS' along with emitting any<br>
+  // incompatible decl-specifier diagnostics.<br>
+  {<br>
+    const char *PrevSpec = 0;<br>
+    unsigned int DiagId = 0;<br>
+    if (DS.setConceptSpec(ConceptLoc, PrevSpec, DiagId,<br>
+                          Actions.getASTContext().<wbr>getPrintingPolicy())) {<br>
+      Diag(ConceptLoc, DiagId) << PrevSpec;<br>
+    }<br>
+    Actions.<wbr>DiagnoseFunctionSpecifiers(DS)<wbr>;<br>
+  }<br>
+<br>
+  if (DSC != DeclSpecContext::DSC_top_<wbr>level) {<br>
+    Diag(ConceptLoc, diag::err_concept_at_non_<wbr>namespace_scope);<br>
+    // If we are not in a template parameter context, skip to a '}' or ';'. The<br>
+    // error messages are better if we just ignore this within template<br>
+    // parameter lists.<br>
+    if (DSC != DeclSpecContext::DSC_template_<wbr>param) {<br>
+      SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);<br>
+    } else {<br>
+      SkipUntil(llvm::makeArrayRef({<wbr>tok::comma, tok::greater}),<br>
+                StopAtSemi | StopBeforeMatch);<br>
+    }<br>
+    return;<br>
+  }<br>
+<br>
+  // A scope-guard that (if an error occurs while parsing a concept) skips to<br>
+  // the next semi or closing brace.<br>
+  class SkipUntilSemiOrClosingBraceOnS<wbr>copeExit {<br>
+    Parser &P;<br>
+    bool Disabled = false;<br>
+<br>
+  public:<br>
+    SkipUntilSemiOrClosingBraceOnS<wbr>copeExit(Parser &P)<br>
+        : P(P) {}<br>
+    void disable() { Disabled = true; }<br>
+    ~<wbr>SkipUntilSemiOrClosingBraceOnS<wbr>copeExit() {<br>
+      if (!Disabled) {<br>
+        // Skip until the semi-colon or a '}'.<br>
+        P.SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);<br>
+      }<br>
+    }<br>
+  } SkipUntilSemiOrClosingBraceOnS<wbr>copeExit(*this);<br>
+<br>
+  if (TemplateInfo.Kind == ParsedTemplateInfo::<wbr>NonTemplate) {<br>
+    Diag(ConceptLoc, diag::err_concept_nontemplate)<wbr>;<br>
+    return;<br>
+  }<br>
+  <br>
+  const TemplateParameterLists &ParamLists = *TemplateInfo.TemplateParams;<br>
+<br>
+  <br>
+  // More than one TPL wouldn't make sense here.<br>
+  if (ParamLists.size() != 1) {<br>
+    Diag(Tok.getLocation(), diag::err_concept_extra_<wbr>headers);<br>
+    return;<br>
+  }<br>
+  const TemplateParameterList *const TPL = ParamLists[0];<br>
+<br>
+  // Explicit specializations of concepts are not allowed.<br>
+  if (TPL->getLAngleLoc().<wbr>getLocWithOffset(1) == TPL->getRAngleLoc()) {<br>
+    assert(!TPL->size() &&<br>
+           "can not have template parameters within empty angle brackets!");<br>
+    Diag(ConceptLoc, diag::err_concept_specialized) << 0;<br>
+    return;<br>
+  }<br>
+  // Concepts can not be defined with nested name specifiers.<br>
+  CXXScopeSpec SS;<br>
+  if (<wbr>ParseOptionalCXXScopeSpecifier<wbr>(SS, nullptr,<br>
+                                     /*EnteringContext=*/false) ||<br>
+      SS.isNotEmpty()) {<br>
+<br>
+    if (SS.isNotEmpty())<br>
+      Diag(Tok.getLocation(), diag::err_concept_unexpected_<wbr>scope_spec);<br>
+    return;<br>
+  }<br>
+  // An identifier (i.e. the concept-name) should follow 'concept'.<br>
+  if (!Tok.is(tok::identifier)) {<br>
+    Diag(Tok.getLocation(), diag::err_expected) << "concept name";<br>
+    return;<br>
+  }<br>
+<br>
+  IdentifierInfo *Id = Tok.getIdentifierInfo();<br>
+  SourceLocation IdLoc = ConsumeToken();<br>
+  <br>
+  // If attributes exist after the identifier, parse them and diagnose<br>
+  DiagnoseAttributes();<br>
+<br>
+  if (!TryConsumeToken(tok::equal)) {<br>
+    Diag(Tok.getLocation(), diag::err_expected) << "equal";<br>
+    return;<br>
+  }<br>
+<br>
+  ExprResult ConstraintExprResult = ParseConstraintExpression();<br>
+  if (ConstraintExprResult.<wbr>isInvalid()) {<br>
+    Diag(Tok.getLocation(), diag::err_expected_expression)<br>
+      << "constraint-expression";<br>
+    return;<br>
+  }<br>
+<br>
+  // We can try to create a valid concept decl node now, so disable the<br>
+  // scope-guard.<br>
+  SkipUntilSemiOrClosingBraceOnS<wbr>copeExit.disable();<br>
+<br>
+  Expr *ConstraintExpr = ConstraintExprResult.get();<br>
+  ConceptDecl *const ConDecl = Actions.<wbr>ActOnConceptDefinition(<br>
+      getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc, ConstraintExpr);<br>
+  DS.setConceptRep(ConDecl);<br>
+<br>
+  if (Tok.isNot(tok::semi)) {<br>
+    <br>
+    ExpectAndConsume(tok::semi, diag::err_expected_after, "concept");<br>
+    // Push this token back into the preprocessor and change our current token<br>
+    // to ';' so that the rest of the code recovers as though there were an<br>
+    // ';' after the definition.<br>
+    PP.EnterToken(Tok);<br>
+    Tok.setKind(tok::semi);<br>
+  }<br>
+  return;<br>
+}<br>
+<br>
 /// ParseTemplateParameters - Parses a template-parameter-list enclosed in<br>
 /// angle brackets. Depth is the depth of this template-parameter-list, which<br>
 /// is the number of template headers directly enclosing this template header.<br>
@@ -690,8 +839,8 @@ Parser::<wbr>ParseNonTypeTemplateParameter(<wbr>un<br>
   // FIXME: The type should probably be restricted in some way... Not all<br>
   // declarators (parts of declarators?) are accepted for parameters.<br>
   DeclSpec DS(AttrFactory);<br>
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,<br>
-                             DeclSpecContext::DSC_template_<wbr>param);<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(<br>
+      DS, ParsedTemplateInfo(), AS_none, DeclSpecContext::DSC_template_<wbr>param);<br>
<br>
   // Parse this as a typename.<br>
   Declarator ParamDecl(DS, DeclaratorContext::<wbr>TemplateParamContext);<br>
<br>
Modified: cfe/trunk/lib/Parse/<wbr>ParseTentative.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>ParseTentative.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/<wbr>ParseTentative.cpp (original)<br>
+++ cfe/trunk/lib/Parse/<wbr>ParseTentative.cpp Tue Apr 24 19:42:26 2018<br>
@@ -1351,6 +1351,7 @@ Parser::<wbr>isCXXDeclarationSpecifier(<wbr>Parser<br>
   case tok::kw_struct:<br>
   case tok::kw_union:<br>
   case tok::kw___interface:<br>
+  case tok::kw_concept:<br>
     // enum-specifier<br>
   case tok::kw_enum:<br>
     // cv-qualifier<br>
<br>
Modified: cfe/trunk/lib/Parse/Parser.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Parse/<wbr>Parser.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Parse/Parser.cpp (original)<br>
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Apr 24 19:42:26 2018<br>
@@ -919,7 +919,7 @@ Parser::<wbr>ParseDeclOrFunctionDefInternal<wbr>(P<br>
                                        AccessSpecifier AS) {<br>
   MaybeParseMicrosoftAttributes(<wbr>DS.getAttributes());<br>
   // Parse the common declaration-specifiers piece.<br>
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,<br>
+  ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS, ParsedTemplateInfo(), AS,<br>
                              DeclSpecContext::DSC_top_<wbr>level);<br>
<br>
   // If we had a free-standing type definition with a missing semicolon, we<br>
@@ -1287,7 +1287,7 @@ void Parser::<wbr>ParseKNRParamDeclarations(D<br>
<br>
     // Parse the common declaration-specifiers piece.<br>
     DeclSpec DS(AttrFactory);<br>
-    ParseDeclarationSpecifiers(DS)<wbr>;<br>
+    ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition(DS);<br>
<br>
     // C99 6.9.1p6: 'each declaration in the declaration list shall have at<br>
     // least one declarator'.<br>
@@ -1647,7 +1647,7 @@ bool Parser::<wbr>TryKeywordIdentFallback(boo<br>
 /// Actions.getTypeName will not be needed to be called again (e.g. getTypeName<br>
 /// will not be called twice, once to check whether we have a declaration<br>
 /// specifier, and another one to get the actual type inside<br>
-/// ParseDeclarationSpecifiers).<br>
+/// ParseDeclarationSpecifiersOrCo<wbr>nceptDefinition).<br>
 ///<br>
 /// This returns true if an error occurred.<br>
 ///<br>
<br>
Modified: cfe/trunk/lib/Sema/DeclSpec.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>DeclSpec.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/DeclSpec.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/DeclSpec.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -426,6 +426,7 @@ unsigned DeclSpec::getParsedSpecifiers(<wbr>)<br>
   return Res;<br>
 }<br>
<br>
+<br>
 template <class T> static bool BadSpecifier(T TNew, T TPrev,<br>
                                             const char *&PrevSpec,<br>
                                             unsigned &DiagID,<br>
@@ -491,7 +492,6 @@ const char *DeclSpec::getSpecifierName(T<br>
   }<br>
   llvm_unreachable("Unknown typespec!");<br>
 }<br>
-<br>
 const char *DeclSpec::getSpecifierName(<wbr>DeclSpec::TST T,<br>
                                        const PrintingPolicy &Policy) {<br>
   switch (T) {<br>
@@ -969,6 +969,69 @@ bool DeclSpec::SetConstexprSpec(<wbr>SourceLo<br>
   return false;<br>
 }<br>
<br>
+bool DeclSpec::setConceptSpec(const SourceLocation Loc, const char *&PrevSpec,<br>
+                              unsigned &DiagID, const PrintingPolicy &PP) {<br>
+  assert(Loc.isValid() && "Loc must be valid, since it is used to identify "<br>
+                          "that this function was called before");<br>
+  assert(!ConceptLoc.isValid() &&<br>
+         "how is this called if concept was already encountered and triggered "<br>
+         "ParseConceptDefinition which parses upto the semi-colon");<br>
+<br>
+  PrevSpec = nullptr;<br>
+  if (TypeSpecType != TST_unspecified) {<br>
+    PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<TST>(TypeSpecType)<wbr>, PP);<br>
+         ClearTypeSpecType();<br>
+  }<br>
+  if (TypeSpecSign != TSS_unspecified) {<br>
+    PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<TSS>(TypeSpecSign)<wbr>);<br>
+         TypeSpecSign = TSS_unspecified;<br>
+  }<br>
+  if (TypeSpecWidth != TSW_unspecified) {<br>
+    PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<TSW>(<wbr>TypeSpecWidth));<br>
+         TypeSpecWidth = TSW_unspecified;<br>
+  }<br>
+  if (StorageClassSpec != SCS_unspecified) {<br>
+    PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<SCS>(<wbr>StorageClassSpec));<br>
+         ClearStorageClassSpecs();<br>
+  }<br>
+  if (ThreadStorageClassSpec != TSCS_unspecified) {<br>
+    PrevSpec =<br>
+        DeclSpec::getSpecifierName(<wbr>static_cast<TSCS>(<wbr>ThreadStorageClassSpec));<br>
+    ClearStorageClassSpecs();<br>
+  }<br>
+  if (TypeSpecComplex != TSC_unspecified) {<br>
+    PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<TSC>(<wbr>TypeSpecComplex));<br>
+    TypeSpecComplex = TSC_unspecified;<br>
+  }<br>
+  if (getTypeQualifiers()) {<br>
+         PrevSpec = DeclSpec::getSpecifierName(<wbr>static_cast<TQ>(<wbr>TypeQualifiers));<br>
+    ClearTypeQualifiers();<br>
+  }<br>
+  if (isFriendSpecified()) {<br>
+    PrevSpec = "friend";<br>
+    Friend_specified = false;<br>
+    FriendLoc = SourceLocation();<br>
+  }<br>
+  if (isConstexprSpecified()) {<br>
+    PrevSpec = "constexpr";<br>
+    Constexpr_specified = false;<br>
+    ConstexprLoc = SourceLocation();<br>
+  }<br>
+  if (isInlineSpecified()) {<br>
+    PrevSpec = "inline";<br>
+    FS_inlineLoc = SourceLocation();<br>
+    FS_inline_specified = false;<br>
+  }<br>
+<br>
+  if (PrevSpec) {<br>
+    DiagID = diag::err_invalid_decl_spec_<wbr>combination;<br>
+  }<br>
+  // We set the concept location regardless of whether an error occurred.<br>
+  DeclRep = nullptr;<br>
+  ConceptLoc = Loc;<br>
+  return PrevSpec; // If this is non-null, an error occurred.<br>
+}<br>
+<br>
 void DeclSpec::<wbr>SaveWrittenBuiltinSpecs() {<br>
   writtenBS.Sign = getTypeSpecSign();<br>
   writtenBS.Width = getTypeSpecWidth();<br>
@@ -1270,6 +1333,7 @@ void DeclSpec::Finish(Sema &S, const Pri<br>
   // TODO: return "auto function" and other bad things based on the real type.<br>
<br>
   // 'data definition has no type or storage class'?<br>
+<br>
 }<br>
<br>
 bool DeclSpec::<wbr>isMissingDeclaratorOk() {<br>
<br>
Modified: cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDecl.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/SemaDecl.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -4212,6 +4212,12 @@ Sema::<wbr>ParsedFreeStandingDeclSpec(<wbr>Scope *<br>
                                  MultiTemplateParamsArg TemplateParams,<br>
                                  bool IsExplicitInstantiation,<br>
                                  RecordDecl *&AnonRecord) {<br>
+<br>
+  // We don't need to do any additional declspecifier checking on concept<br>
+  // definitions since that should already have been done when the concept kw<br>
+  // location was set within DS.<br>
+  if (DS.isConceptSpecified()) return DS.getRepAsConcept();<br>
+  <br>
   Decl *TagD = nullptr;<br>
   TagDecl *Tag = nullptr;<br>
   if (DS.getTypeSpecType() == DeclSpec::TST_class ||<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp?rev=330794&r1=<wbr>330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaDeclCXX.cpp Tue Apr 24 19:42:26 2018<br>
@@ -9467,7 +9467,7 @@ UsingShadowDecl *Sema::BuildUsingShadowD<br>
     NonTemplateTarget = TargetTD->getTemplatedDecl();<br>
<br>
   UsingShadowDecl *Shadow;<br>
-  if (isa<CXXConstructorDecl>(<wbr>NonTemplateTarget)) {<br>
+  if (!isa<ConceptDecl>(Target) && isa<CXXConstructorDecl>(<wbr>NonTemplateTarget)) {<br>
     bool IsVirtualBase =<br>
         isVirtualDirectBase(cast<<wbr>CXXRecordDecl>(CurContext),<br>
                             UD->getQualifier()-><wbr>getAsRecordDecl());<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp?rev=330794&<wbr>r1=330793&r2=330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplate.cpp Tue Apr 24 19:42:26 2018<br>
@@ -232,9 +232,11 @@ TemplateNameKind Sema::isTemplateName(Sc<br>
     } else {<br>
       assert(isa<ClassTemplateDecl>(<wbr>TD) || isa<TemplateTemplateParmDecl>(<wbr>TD) ||<br>
              isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||<br>
-             isa<BuiltinTemplateDecl>(TD));<br>
+             isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));<br>
       TemplateKind =<br>
-          isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;<br>
+          isa<VarTemplateDecl>(TD) ? TNK_Var_template :<br>
+          isa<ConceptDecl>(TD) ? TNK_Concept_template :<br>
+          TNK_Type_template;<br>
     }<br>
   }<br>
<br>
@@ -3034,7 +3036,8 @@ QualType Sema::CheckTemplateIdType(<wbr>Templ<br>
<br>
   TemplateDecl *Template = Name.getAsTemplateDecl();<br>
   if (!Template || isa<FunctionTemplateDecl>(<wbr>Template) ||<br>
-      isa<VarTemplateDecl>(Template)<wbr>) {<br>
+      isa<VarTemplateDecl>(Template) ||<br>
+      isa<ConceptDecl>(Template)) {<br>
     // We might have a substituted template template parameter pack. If so,<br>
     // build a template specialization type for it.<br>
     if (Name.<wbr>getAsSubstTemplateTemplateParm<wbr>Pack())<br>
@@ -3988,6 +3991,18 @@ Sema::CheckVarTemplateId(const CXXScopeS<br>
                                   /*FoundD=*/nullptr, TemplateArgs);<br>
 }<br>
<br>
+ExprResult<br>
+Sema::CheckConceptTemplateId(<wbr>const CXXScopeSpec &SS,<br>
+                             const DeclarationNameInfo &NameInfo,<br>
+                             ConceptDecl *Template,<br>
+                             SourceLocation TemplateLoc,<br>
+                             const TemplateArgumentListInfo *TemplateArgs) {<br>
+  // TODO: Do concept specialization here.<br>
+  Diag(Template->getLocation(), diag::err_concept_feature_<wbr>unimplemented)<br>
+      << "can not form concept template-id";<br>
+  return ExprError();<br>
+}<br>
+<br>
 ExprResult Sema::BuildTemplateIdExpr(<wbr>const CXXScopeSpec &SS,<br>
                                      SourceLocation TemplateKWLoc,<br>
                                      LookupResult &R,<br>
@@ -4009,14 +4024,21 @@ ExprResult Sema::BuildTemplateIdExpr(con<br>
<br>
   // In C++1y, check variable template ids.<br>
   bool InstantiationDependent;<br>
-  if (R.getAsSingle<<wbr>VarTemplateDecl>() &&<br>
-      !TemplateSpecializationType::<wbr>anyDependentTemplateArguments(<br>
-           *TemplateArgs, InstantiationDependent)) {<br>
+  const bool DependentArguments =<br>
+    TemplateSpecializationType::<wbr>anyDependentTemplateArguments(<br>
+      *TemplateArgs, InstantiationDependent);<br>
+  if (R.getAsSingle<<wbr>VarTemplateDecl>() && !DependentArguments) {<br>
     return CheckVarTemplateId(SS, R.getLookupNameInfo(),<br>
                               R.getAsSingle<VarTemplateDecl><wbr>(),<br>
                               TemplateKWLoc, TemplateArgs);<br>
   }<br>
<br>
+  if (R.getAsSingle<ConceptDecl>() && !DependentArguments) {<br>
+    return CheckConceptTemplateId(SS, R.getLookupNameInfo(),<br>
+                                  R.getAsSingle<ConceptDecl>(),<br>
+                                  TemplateKWLoc, TemplateArgs);<br>
+  }<br>
+<br>
   // We don't want lookup warnings at this point.<br>
   R.suppressDiagnostics();<br>
<br>
@@ -7688,6 +7710,61 @@ Decl *Sema::<wbr>ActOnTemplateDeclarator(Scop<br>
   return NewDecl;<br>
 }<br>
<br>
+ConceptDecl *Sema::ActOnConceptDefinition(<wbr>Scope *S,<br>
+    MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name,<br>
+    SourceLocation NameLoc, Expr *ConstraintExpr) {<br>
+  // C++2a [temp.concept]p3:<br>
+  // A concept-definition shall appear in the global scope or in a namespace<br>
+  // scope.<br>
+  assert(<br>
+      CurContext->isFileContext() &&<br>
+      "We check during parsing that 'concept's only occur at namespace scope");<br>
+<br>
+  // Forbid any prior declaration of this name within the current namespace.<br>
+  LookupResult Previous(*this,<br>
+                        DeclarationNameInfo(<wbr>DeclarationName(Name), NameLoc),<br>
+                        LookupOrdinaryName);<br>
+  LookupName(Previous, S);<br>
+  if (!Previous.empty()) {<br>
+    const NamedDecl *PrevDecl = Previous.<wbr>getRepresentativeDecl();<br>
+    if (PrevDecl->getDeclContext()-><wbr>Equals(CurContext)) {<br>
+      if (Previous.isSingleResult() &&<br>
+          isa<ConceptDecl>(Previous.<wbr>getFoundDecl())) {<br>
+        Diag(NameLoc, diag::err_redefinition) << Name;<br>
+      } else {<br>
+        Diag(NameLoc, diag::err_redefinition_<wbr>different_kind) << Name;<br>
+      }<br>
+      Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;<br>
+      return nullptr;<br>
+    }<br>
+  }<br>
+<br>
+  ConceptDecl *NewDecl = ConceptDecl::Create(Context, CurContext, NameLoc,<br>
+                                             Name, TemplateParameterLists[0],<br>
+                                             ConstraintExpr);<br>
+<br>
+  if (!NewDecl)<br>
+    return nullptr;<br>
+<br>
+  if (NewDecl-><wbr>getAssociatedConstraints()) {<br>
+    // C++2a [temp.concept]p4:<br>
+    // A concept shall not have associated constraints.<br>
+    // TODO: Make a test once we have actual associated constraints.<br>
+    Diag(NameLoc, diag::err_concept_no_<wbr>associated_constraints);<br>
+    NewDecl->setInvalidDecl();<br>
+  }<br>
+<br>
+  assert((S-><wbr>isTemplateParamScope() || !TemplateParameterLists[0]-><wbr>size()) &&<br>
+         "Not in template param scope?");<br>
+  assert(S->getParent() && !S->getParent()-><wbr>isTemplateParamScope() &&<br>
+         "Parent scope should exist and not be template parameter.");<br>
+<br>
+  ActOnDocumentableDecl(NewDecl)<wbr>;<br>
+  PushOnScopeChains(NewDecl, S->getParent(), /*AddToContext=*/true);<br>
+<br>
+  return NewDecl;<br>
+}<br>
+<br>
 /// \brief Strips various properties off an implicit instantiation<br>
 /// that has just been explicitly specialized.<br>
 static void StripImplicitInstantiation(<wbr>NamedDecl *D) {<br>
<br>
Modified: cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp?rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp (original)<br>
+++ cfe/trunk/lib/Sema/<wbr>SemaTemplateInstantiateDecl.<wbr>cpp Tue Apr 24 19:42:26 2018<br>
@@ -3073,6 +3073,11 @@ Decl *TemplateDeclInstantiator::<wbr>VisitFri<br>
   return nullptr;<br>
 }<br>
<br>
+Decl *TemplateDeclInstantiator::<wbr>VisitConceptDecl(ConceptDecl *D) {<br>
+  llvm_unreachable("Concept definitions cannot reside inside a template");<br>
+  return nullptr;<br>
+}<br>
+<br>
 Decl *TemplateDeclInstantiator::<wbr>VisitDecl(Decl *D) {<br>
   llvm_unreachable("Unexpected decl");<br>
 }<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTCommon.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTCommon.cpp?<wbr>rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTCommon.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTCommon.cpp Tue Apr 24 19:42:26 2018<br>
@@ -313,6 +313,7 @@ bool serialization::<wbr>isRedeclarableDeclKi<br>
   case Decl::BuiltinTemplate:<br>
   case Decl::Decomposition:<br>
   case Decl::Binding:<br>
+  case Decl::Concept:<br>
     return false;<br>
<br>
   // These indirectly derive from Redeclarable<T> but are not actually<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTReaderDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTReaderDecl.<wbr>cpp?rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTReaderDecl.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTReaderDecl.cpp Tue Apr 24 19:42:26 2018<br>
@@ -381,6 +381,7 @@ namespace clang {<br>
     void VisitBindingDecl(BindingDecl *BD);<br>
     void VisitNonTypeTemplateParmDecl(<wbr>NonTypeTemplateParmDecl *D);<br>
     DeclID VisitTemplateDecl(TemplateDecl *D);<br>
+    void VisitConceptDecl(ConceptDecl *D);<br>
     RedeclarableResult VisitRedeclarableTemplateDecl(<wbr>RedeclarableTemplateDecl *D);<br>
     void VisitClassTemplateDecl(<wbr>ClassTemplateDecl *D);<br>
     void VisitBuiltinTemplateDecl(<wbr>BuiltinTemplateDecl *D);<br>
@@ -2031,6 +2032,11 @@ DeclID ASTDeclReader::<wbr>VisitTemplateDecl(<br>
   return PatternID;<br>
 }<br>
<br>
+void ASTDeclReader::<wbr>VisitConceptDecl(ConceptDecl *D) {<br>
+  VisitTemplateDecl(D);<br>
+  D->setConstraintExpr(Record.<wbr>readExpr());<br>
+}<br>
+<br>
 ASTDeclReader::<wbr>RedeclarableResult<br>
 ASTDeclReader::<wbr>VisitRedeclarableTemplateDecl(<wbr>RedeclarableTemplateDecl *D) {<br>
   RedeclarableResult Redecl = VisitRedeclarable(D);<br>
@@ -3595,6 +3601,9 @@ Decl *ASTReader::ReadDeclRecord(<wbr>DeclID I<br>
   case DECL_TYPE_ALIAS_TEMPLATE:<br>
     D = TypeAliasTemplateDecl::<wbr>CreateDeserialized(Context, ID);<br>
     break;<br>
+  case DECL_CONCEPT:<br>
+    D = ConceptDecl::<wbr>CreateDeserialized(Context, ID);<br>
+    break;<br>
   case DECL_STATIC_ASSERT:<br>
     D = StaticAssertDecl::<wbr>CreateDeserialized(Context, ID);<br>
     break;<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriter.cpp?<wbr>rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTWriter.cpp Tue Apr 24 19:42:26 2018<br>
@@ -1280,6 +1280,7 @@ void ASTWriter::<wbr>WriteBlockInfoBlock() {<br>
   RECORD(DECL_TEMPLATE_TYPE_<wbr>PARM);<br>
   RECORD(DECL_NON_TYPE_TEMPLATE_<wbr>PARM);<br>
   RECORD(DECL_TEMPLATE_TEMPLATE_<wbr>PARM);<br>
+  RECORD(DECL_CONCEPT);<br>
   RECORD(DECL_TYPE_ALIAS_<wbr>TEMPLATE);<br>
   RECORD(DECL_STATIC_ASSERT);<br>
   RECORD(DECL_CXX_BASE_<wbr>SPECIFIERS);<br>
<br>
Modified: cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/lib/<wbr>Serialization/ASTWriterDecl.<wbr>cpp?rev=330794&r1=330793&r2=<wbr>330794&view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp (original)<br>
+++ cfe/trunk/lib/Serialization/<wbr>ASTWriterDecl.cpp Tue Apr 24 19:42:26 2018<br>
@@ -102,6 +102,7 @@ namespace clang {<br>
     void VisitBindingDecl(BindingDecl *D);<br>
     void VisitNonTypeTemplateParmDecl(<wbr>NonTypeTemplateParmDecl *D);<br>
     void VisitTemplateDecl(TemplateDecl *D);<br>
+    void VisitConceptDecl(ConceptDecl *D);<br>
     void VisitRedeclarableTemplateDecl(<wbr>RedeclarableTemplateDecl *D);<br>
     void VisitClassTemplateDecl(<wbr>ClassTemplateDecl *D);<br>
     void VisitVarTemplateDecl(<wbr>VarTemplateDecl *D);<br>
@@ -1395,6 +1396,12 @@ void ASTDeclWriter::<wbr>VisitTemplateDecl(Te<br>
   Record.<wbr>AddTemplateParameterList(D-><wbr>getTemplateParameters());<br>
 }<br>
<br>
+void ASTDeclWriter::<wbr>VisitConceptDecl(ConceptDecl *D) {<br>
+  VisitTemplateDecl(D);<br>
+  Record.AddStmt(D-><wbr>getConstraintExpr());<br>
+  Code = serialization::DECL_CONCEPT;<br>
+}<br>
+<br>
 void ASTDeclWriter::<wbr>VisitRedeclarableTemplateDecl(<wbr>RedeclarableTemplateDecl *D) {<br>
   VisitRedeclarable(D);<br>
<br>
<br>
Removed: cfe/trunk/test/Parser/cxx-<wbr>concept-declaration.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-concept-declaration.cpp?rev=330793&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/Parser/<wbr>cxx-concept-declaration.cpp?<wbr>rev=330793&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Parser/cxx-<wbr>concept-declaration.cpp (original)<br>
+++ cfe/trunk/test/Parser/cxx-<wbr>concept-declaration.cpp (removed)<br>
@@ -1,7 +0,0 @@<br>
-<br>
-// Support parsing of concepts<br>
-// Disabled for now.<br>
-// expected-no-diagnostics<br>
-<br>
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s<br>
-// template<typename T> concept C1 = true;<br>
<br>
Added: cfe/trunk/test/Parser/cxx2a-<wbr>concept-declaration.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp?rev=330794&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/test/Parser/<wbr>cxx2a-concept-declaration.cpp?<wbr>rev=330794&view=auto</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/test/Parser/cxx2a-<wbr>concept-declaration.cpp (added)<br>
+++ cfe/trunk/test/Parser/cxx2a-<wbr>concept-declaration.cpp Tue Apr 24 19:42:26 2018<br>
@@ -0,0 +1,83 @@<br>
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s<br>
+// Support parsing of concepts<br>
+<br>
+concept X;  //expected-error {{must be a template}}<br>
+<br>
+template<typename T> concept C1 = true; //expected-note{{declared here}}  <-- previous declaration<br>
+<br>
+template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}<br>
+<br>
+template<concept T> concept D1 = true; // expected-error {{'concept' can only appear in namespace scope}} \<br>
+                                          expected-error {{expected template parameter}}<br>
+<br>
+template<> concept X = true; // expected-error {{cannot be explicitly specialized}}<br>
+<br>
+namespace ns1 {<br>
+template<> concept D1 = true;  // expected-error {{cannot be explicitly specialized}}<br>
+template<typename T> const concept C1 = true; //expected-error{{cannot combine with}}<br>
+namespace ns12 {<br>
+template<typename T> decltype(T{}) concept C2 = true; //expected-error{{cannot combine with}}<br>
+template<typename T> bool concept C3 = true; //expected-error{{cannot combine with}}<br>
+template<typename T> unsigned concept C4 = true; //expected-error{{cannot combine with}}<br>
+template<typename T> short concept C5 = true; //expected-error{{cannot combine with}}<br>
+template<typename T> typedef concept C6 = true; //expected-error{{cannot combine with}}<br>
+}<br>
+template<class> concept <br>
+                        const  //expected-error{{expected concept name}}<br>
+                                                     C2 = true; <br>
+                                                         <br>
+void f() {<br>
+       concept X; //expected-error{{'concept' can only appear in namespace scope}}<br>
+}<br>
+template<concept X,  //expected-error{{'concept' can only appear in namespace scope}} \<br>
+                                          expected-error {{expected template parameter}}<br>
+                                 int J> void f();<br>
+}<br>
+<br>
+template<class T><br>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}<br>
+<br>
+namespace ns2 {<br>
+template<class T><br>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}<br>
+       <br>
+}<br>
+<br>
+namespace ns3 {<br>
+   template<typename T> concept C1 = true; <br>
+<br>
+  namespace ns1 {<br>
+       using ns3::C1; //expected-note{{declared here}}<br>
+       template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}<br>
+  }<br>
+<br>
+}<br>
+<br>
+// TODO:<br>
+// template<typename T> concept C2 = 0.f; // expected error {{constraint expression must be 'bool'}}<br>
+<br>
+struct S1 {<br>
+  template<typename T> concept C1 = true; // expected-error {{can only appear in namespace scope}}<br>
+};<br>
+<br>
+template<typename A><br>
+template<typename B><br>
+concept C4 = true; // expected-error {{extraneous template parameter list in concept definition}}<br>
+<br>
+template<typename T> concept C5 = true; // expected-note {{previous}} expected-note {{previous}}<br>
+int C5; // expected-error {{redefinition}}<br>
+struct C5 {}; // expected-error {{redefinition}}<br>
+<br>
+struct C6 {}; //expected-note{{declared here}}  <-- previous declaration<br>
+template<typename T> concept C6 = true; // expected-error {{redefinition of 'C6' as different kind of symbol}}<br>
+<br>
+namespace thing {};<br>
+<br>
+template<typename T> concept thing::C7 = true;  // expected-error {{concepts must be defined in their own namespace}}<br>
+<br>
+<br>
+namespace ns5 {<br>
+}<br>
+<br>
+// TODO: Add test to prevent explicit specialization, partial specialization<br>
+// and explicit instantiation of concepts.<br>
<br>
Modified: cfe/trunk/tools/libclang/<wbr>CIndex.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=330794&r1=330793&r2=330794&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-<wbr>project/cfe/trunk/tools/<wbr>libclang/CIndex.cpp?rev=<wbr>330794&r1=330793&r2=330794&<wbr>view=diff</a><br>
==============================<wbr>==============================<wbr>==================<br>
--- cfe/trunk/tools/libclang/<wbr>CIndex.cpp (original)<br>
+++ cfe/trunk/tools/libclang/<wbr>CIndex.cpp Tue Apr 24 19:42:26 2018<br>
@@ -6173,6 +6173,7 @@ CXCursor clang_getCursorDefinition(<wbr>CXCur<br>
   case Decl::PragmaComment:<br>
   case Decl::PragmaDetectMismatch:<br>
   case Decl::UsingPack:<br>
+  case Decl::Concept:<br>
     return C;<br>
<br>
   // Declaration kinds that don't make any sense here, but are<br>
<br>
<br>
______________________________<wbr>_________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/<wbr>mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>