<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:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);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>
<br>
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></blockquote><div><br></div><div>This doesn't seem very clear, it sounds like you're saying that the user must add a namespace to contain their concepts. For alias-declarations, we say:</div><div><br></div><div><div><font face="monospace, monospace"><source>:2:7: error: name defined in alias declaration must be an identifier</font></div><div><font face="monospace, monospace">using N::a = int;</font></div><div><font face="monospace, monospace">      ^~~</font></div></div><div><br></div><div>... which is admittedly also not very good, but making the two consistent seems like a good idea.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+def err_concept_nontemplate : Error<"concept definition must be a template; "<br>
+                                    "missing template parameter list">;<br></blockquote><div><br></div><div>This is not how we wrap lines in .td files :)</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+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></blockquote><div><br></div><div>I don't think we need/want single-quotes around "concept" in these. We're talking about concepts abstractly, not the 'concept' keyword.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<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></blockquote><div><br></div><div>I think this puts the emphasis on the wrong place. The user probably meant to write a constraint expression of type 'bool', so we should front-load the information about what type they actually got. Maybe:</div><div><br></div><div>"constraint expression is of type '%0' but must be of type 'bool'"</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+def err_concept_no_associated_<wbr>constraints : Error<<br>
+  "concept may not have associated constraints">;<br></blockquote><div><br></div><div>may not -> cannot. This is a restriction, not a permission.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+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></blockquote><div><br></div><div>Shouldn't this be returning a Decl*? This approach is presumably failing to hand the declaration off to ActOnTopLevelDecl in the outer parse loop.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+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></blockquote><div><br></div><div>Why the explicit "this->"s here?</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<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>
</blockquote><div><br></div><div>Why would we even get here in these cases? The only case we should reach this code is at class scope, because that's the only place where a template declaration can occur but a concept definition cannot.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">+      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></blockquote><div><br></div><div>This seems like a bad idea to me. *Assuming* that something has gone wrong unless otherwise notified makes this code fragile. This is not an appropriate use for RAII in my view. If you want to more nicely factor this code, consider factoring out the inner parsing code into a helper function that returns 'bool', and do the SkipUntil if the helper returns true.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  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></blockquote><div><br></div><div>This is very wrong. "template< >" is missed by this, for example, as are a bunch of macro cases. TPL->empty() is the thing you need to check here.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    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></blockquote><div><br></div><div>This is not acceptable; diagnostics should be localizable, so you should not use English phrases here.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    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></blockquote><div><br></div><div>Missing period at end of comment.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  DiagnoseAttributes();<br>
+<br>
+  if (!TryConsumeToken(tok::equal)) {<br>
+    Diag(Tok.getLocation(), diag::err_expected) << "equal";<br></blockquote><div><br></div><div>This is likewise wrong. You can use tok::equal, or "'='", but not the English word "equal".</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    return;<br>
+  }<br>
+<br>
+  ExprResult ConstraintExprResult = ParseConstraintExpression();<br>
+  if (ConstraintExprResult.<wbr>isInvalid()) {<br>
+    Diag(Tok.getLocation(), diag::err_expected_expression)<br>
+      << "constraint-expression";<br></blockquote><div><br></div><div>Grammar terms are not appropriate here either. But you should not produce a diagnostic here at all -- when a function returns an invalid ActionResult, the universal convention is that that means a diagnostic has already been emitted.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    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></blockquote><div><br></div><div>Again, the use of "concept" here is inappropriate.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    // 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></blockquote><div><br></div><div>This doesn't make sense. ExpectAndConsume doesn't consume the token if it's not the expected one. But in any case, you should replace all of this with ExpectAndConsumeSemi.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+    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></blockquote><div><br></div><div>Is the problem here that NonTemplateTarget is null for a ConceptDecl? If so, please express that directly with a null check.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
     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></blockquote><div><br></div><div>This assert is incorrect; concept definitions can also appear in ExportDecls, for instance.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<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></blockquote><div><br></div><div>This is impossible.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  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></blockquote><div><br></div><div>This is also impossible, since we don't pass any associated constraints into the ::Create call. And when that can happen (template<Constraint A> concept B = ...), we should be checking this before we create the declaration.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+  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></blockquote><div><br></div><div>This return statement is dead code, remove it.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+}<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>