r330794 - [c++2a] [concepts] Add rudimentary parsing support for template concept declarations

Faisal Vali via cfe-commits cfe-commits at lists.llvm.org
Tue Apr 24 19:42:26 PDT 2018


Author: faisalv
Date: Tue Apr 24 19:42:26 2018
New Revision: 330794

URL: http://llvm.org/viewvc/llvm-project?rev=330794&view=rev
Log:
[c++2a] [concepts] Add rudimentary parsing support for template concept declarations


This patch is a tweak of changyu's patch: https://reviews.llvm.org/D40381. 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.

See the test file to get a sense of the basic parsing that this patch supports. 

There is much more work to be done before concepts are usable...

Thanks Changyu!

Added:
    cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp
Removed:
    cfe/trunk/test/Parser/cxx-concept-declaration.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclTemplate.h
    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
    cfe/trunk/include/clang/Basic/DeclNodes.td
    cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/TemplateKinds.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
    cfe/trunk/lib/AST/ASTDumper.cpp
    cfe/trunk/lib/AST/DeclBase.cpp
    cfe/trunk/lib/AST/DeclTemplate.cpp
    cfe/trunk/lib/CodeGen/CGDecl.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseDeclCXX.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/DeclSpec.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Serialization/ASTCommon.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/tools/libclang/CIndex.cpp

Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Apr 24 19:42:26 2018
@@ -3015,6 +3015,46 @@ public:
   static bool classofKind(Kind K) { return K == VarTemplate; }
 };
 
+/// \brief Represents a C++2a ([temp] p1) concept-definition.
+class ConceptDecl : public TemplateDecl {
+protected:
+  Expr *ConstraintExpr;
+
+  ConceptDecl(DeclContext *DC,
+              SourceLocation NameLoc, DeclarationName Name,
+              TemplateParameterList *Params,
+              Expr *ConstraintExpr)
+      : TemplateDecl(nullptr, Concept, DC, NameLoc, Name, Params),
+        ConstraintExpr(ConstraintExpr) {};
+public:
+  static ConceptDecl *Create(ASTContext &C, DeclContext *DC,
+                             SourceLocation NameLoc, DeclarationName Name,
+                             TemplateParameterList *Params,
+                             Expr *ConstraintExpr);
+  static ConceptDecl *CreateDeserialized(ASTContext &C, unsigned ID);
+
+  Expr *getConstraintExpr() const {
+    return ConstraintExpr;
+  }
+
+  void setConstraintExpr(Expr *CE) {
+    ConstraintExpr = CE;
+  }
+
+  SourceRange getSourceRange() const override LLVM_READONLY {
+    return SourceRange(getTemplateParameters()->getTemplateLoc(),
+                       getConstraintExpr()->getLocEnd());
+  }
+
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
+  static bool classofKind(Kind K) { return K == Concept; }
+
+  friend class ASTReader;
+  friend class ASTDeclReader;
+  friend class ASTDeclWriter;
+};
+
 inline NamedDecl *getAsNamedDecl(TemplateParameter P) {
   if (auto *PD = P.dyn_cast<TemplateTypeParmDecl *>())
     return PD;

Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
+++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Tue Apr 24 19:42:26 2018
@@ -1722,6 +1722,13 @@ DEF_TRAVERSE_TMPL_DECL(Class)
 DEF_TRAVERSE_TMPL_DECL(Var)
 DEF_TRAVERSE_TMPL_DECL(Function)
 
+DEF_TRAVERSE_DECL(ConceptDecl, {
+  TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters()));
+  TRY_TO(TraverseStmt(D->getConstraintExpr()));
+  // FIXME: Traverse all the concept specializations (once we implement forming
+  // template-ids with them).
+})
+
 DEF_TRAVERSE_DECL(TemplateTemplateParmDecl, {
   // D is the "T" in something like
   //   template <template <typename> class T> class container { };

Modified: cfe/trunk/include/clang/Basic/DeclNodes.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DeclNodes.td?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DeclNodes.td (original)
+++ cfe/trunk/include/clang/Basic/DeclNodes.td Tue Apr 24 19:42:26 2018
@@ -69,6 +69,7 @@ def Named : Decl<"named declarations", 1
       def TypeAliasTemplate : DDecl<RedeclarableTemplate>;
     def TemplateTemplateParm : DDecl<Template>;
     def BuiltinTemplate : DDecl<Template>;
+    def Concept : DDecl<Template>;
   def Using : DDecl<Named>;
   def UsingPack : DDecl<Named>;
   def UsingShadow : DDecl<Named>;

Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Tue Apr 24 19:42:26 2018
@@ -1150,6 +1150,24 @@ def err_pragma_cannot_end_force_cuda_hos
   "force_cuda_host_device begin">;
 } // end of Parse Issue category.
 
+let CategoryName = "Concepts Issue" in {
+def err_concept_at_non_namespace_scope : Error<
+  "'concept' can only appear in namespace scope">;
+
+def err_concept_extra_headers : Error<
+  "extraneous template parameter list in concept definition">;
+def err_concept_unexpected_scope_spec : Error<
+  "invalid nested name specifier; concepts must be defined in their own namespace">;
+def err_concept_nontemplate : Error<"concept definition must be a template; "
+                                    "missing template parameter list">;
+def err_concept_specialized : Error<
+  "'concept' cannot be "
+  "%select{explicitly specialized|partially specialized}0">;
+def note_concept_specialized : Note<
+  "'concept' cannot be "
+  "%select{explicitly specialized|partially specialized}0">;
+}
+
 let CategoryName = "Modules Issue" in {
 def err_unexpected_module_decl : Error<
   "module declaration can only appear at the top level">;

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Apr 24 19:42:26 2018
@@ -2387,33 +2387,16 @@ def warn_private_extern : Warning<
 def note_private_extern : Note<
   "use __attribute__((visibility(\"hidden\"))) attribute instead">;
 
-// C++ Concepts TS
-def err_concept_wrong_decl_kind : Error<
-  "'concept' can only appear on the definition of a function template or variable template">;
-def err_concept_decls_may_only_appear_in_namespace_scope : Error<
-  "concept declarations may only appear in namespace scope">;
-def err_function_concept_not_defined : Error<
-  "function concept declaration must be a definition">;
-def err_var_concept_not_initialized : Error<
-  "variable concept declaration must be initialized">;
-def err_function_concept_exception_spec : Error<
-  "function concept cannot have exception specification">;
-def err_concept_decl_invalid_specifiers : Error<
-  "%select{variable|function}0 concept cannot be declared "
-  "'%select{thread_local|inline|friend|constexpr}1'">;
-def err_function_concept_with_params : Error<
-  "function concept cannot have any parameters">;
-def err_function_concept_bool_ret : Error<
-  "declared return type of function concept must be 'bool'">;
-def err_variable_concept_bool_decl : Error<
-  "declared type of variable concept must be 'bool'">;
-def err_concept_specified_specialization : Error<
-  "'concept' cannot be applied on an "
-  "%select{explicit instantiation|explicit specialization|partial specialization}0">;
-def err_concept_specialized : Error<
-  "%select{function|variable}0 concept cannot be "
-  "%select{explicitly instantiated|explicitly specialized|partially specialized}1">;
+// C++ Concepts
 
+
+
+def err_concept_initialized_with_non_bool_type : Error<
+  "type of constraint expression must be 'bool' - not '%0'">;
+def err_concept_no_associated_constraints : Error<
+  "concept may not have associated constraints">;
+def err_concept_feature_unimplemented : Error<
+  "unimplemented concept feature: %0 (coming soon)">;
 def err_template_different_associated_constraints : Error<
   "associated constraints differ in template redeclaration">;
 

Modified: cfe/trunk/include/clang/Basic/TemplateKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TemplateKinds.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TemplateKinds.h (original)
+++ cfe/trunk/include/clang/Basic/TemplateKinds.h Tue Apr 24 19:42:26 2018
@@ -43,10 +43,10 @@ enum TemplateNameKind {
   /// whether the template name is assumed to refer to a type template or a
   /// function template depends on the context in which the template
   /// name occurs.
-  TNK_Dependent_template_name
+  TNK_Dependent_template_name,
+  /// The name refers to a concept definition.
+  TNK_Concept_template
 };
 
 }
 #endif
-
-

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Apr 24 19:42:26 2018
@@ -1959,7 +1959,16 @@ private:
                         ParsedAttributesWithRange &Attrs);
   DeclSpecContext
   getDeclSpecContextFromDeclaratorContext(DeclaratorContext Context);
-  void ParseDeclarationSpecifiers(
+
+  /// \brief Parses declaration-specifiers upto a declarator or ';' emitting
+  /// diagnostics as necessary and storing parsed information within DS.
+  ///
+  /// Note: Asides from parsing the routine C/C++ decl-specifiers (which could
+  /// include entire class or enum definitions), this also parses a concept
+  /// definition and stores the appropriate AST representations (for
+  /// class/enum/concept declarations/definitions, decltype
+  /// expression-operands or types, where appropriate) within DS.
+  void ParseDeclarationSpecifiersOrConceptDefinition(
       DeclSpec &DS,
       const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo(),
       AccessSpecifier AS = AS_none,
@@ -2811,6 +2820,11 @@ private:
                                    SourceLocation &DeclEnd,
                                    AccessSpecifier AS = AS_none);
 
+  /// \brief Parse a single template declaration that declares a concept [c++2a]
+  /// and store the AST node within DS.
+  void ParseConceptDefinition(SourceLocation ConceptLoc, DeclSpec &DS,
+                              const ParsedTemplateInfo &TemplateInfo,
+                              AccessSpecifier AS, DeclSpecContext DSC);
   //===--------------------------------------------------------------------===//
   // Modules
   DeclGroupPtrTy ParseModuleDecl();

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Tue Apr 24 19:42:26 2018
@@ -38,6 +38,7 @@
 namespace clang {
   class ASTContext;
   class CXXRecordDecl;
+  class ConceptDecl;
   class TypeLoc;
   class LangOptions;
   class IdentifierInfo;
@@ -221,10 +222,13 @@ public:
   unsigned location_size() const { return Builder.getBuffer().second; }
 };
 
-/// \brief Captures information about "declaration specifiers".
+/// \brief Captures information about "decl-specifiers" and also concept
+/// definitions.
 ///
 /// "Declaration specifiers" encompasses storage-class-specifiers,
-/// type-specifiers, type-qualifiers, and function-specifiers.
+/// type-specifiers, type-qualifiers, and function-specifiers. This includes
+/// class and enum definitions whose AST representations must be stored - same
+/// with the expression-operands of decltype.
 class DeclSpec {
 public:
   /// \brief storage-class-specifier
@@ -363,8 +367,14 @@ private:
   unsigned Constexpr_specified : 1;
 
   union {
+	// Valid if isTypeRep is true.
     UnionParsedType TypeRep;
+    // If we parsed a concept, class, enum (etc.) defintion or elaborated type
+    // specifier, this stores the AST representation.  This is valid if either
+    // isDeclRep or isConceptSpecified returns true.
     Decl *DeclRep;
+    // If we parsed a typeof(e) or decltype(e) operator, this stores the
+    // expression 'e'.  Valid if isExprRep is true.
     Expr *ExprRep;
   };
 
@@ -393,6 +403,11 @@ private:
   SourceLocation FS_forceinlineLoc;
   SourceLocation FriendLoc, ModulePrivateLoc, ConstexprLoc;
   SourceLocation TQ_pipeLoc;
+  
+  // Even though 'concept' is not a specifier, we handle it here. This allows us
+  // to reuse infrastructure for diagnosing attributes and invalid
+  // decl-specifiers.
+  SourceLocation ConceptLoc;
 
   WrittenBuiltinSpecs writtenBS;
   void SaveWrittenBuiltinSpecs();
@@ -482,7 +497,10 @@ public:
   bool isTypeSpecOwned() const { return TypeSpecOwned; }
   bool isTypeRep() const { return isTypeRep((TST) TypeSpecType); }
   bool isTypeSpecPipe() const { return TypeSpecPipe; }
-
+  bool isDeclRep() const {
+    return isDeclRep((TST)TypeSpecType);
+  }
+  
   ParsedType getRepAsType() const {
     assert(isTypeRep((TST) TypeSpecType) && "DeclSpec does not store a type");
     return TypeRep;
@@ -491,6 +509,17 @@ public:
     assert(isDeclRep((TST) TypeSpecType) && "DeclSpec does not store a decl");
     return DeclRep;
   }
+  // This is a template that should only be instantiated with the type
+  // ConceptDecl.  By making it a template we only require ConceptDecl to be a
+  // complete type where this function is called.
+  template<class ConceptDeclTy = ConceptDecl>
+  ConceptDeclTy *getRepAsConcept() const {
+    static_assert(std::is_same<ConceptDeclTy, ConceptDecl>::value,
+                  "Must only be instantiated with ConceptDecl");
+    assert(isConceptSpecified() && "DeclSpec does not store a concept");
+
+    return cast_or_null<ConceptDeclTy>(DeclRep);
+  }
   Expr *getRepAsExpr() const {
     assert(isExprRep((TST) TypeSpecType) && "DeclSpec does not store an expr");
     return ExprRep;
@@ -665,6 +694,19 @@ public:
     assert(isDeclRep((TST) TypeSpecType));
     DeclRep = Rep;
   }
+  // This function can only be instantiated with ConceptDecl.  We made it a
+  // template so that ConceptDecl only has to be defined where this is called.
+  template <class ConceptDeclTy = ConceptDecl>
+  void setConceptRep(ConceptDecl *Rep) {
+    static_assert(std::is_same<ConceptDeclTy, ConceptDecl>::value,
+                  "Must only be instantiated with ConceptDecl");
+    assert(isConceptSpecified() && "DeclSpec does not store a concept");
+    assert(!DeclRep &&
+           "why is this not null? We expect this function to be called only "
+           "once, and usually right after DeclRep was set to null");
+    DeclRep = Rep;
+  }
+  
   void UpdateTypeRep(ParsedType Rep) {
     assert(isTypeRep((TST) TypeSpecType));
     TypeRep = Rep;
@@ -694,6 +736,8 @@ public:
                             unsigned &DiagID);
   bool SetConstexprSpec(SourceLocation Loc, const char *&PrevSpec,
                         unsigned &DiagID);
+  bool setConceptSpec(SourceLocation Loc, const char *&PrevSpec,
+                      unsigned &DiagID, const PrintingPolicy &P);
 
   bool isFriendSpecified() const { return Friend_specified; }
   SourceLocation getFriendSpecLoc() const { return FriendLoc; }
@@ -704,6 +748,8 @@ public:
   bool isConstexprSpecified() const { return Constexpr_specified; }
   SourceLocation getConstexprSpecLoc() const { return ConstexprLoc; }
 
+  bool isConceptSpecified() const { return ConceptLoc.isValid(); }
+  SourceLocation getConceptLoc() const { return ConceptLoc; }
   void ClearConstexprSpec() {
     Constexpr_specified = false;
     ConstexprLoc = SourceLocation();

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Tue Apr 24 19:42:26 2018
@@ -2126,6 +2126,7 @@ public:
 
   Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
                                    RecordDecl *&AnonRecord);
+
   Decl *ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
                                    MultiTemplateParamsArg TemplateParams,
                                    bool IsExplicitInstantiation,
@@ -6229,6 +6230,13 @@ public:
                                 SourceLocation TemplateLoc,
                                 const TemplateArgumentListInfo *TemplateArgs);
 
+  ExprResult
+  CheckConceptTemplateId(const CXXScopeSpec &SS,
+                         const DeclarationNameInfo &NameInfo,
+                         ConceptDecl *Template,
+                         SourceLocation TemplateLoc,
+                         const TemplateArgumentListInfo *TemplateArgs);
+
   ExprResult BuildTemplateIdExpr(const CXXScopeSpec &SS,
                                  SourceLocation TemplateKWLoc,
                                  LookupResult &R,
@@ -6507,6 +6515,13 @@ public:
                                   const TemplateArgument *Args,
                                   unsigned NumArgs);
 
+  // Concepts
+  ConceptDecl *ActOnConceptDefinition(
+      Scope *S,
+      MultiTemplateParamsArg TemplateParameterLists,
+      IdentifierInfo *Name, SourceLocation NameLoc,
+      Expr *ConstraintExpr);
+
   //===--------------------------------------------------------------------===//
   // C++ Variadic Templates (C++0x [temp.variadic])
   //===--------------------------------------------------------------------===//

Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
+++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Tue Apr 24 19:42:26 2018
@@ -1408,6 +1408,9 @@ namespace serialization {
       /// \brief A TypeAliasTemplateDecl record.
       DECL_TYPE_ALIAS_TEMPLATE,
 
+      /// \brief A ConceptDecl record.
+      DECL_CONCEPT,
+
       /// \brief A StaticAssertDecl record.
       DECL_STATIC_ASSERT,
 

Modified: cfe/trunk/lib/AST/ASTDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTDumper.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTDumper.cpp (original)
+++ cfe/trunk/lib/AST/ASTDumper.cpp Tue Apr 24 19:42:26 2018
@@ -466,6 +466,7 @@ namespace  {
                                          bool DumpRefOnly);
     template<typename TemplateDecl>
     void VisitTemplateDecl(const TemplateDecl *D, bool DumpExplicitInst);
+    void VisitConceptDecl(const ConceptDecl *D);
     void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D);
     void VisitClassTemplateDecl(const ClassTemplateDecl *D);
     void VisitClassTemplateSpecializationDecl(
@@ -1577,6 +1578,12 @@ void ASTDumper::VisitTemplateDecl(const
                                     !D->isCanonicalDecl());
 }
 
+void ASTDumper::VisitConceptDecl(const ConceptDecl *D) {
+  dumpName(D);
+  dumpTemplateParameters(D->getTemplateParameters());
+  dumpStmt(D->getConstraintExpr());
+}
+
 void ASTDumper::VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
   // FIXME: We don't add a declaration of a function template specialization
   // to its context when it's explicitly instantiated, so dump explicit

Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Tue Apr 24 19:42:26 2018
@@ -724,6 +724,7 @@ unsigned Decl::getIdentifierNamespaceFor
     case Binding:
     case NonTypeTemplateParm:
     case VarTemplate:
+    case Concept:
       // These (C++-only) declarations are found by redeclaration lookup for
       // tag types, so we include them in the tag namespace.
       return IDNS_Ordinary | IDNS_Tag;

Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Tue Apr 24 19:42:26 2018
@@ -789,6 +789,27 @@ ClassTemplateSpecializationDecl::getSour
 }
 
 //===----------------------------------------------------------------------===//
+// ConceptDecl Implementation
+//===----------------------------------------------------------------------===//
+ConceptDecl *ConceptDecl::Create(ASTContext &C, DeclContext *DC,
+                                 SourceLocation NameLoc, DeclarationName Name,
+                                 TemplateParameterList *Params,
+                                 Expr *ConstraintExpr) {
+  // TODO: Do we need this?
+  //  AdoptTemplateParameterList(Params, cast<DeclContext>(Decl));
+  return new (C, DC) ConceptDecl(DC, NameLoc, Name, Params, ConstraintExpr);
+}
+
+ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C,
+                                             unsigned ID) {
+  ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(),
+                                                DeclarationName(),
+                                                nullptr, nullptr);
+
+  return Result;
+}
+
+//===----------------------------------------------------------------------===//
 // ClassTemplatePartialSpecializationDecl Implementation
 //===----------------------------------------------------------------------===//
 void ClassTemplatePartialSpecializationDecl::anchor() {}

Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDecl.cpp Tue Apr 24 19:42:26 2018
@@ -105,6 +105,7 @@ void CodeGenFunction::EmitDecl(const Dec
   case Decl::OMPThreadPrivate:
   case Decl::OMPCapturedExpr:
   case Decl::Empty:
+  case Decl::Concept:
     // None of these decls require codegen support.
     return;
 

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Tue Apr 24 19:42:26 2018
@@ -4423,6 +4423,7 @@ void CodeGenModule::EmitTopLevelDecl(Dec
   case Decl::TypeAliasTemplate:
   case Decl::Block:
   case Decl::Empty:
+  case Decl::Concept:
     break;
   case Decl::Using:          // using X; [C++]
     if (CGDebugInfo *DI = getModuleDebugInfo())

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Tue Apr 24 19:42:26 2018
@@ -1739,7 +1739,8 @@ Parser::ParseSimpleDeclaration(Declarato
   ParsingDeclSpec DS(*this);
 
   DeclSpecContext DSContext = getDeclSpecContextFromDeclaratorContext(Context);
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none, DSContext);
+  ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(),
+                                                       AS_none, DSContext);
 
   // If we had a free-standing type definition with a missing semicolon, we
   // may get this far before the problem becomes obvious.
@@ -2386,7 +2387,8 @@ void Parser::ParseSpecifierQualifierList
   /// specifier-qualifier-list is a subset of declaration-specifiers.  Just
   /// parse declaration-specifiers and complain about extra stuff.
   /// TODO: diagnose attribute-specifiers and alignment-specifiers.
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC);
+  ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(), AS,
+                                                DSC);
 
   // Validate declspec for type-name.
   unsigned Specs = DS.getParsedSpecifiers();
@@ -2871,11 +2873,12 @@ Parser::DiagnoseMissingSemiAfterTagDefin
   // and call ParsedFreeStandingDeclSpec as appropriate.
   DS.ClearTypeSpecType();
   ParsedTemplateInfo NotATemplate;
-  ParseDeclarationSpecifiers(DS, NotATemplate, AS, DSContext, LateAttrs);
+  ParseDeclarationSpecifiersOrConceptDefinition(DS, NotATemplate, AS, DSContext,
+                                      LateAttrs);
   return false;
 }
 
-/// ParseDeclarationSpecifiers
+/// ParseDeclarationSpecifiersOrConceptDefinition
 ///       declaration-specifiers: [C99 6.7]
 ///         storage-class-specifier declaration-specifiers[opt]
 ///         type-specifier declaration-specifiers[opt]
@@ -2902,7 +2905,8 @@ Parser::DiagnoseMissingSemiAfterTagDefin
 /// [OpenCL] '__kernel'
 ///       'friend': [C++ dcl.friend]
 ///       'constexpr': [C++0x dcl.constexpr]
-void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
+/// [C++2a] 'concept'
+void Parser::ParseDeclarationSpecifiersOrConceptDefinition(DeclSpec &DS,
                                         const ParsedTemplateInfo &TemplateInfo,
                                         AccessSpecifier AS,
                                         DeclSpecContext DSContext,
@@ -3680,7 +3684,11 @@ void Parser::ParseDeclarationSpecifiers(
       ConsumeToken();
       ParseEnumSpecifier(Loc, DS, TemplateInfo, AS, DSContext);
       continue;
-
+    
+    case tok::kw_concept:
+      ConsumeToken();
+      ParseConceptDefinition(Loc, DS, TemplateInfo, AS, DSContext);
+      continue;
     // cv-qualifier:
     case tok::kw_const:
       isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID,
@@ -6366,7 +6374,7 @@ void Parser::ParseParameterDeclarationCl
     // too much hassle.
     DS.takeAttributesFrom(FirstArgAttrs);
 
-    ParseDeclarationSpecifiers(DS);
+    ParseDeclarationSpecifiersOrConceptDefinition(DS);
 
 
     // Parse the declarator.  This is "PrototypeContext" or 

Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Tue Apr 24 19:42:26 2018
@@ -2561,8 +2561,8 @@ Parser::ParseCXXClassMemberDeclaration(A
   if (MalformedTypeSpec)
     DS.SetTypeSpecError();
 
-  ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DeclSpecContext::DSC_class,
-                             &CommonLateParsedAttrs);
+  ParseDeclarationSpecifiersOrConceptDefinition(
+      DS, TemplateInfo, AS, DeclSpecContext::DSC_class, &CommonLateParsedAttrs);
 
   // Turn off colon protection that was set for declspec.
   X.restore();

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Tue Apr 24 19:42:26 2018
@@ -1490,7 +1490,7 @@ Decl *Parser::ParseObjCMethodDecl(Source
       cStyleParamWarned = true;
     }
     DeclSpec DS(AttrFactory);
-    ParseDeclarationSpecifiers(DS);
+    ParseDeclarationSpecifiersOrConceptDefinition(DS);
     // Parse the declarator.
     Declarator ParmDecl(DS, DeclaratorContext::PrototypeContext);
     ParseDeclarator(ParmDecl);
@@ -2541,7 +2541,7 @@ StmtResult Parser::ParseObjCTryStmt(Sour
                                         Scope::AtCatchScope);
         if (Tok.isNot(tok::ellipsis)) {
           DeclSpec DS(AttrFactory);
-          ParseDeclarationSpecifiers(DS);
+          ParseDeclarationSpecifiersOrConceptDefinition(DS);
           Declarator ParmDecl(DS, DeclaratorContext::ObjCCatchContext);
           ParseDeclarator(ParmDecl);
 

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Apr 24 19:42:26 2018
@@ -54,6 +54,15 @@ Parser::ParseDeclarationStartingWithTemp
 ///       template-declaration: [C++ temp]
 ///         'export'[opt] 'template' '<' template-parameter-list '>' declaration
 ///
+///       template-declaration: [C++2a]
+///         template-head declaration
+///         template-head concept-definition
+///
+///       TODO: requires-clause
+///       template-head: [C++2a]
+///         'export'[opt] 'template' '<' template-parameter-list '>'
+///             requires-clause[opt]
+///
 ///       explicit-specialization: [ C++ temp.expl.spec]
 ///         'template' '<' '>' declaration
 Decl *
@@ -148,13 +157,10 @@ Parser::ParseTemplateDeclarationOrSpecia
   unsigned NewFlags = getCurScope()->getFlags() & ~Scope::TemplateParamScope;
   ParseScopeFlags TemplateScopeFlags(this, NewFlags, isSpecialization);
 
-  // Parse the actual template declaration.
-  return ParseSingleDeclarationAfterTemplate(Context,
-                                             ParsedTemplateInfo(&ParamLists,
-                                                             isSpecialization,
-                                                         LastParamListWasEmpty),
-                                             ParsingTemplateParams,
-                                             DeclEnd, AS, AccessAttrs);
+  return ParseSingleDeclarationAfterTemplate(
+      Context,
+      ParsedTemplateInfo(&ParamLists, isSpecialization, LastParamListWasEmpty),
+      ParsingTemplateParams, DeclEnd, AS, AccessAttrs);
 }
 
 /// \brief Parse a single declaration that declares a template,
@@ -208,7 +214,7 @@ Parser::ParseSingleDeclarationAfterTempl
   // the template parameters.
   ParsingDeclSpec DS(*this, &DiagsFromTParams);
 
-  ParseDeclarationSpecifiers(DS, TemplateInfo, AS,
+  ParseDeclarationSpecifiersOrConceptDefinition(DS, TemplateInfo, AS,
                              getDeclSpecContextFromDeclaratorContext(Context));
 
   if (Tok.is(tok::semi)) {
@@ -322,6 +328,149 @@ Parser::ParseSingleDeclarationAfterTempl
   return ThisDecl;
 }
 
+
+void
+Parser::ParseConceptDefinition(SourceLocation ConceptLoc,
+                           DeclSpec &DS, const ParsedTemplateInfo &TemplateInfo,
+                           AccessSpecifier AS, 
+                           DeclSpecContext DSC) {
+
+  
+  auto DiagnoseAttributes = [this] {
+    ParsedAttributesWithRange attrs(this->AttrFactory);
+    this->MaybeParseGNUAttributes(attrs);
+    this->MaybeParseCXX11Attributes(attrs);
+    this->MaybeParseMicrosoftDeclSpecs(attrs);
+    this->ProhibitAttributes(attrs);
+  };
+
+
+  // If attributes exist after 'concept' kw but before the concept name,
+  // prohibit them for now (if CWG approves attributes on concepts, this is
+  // likely where they will go...).
+  DiagnoseAttributes();
+
+  // Set the concept specifier at ConceptLoc within 'DS' along with emitting any
+  // incompatible decl-specifier diagnostics.
+  {
+    const char *PrevSpec = 0;
+    unsigned int DiagId = 0;
+    if (DS.setConceptSpec(ConceptLoc, PrevSpec, DiagId,
+                          Actions.getASTContext().getPrintingPolicy())) {
+      Diag(ConceptLoc, DiagId) << PrevSpec;
+    }
+    Actions.DiagnoseFunctionSpecifiers(DS);
+  }
+
+  if (DSC != DeclSpecContext::DSC_top_level) {
+    Diag(ConceptLoc, diag::err_concept_at_non_namespace_scope);
+    // If we are not in a template parameter context, skip to a '}' or ';'. The
+    // error messages are better if we just ignore this within template
+    // parameter lists.
+    if (DSC != DeclSpecContext::DSC_template_param) {
+      SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+    } else {
+      SkipUntil(llvm::makeArrayRef({tok::comma, tok::greater}),
+                StopAtSemi | StopBeforeMatch);
+    }
+    return;
+  }
+
+  // A scope-guard that (if an error occurs while parsing a concept) skips to
+  // the next semi or closing brace.
+  class SkipUntilSemiOrClosingBraceOnScopeExit {
+    Parser &P;
+    bool Disabled = false;
+
+  public:
+    SkipUntilSemiOrClosingBraceOnScopeExit(Parser &P)
+        : P(P) {}
+    void disable() { Disabled = true; }
+    ~SkipUntilSemiOrClosingBraceOnScopeExit() {
+      if (!Disabled) {
+        // Skip until the semi-colon or a '}'.
+        P.SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch);
+      }
+    }
+  } SkipUntilSemiOrClosingBraceOnScopeExit(*this);
+
+  if (TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate) {
+    Diag(ConceptLoc, diag::err_concept_nontemplate);
+    return;
+  }
+  
+  const TemplateParameterLists &ParamLists = *TemplateInfo.TemplateParams;
+
+  
+  // More than one TPL wouldn't make sense here.
+  if (ParamLists.size() != 1) {
+    Diag(Tok.getLocation(), diag::err_concept_extra_headers);
+    return;
+  }
+  const TemplateParameterList *const TPL = ParamLists[0];
+
+  // Explicit specializations of concepts are not allowed.
+  if (TPL->getLAngleLoc().getLocWithOffset(1) == TPL->getRAngleLoc()) {
+    assert(!TPL->size() &&
+           "can not have template parameters within empty angle brackets!");
+    Diag(ConceptLoc, diag::err_concept_specialized) << 0;
+    return;
+  }
+  // Concepts can not be defined with nested name specifiers.
+  CXXScopeSpec SS;
+  if (ParseOptionalCXXScopeSpecifier(SS, nullptr,
+                                     /*EnteringContext=*/false) ||
+      SS.isNotEmpty()) {
+
+    if (SS.isNotEmpty())
+      Diag(Tok.getLocation(), diag::err_concept_unexpected_scope_spec);
+    return;
+  }
+  // An identifier (i.e. the concept-name) should follow 'concept'.
+  if (!Tok.is(tok::identifier)) {
+    Diag(Tok.getLocation(), diag::err_expected) << "concept name";
+    return;
+  }
+
+  IdentifierInfo *Id = Tok.getIdentifierInfo();
+  SourceLocation IdLoc = ConsumeToken();
+  
+  // If attributes exist after the identifier, parse them and diagnose
+  DiagnoseAttributes();
+
+  if (!TryConsumeToken(tok::equal)) {
+    Diag(Tok.getLocation(), diag::err_expected) << "equal";
+    return;
+  }
+
+  ExprResult ConstraintExprResult = ParseConstraintExpression();
+  if (ConstraintExprResult.isInvalid()) {
+    Diag(Tok.getLocation(), diag::err_expected_expression)
+      << "constraint-expression";
+    return;
+  }
+
+  // We can try to create a valid concept decl node now, so disable the
+  // scope-guard.
+  SkipUntilSemiOrClosingBraceOnScopeExit.disable();
+
+  Expr *ConstraintExpr = ConstraintExprResult.get();
+  ConceptDecl *const ConDecl = Actions.ActOnConceptDefinition(
+      getCurScope(), *TemplateInfo.TemplateParams, Id, IdLoc, ConstraintExpr);
+  DS.setConceptRep(ConDecl);
+
+  if (Tok.isNot(tok::semi)) {
+    
+    ExpectAndConsume(tok::semi, diag::err_expected_after, "concept");
+    // Push this token back into the preprocessor and change our current token
+    // to ';' so that the rest of the code recovers as though there were an
+    // ';' after the definition.
+    PP.EnterToken(Tok);
+    Tok.setKind(tok::semi);
+  }
+  return;
+}
+
 /// ParseTemplateParameters - Parses a template-parameter-list enclosed in
 /// angle brackets. Depth is the depth of this template-parameter-list, which
 /// is the number of template headers directly enclosing this template header.
@@ -690,8 +839,8 @@ Parser::ParseNonTypeTemplateParameter(un
   // FIXME: The type should probably be restricted in some way... Not all
   // declarators (parts of declarators?) are accepted for parameters.
   DeclSpec DS(AttrFactory);
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS_none,
-                             DeclSpecContext::DSC_template_param);
+  ParseDeclarationSpecifiersOrConceptDefinition(
+      DS, ParsedTemplateInfo(), AS_none, DeclSpecContext::DSC_template_param);
 
   // Parse this as a typename.
   Declarator ParamDecl(DS, DeclaratorContext::TemplateParamContext);

Modified: cfe/trunk/lib/Parse/ParseTentative.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTentative.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Tue Apr 24 19:42:26 2018
@@ -1351,6 +1351,7 @@ Parser::isCXXDeclarationSpecifier(Parser
   case tok::kw_struct:
   case tok::kw_union:
   case tok::kw___interface:
+  case tok::kw_concept:
     // enum-specifier
   case tok::kw_enum:
     // cv-qualifier

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Apr 24 19:42:26 2018
@@ -919,7 +919,7 @@ Parser::ParseDeclOrFunctionDefInternal(P
                                        AccessSpecifier AS) {
   MaybeParseMicrosoftAttributes(DS.getAttributes());
   // Parse the common declaration-specifiers piece.
-  ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS,
+  ParseDeclarationSpecifiersOrConceptDefinition(DS, ParsedTemplateInfo(), AS,
                              DeclSpecContext::DSC_top_level);
 
   // If we had a free-standing type definition with a missing semicolon, we
@@ -1287,7 +1287,7 @@ void Parser::ParseKNRParamDeclarations(D
 
     // Parse the common declaration-specifiers piece.
     DeclSpec DS(AttrFactory);
-    ParseDeclarationSpecifiers(DS);
+    ParseDeclarationSpecifiersOrConceptDefinition(DS);
 
     // C99 6.9.1p6: 'each declaration in the declaration list shall have at
     // least one declarator'.
@@ -1647,7 +1647,7 @@ bool Parser::TryKeywordIdentFallback(boo
 /// Actions.getTypeName will not be needed to be called again (e.g. getTypeName
 /// will not be called twice, once to check whether we have a declaration
 /// specifier, and another one to get the actual type inside
-/// ParseDeclarationSpecifiers).
+/// ParseDeclarationSpecifiersOrConceptDefinition).
 ///
 /// This returns true if an error occurred.
 ///

Modified: cfe/trunk/lib/Sema/DeclSpec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/DeclSpec.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/DeclSpec.cpp (original)
+++ cfe/trunk/lib/Sema/DeclSpec.cpp Tue Apr 24 19:42:26 2018
@@ -426,6 +426,7 @@ unsigned DeclSpec::getParsedSpecifiers()
   return Res;
 }
 
+
 template <class T> static bool BadSpecifier(T TNew, T TPrev,
                                             const char *&PrevSpec,
                                             unsigned &DiagID,
@@ -491,7 +492,6 @@ const char *DeclSpec::getSpecifierName(T
   }
   llvm_unreachable("Unknown typespec!");
 }
-
 const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
                                        const PrintingPolicy &Policy) {
   switch (T) {
@@ -969,6 +969,69 @@ bool DeclSpec::SetConstexprSpec(SourceLo
   return false;
 }
 
+bool DeclSpec::setConceptSpec(const SourceLocation Loc, const char *&PrevSpec,
+                              unsigned &DiagID, const PrintingPolicy &PP) {
+  assert(Loc.isValid() && "Loc must be valid, since it is used to identify "
+                          "that this function was called before");
+  assert(!ConceptLoc.isValid() &&
+         "how is this called if concept was already encountered and triggered "
+         "ParseConceptDefinition which parses upto the semi-colon");
+
+  PrevSpec = nullptr;
+  if (TypeSpecType != TST_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName(static_cast<TST>(TypeSpecType), PP);
+	  ClearTypeSpecType();
+  }
+  if (TypeSpecSign != TSS_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName(static_cast<TSS>(TypeSpecSign));
+	  TypeSpecSign = TSS_unspecified;
+  }
+  if (TypeSpecWidth != TSW_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName(static_cast<TSW>(TypeSpecWidth));
+	  TypeSpecWidth = TSW_unspecified;
+  }
+  if (StorageClassSpec != SCS_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName(static_cast<SCS>(StorageClassSpec));
+	  ClearStorageClassSpecs();
+  }
+  if (ThreadStorageClassSpec != TSCS_unspecified) {
+    PrevSpec =
+        DeclSpec::getSpecifierName(static_cast<TSCS>(ThreadStorageClassSpec));
+    ClearStorageClassSpecs();
+  }
+  if (TypeSpecComplex != TSC_unspecified) {
+    PrevSpec = DeclSpec::getSpecifierName(static_cast<TSC>(TypeSpecComplex));
+    TypeSpecComplex = TSC_unspecified;
+  }
+  if (getTypeQualifiers()) {
+	  PrevSpec = DeclSpec::getSpecifierName(static_cast<TQ>(TypeQualifiers));
+    ClearTypeQualifiers();
+  }
+  if (isFriendSpecified()) {
+    PrevSpec = "friend";
+    Friend_specified = false;
+    FriendLoc = SourceLocation();
+  }
+  if (isConstexprSpecified()) {
+    PrevSpec = "constexpr";
+    Constexpr_specified = false;
+    ConstexprLoc = SourceLocation();
+  }
+  if (isInlineSpecified()) {
+    PrevSpec = "inline";
+    FS_inlineLoc = SourceLocation();
+    FS_inline_specified = false;
+  }
+
+  if (PrevSpec) {
+    DiagID = diag::err_invalid_decl_spec_combination;
+  }
+  // We set the concept location regardless of whether an error occurred.
+  DeclRep = nullptr;
+  ConceptLoc = Loc;
+  return PrevSpec; // If this is non-null, an error occurred.
+}
+
 void DeclSpec::SaveWrittenBuiltinSpecs() {
   writtenBS.Sign = getTypeSpecSign();
   writtenBS.Width = getTypeSpecWidth();
@@ -1270,6 +1333,7 @@ void DeclSpec::Finish(Sema &S, const Pri
   // TODO: return "auto function" and other bad things based on the real type.
 
   // 'data definition has no type or storage class'?
+
 }
 
 bool DeclSpec::isMissingDeclaratorOk() {

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Apr 24 19:42:26 2018
@@ -4212,6 +4212,12 @@ Sema::ParsedFreeStandingDeclSpec(Scope *
                                  MultiTemplateParamsArg TemplateParams,
                                  bool IsExplicitInstantiation,
                                  RecordDecl *&AnonRecord) {
+
+  // We don't need to do any additional declspecifier checking on concept
+  // definitions since that should already have been done when the concept kw
+  // location was set within DS.
+  if (DS.isConceptSpecified()) return DS.getRepAsConcept();
+  
   Decl *TagD = nullptr;
   TagDecl *Tag = nullptr;
   if (DS.getTypeSpecType() == DeclSpec::TST_class ||

Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Tue Apr 24 19:42:26 2018
@@ -9467,7 +9467,7 @@ UsingShadowDecl *Sema::BuildUsingShadowD
     NonTemplateTarget = TargetTD->getTemplatedDecl();
 
   UsingShadowDecl *Shadow;
-  if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+  if (!isa<ConceptDecl>(Target) && isa<CXXConstructorDecl>(NonTemplateTarget)) {
     bool IsVirtualBase =
         isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
                             UD->getQualifier()->getAsRecordDecl());

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Apr 24 19:42:26 2018
@@ -232,9 +232,11 @@ TemplateNameKind Sema::isTemplateName(Sc
     } else {
       assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
              isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) ||
-             isa<BuiltinTemplateDecl>(TD));
+             isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD));
       TemplateKind =
-          isa<VarTemplateDecl>(TD) ? TNK_Var_template : TNK_Type_template;
+          isa<VarTemplateDecl>(TD) ? TNK_Var_template :
+          isa<ConceptDecl>(TD) ? TNK_Concept_template :
+          TNK_Type_template;
     }
   }
 
@@ -3034,7 +3036,8 @@ QualType Sema::CheckTemplateIdType(Templ
 
   TemplateDecl *Template = Name.getAsTemplateDecl();
   if (!Template || isa<FunctionTemplateDecl>(Template) ||
-      isa<VarTemplateDecl>(Template)) {
+      isa<VarTemplateDecl>(Template) ||
+      isa<ConceptDecl>(Template)) {
     // We might have a substituted template template parameter pack. If so,
     // build a template specialization type for it.
     if (Name.getAsSubstTemplateTemplateParmPack())
@@ -3988,6 +3991,18 @@ Sema::CheckVarTemplateId(const CXXScopeS
                                   /*FoundD=*/nullptr, TemplateArgs);
 }
 
+ExprResult
+Sema::CheckConceptTemplateId(const CXXScopeSpec &SS,
+                             const DeclarationNameInfo &NameInfo,
+                             ConceptDecl *Template,
+                             SourceLocation TemplateLoc,
+                             const TemplateArgumentListInfo *TemplateArgs) {
+  // TODO: Do concept specialization here.
+  Diag(Template->getLocation(), diag::err_concept_feature_unimplemented)
+      << "can not form concept template-id";
+  return ExprError();
+}
+
 ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
                                      SourceLocation TemplateKWLoc,
                                      LookupResult &R,
@@ -4009,14 +4024,21 @@ ExprResult Sema::BuildTemplateIdExpr(con
 
   // In C++1y, check variable template ids.
   bool InstantiationDependent;
-  if (R.getAsSingle<VarTemplateDecl>() &&
-      !TemplateSpecializationType::anyDependentTemplateArguments(
-           *TemplateArgs, InstantiationDependent)) {
+  const bool DependentArguments =
+    TemplateSpecializationType::anyDependentTemplateArguments(
+      *TemplateArgs, InstantiationDependent);
+  if (R.getAsSingle<VarTemplateDecl>() && !DependentArguments) {
     return CheckVarTemplateId(SS, R.getLookupNameInfo(),
                               R.getAsSingle<VarTemplateDecl>(),
                               TemplateKWLoc, TemplateArgs);
   }
 
+  if (R.getAsSingle<ConceptDecl>() && !DependentArguments) {
+    return CheckConceptTemplateId(SS, R.getLookupNameInfo(),
+                                  R.getAsSingle<ConceptDecl>(),
+                                  TemplateKWLoc, TemplateArgs);
+  }
+
   // We don't want lookup warnings at this point.
   R.suppressDiagnostics();
 
@@ -7688,6 +7710,61 @@ Decl *Sema::ActOnTemplateDeclarator(Scop
   return NewDecl;
 }
 
+ConceptDecl *Sema::ActOnConceptDefinition(Scope *S,
+    MultiTemplateParamsArg TemplateParameterLists, IdentifierInfo *Name,
+    SourceLocation NameLoc, Expr *ConstraintExpr) {
+  // C++2a [temp.concept]p3:
+  // A concept-definition shall appear in the global scope or in a namespace
+  // scope.
+  assert(
+      CurContext->isFileContext() &&
+      "We check during parsing that 'concept's only occur at namespace scope");
+
+  // Forbid any prior declaration of this name within the current namespace.
+  LookupResult Previous(*this,
+                        DeclarationNameInfo(DeclarationName(Name), NameLoc),
+                        LookupOrdinaryName);
+  LookupName(Previous, S);
+  if (!Previous.empty()) {
+    const NamedDecl *PrevDecl = Previous.getRepresentativeDecl();
+    if (PrevDecl->getDeclContext()->Equals(CurContext)) {
+      if (Previous.isSingleResult() &&
+          isa<ConceptDecl>(Previous.getFoundDecl())) {
+        Diag(NameLoc, diag::err_redefinition) << Name;
+      } else {
+        Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
+      }
+      Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl;
+      return nullptr;
+    }
+  }
+
+  ConceptDecl *NewDecl = ConceptDecl::Create(Context, CurContext, NameLoc,
+                                             Name, TemplateParameterLists[0],
+                                             ConstraintExpr);
+
+  if (!NewDecl)
+    return nullptr;
+
+  if (NewDecl->getAssociatedConstraints()) {
+    // C++2a [temp.concept]p4:
+    // A concept shall not have associated constraints.
+    // TODO: Make a test once we have actual associated constraints.
+    Diag(NameLoc, diag::err_concept_no_associated_constraints);
+    NewDecl->setInvalidDecl();
+  }
+
+  assert((S->isTemplateParamScope() || !TemplateParameterLists[0]->size()) &&
+         "Not in template param scope?");
+  assert(S->getParent() && !S->getParent()->isTemplateParamScope() &&
+         "Parent scope should exist and not be template parameter.");
+
+  ActOnDocumentableDecl(NewDecl);
+  PushOnScopeChains(NewDecl, S->getParent(), /*AddToContext=*/true);
+
+  return NewDecl;
+}
+
 /// \brief Strips various properties off an implicit instantiation
 /// that has just been explicitly specialized.
 static void StripImplicitInstantiation(NamedDecl *D) {

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Apr 24 19:42:26 2018
@@ -3073,6 +3073,11 @@ Decl *TemplateDeclInstantiator::VisitFri
   return nullptr;
 }
 
+Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) {
+  llvm_unreachable("Concept definitions cannot reside inside a template");
+  return nullptr;
+}
+
 Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) {
   llvm_unreachable("Unexpected decl");
 }

Modified: cfe/trunk/lib/Serialization/ASTCommon.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTCommon.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTCommon.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTCommon.cpp Tue Apr 24 19:42:26 2018
@@ -313,6 +313,7 @@ bool serialization::isRedeclarableDeclKi
   case Decl::BuiltinTemplate:
   case Decl::Decomposition:
   case Decl::Binding:
+  case Decl::Concept:
     return false;
 
   // These indirectly derive from Redeclarable<T> but are not actually

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Tue Apr 24 19:42:26 2018
@@ -381,6 +381,7 @@ namespace clang {
     void VisitBindingDecl(BindingDecl *BD);
     void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
     DeclID VisitTemplateDecl(TemplateDecl *D);
+    void VisitConceptDecl(ConceptDecl *D);
     RedeclarableResult VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D);
@@ -2031,6 +2032,11 @@ DeclID ASTDeclReader::VisitTemplateDecl(
   return PatternID;
 }
 
+void ASTDeclReader::VisitConceptDecl(ConceptDecl *D) {
+  VisitTemplateDecl(D);
+  D->setConstraintExpr(Record.readExpr());
+}
+
 ASTDeclReader::RedeclarableResult
 ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   RedeclarableResult Redecl = VisitRedeclarable(D);
@@ -3595,6 +3601,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID I
   case DECL_TYPE_ALIAS_TEMPLATE:
     D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_CONCEPT:
+    D = ConceptDecl::CreateDeserialized(Context, ID);
+    break;
   case DECL_STATIC_ASSERT:
     D = StaticAssertDecl::CreateDeserialized(Context, ID);
     break;

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Tue Apr 24 19:42:26 2018
@@ -1280,6 +1280,7 @@ void ASTWriter::WriteBlockInfoBlock() {
   RECORD(DECL_TEMPLATE_TYPE_PARM);
   RECORD(DECL_NON_TYPE_TEMPLATE_PARM);
   RECORD(DECL_TEMPLATE_TEMPLATE_PARM);
+  RECORD(DECL_CONCEPT);
   RECORD(DECL_TYPE_ALIAS_TEMPLATE);
   RECORD(DECL_STATIC_ASSERT);
   RECORD(DECL_CXX_BASE_SPECIFIERS);

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Tue Apr 24 19:42:26 2018
@@ -102,6 +102,7 @@ namespace clang {
     void VisitBindingDecl(BindingDecl *D);
     void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D);
     void VisitTemplateDecl(TemplateDecl *D);
+    void VisitConceptDecl(ConceptDecl *D);
     void VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D);
     void VisitClassTemplateDecl(ClassTemplateDecl *D);
     void VisitVarTemplateDecl(VarTemplateDecl *D);
@@ -1395,6 +1396,12 @@ void ASTDeclWriter::VisitTemplateDecl(Te
   Record.AddTemplateParameterList(D->getTemplateParameters());
 }
 
+void ASTDeclWriter::VisitConceptDecl(ConceptDecl *D) {
+  VisitTemplateDecl(D);
+  Record.AddStmt(D->getConstraintExpr());
+  Code = serialization::DECL_CONCEPT;
+}
+
 void ASTDeclWriter::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) {
   VisitRedeclarable(D);
 

Removed: cfe/trunk/test/Parser/cxx-concept-declaration.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-concept-declaration.cpp?rev=330793&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx-concept-declaration.cpp (original)
+++ cfe/trunk/test/Parser/cxx-concept-declaration.cpp (removed)
@@ -1,7 +0,0 @@
-
-// Support parsing of concepts
-// Disabled for now.
-// expected-no-diagnostics
-
-// RUN:  %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s
-// template<typename T> concept C1 = true;

Added: cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp?rev=330794&view=auto
==============================================================================
--- cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp (added)
+++ cfe/trunk/test/Parser/cxx2a-concept-declaration.cpp Tue Apr 24 19:42:26 2018
@@ -0,0 +1,83 @@
+// RUN:  %clang_cc1 -std=c++2a -fconcepts-ts -verify %s
+// Support parsing of concepts
+
+concept X;  //expected-error {{must be a template}}
+
+template<typename T> concept C1 = true; //expected-note{{declared here}}  <-- previous declaration
+
+template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}
+
+template<concept T> concept D1 = true; // expected-error {{'concept' can only appear in namespace scope}} \
+                                          expected-error {{expected template parameter}}
+
+template<> concept X = true; // expected-error {{cannot be explicitly specialized}}
+
+namespace ns1 {
+template<> concept D1 = true;  // expected-error {{cannot be explicitly specialized}}
+template<typename T> const concept C1 = true; //expected-error{{cannot combine with}}
+namespace ns12 {
+template<typename T> decltype(T{}) concept C2 = true; //expected-error{{cannot combine with}}
+template<typename T> bool concept C3 = true; //expected-error{{cannot combine with}}
+template<typename T> unsigned concept C4 = true; //expected-error{{cannot combine with}}
+template<typename T> short concept C5 = true; //expected-error{{cannot combine with}}
+template<typename T> typedef concept C6 = true; //expected-error{{cannot combine with}}
+}
+template<class> concept 
+                        const  //expected-error{{expected concept name}}
+						      C2 = true; 
+							  
+void f() {
+	concept X; //expected-error{{'concept' can only appear in namespace scope}}
+}
+template<concept X,  //expected-error{{'concept' can only appear in namespace scope}} \
+                                          expected-error {{expected template parameter}}
+				  int J> void f();
+}
+
+template<class T>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}
+
+namespace ns2 {
+template<class T>
+concept [[test]] X2 [[test2]] = T::value; //expected-error2{{attribute list cannot appear here}}
+	
+}
+
+namespace ns3 {
+   template<typename T> concept C1 = true; 
+
+  namespace ns1 {
+	using ns3::C1; //expected-note{{declared here}}
+	template<typename T> concept C1 = true; // expected-error {{redefinition of 'C1'}}
+  }
+
+}
+
+// TODO:
+// template<typename T> concept C2 = 0.f; // expected error {{constraint expression must be 'bool'}}
+
+struct S1 {
+  template<typename T> concept C1 = true; // expected-error {{can only appear in namespace scope}}
+};
+
+template<typename A>
+template<typename B>
+concept C4 = true; // expected-error {{extraneous template parameter list in concept definition}}
+
+template<typename T> concept C5 = true; // expected-note {{previous}} expected-note {{previous}}
+int C5; // expected-error {{redefinition}}
+struct C5 {}; // expected-error {{redefinition}}
+
+struct C6 {}; //expected-note{{declared here}}  <-- previous declaration
+template<typename T> concept C6 = true; // expected-error {{redefinition of 'C6' as different kind of symbol}}
+
+namespace thing {};
+
+template<typename T> concept thing::C7 = true;  // expected-error {{concepts must be defined in their own namespace}}
+
+
+namespace ns5 {
+}
+
+// TODO: Add test to prevent explicit specialization, partial specialization
+// and explicit instantiation of concepts.

Modified: cfe/trunk/tools/libclang/CIndex.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=330794&r1=330793&r2=330794&view=diff
==============================================================================
--- cfe/trunk/tools/libclang/CIndex.cpp (original)
+++ cfe/trunk/tools/libclang/CIndex.cpp Tue Apr 24 19:42:26 2018
@@ -6173,6 +6173,7 @@ CXCursor clang_getCursorDefinition(CXCur
   case Decl::PragmaComment:
   case Decl::PragmaDetectMismatch:
   case Decl::UsingPack:
+  case Decl::Concept:
     return C;
 
   // Declaration kinds that don't make any sense here, but are




More information about the cfe-commits mailing list