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

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 25 14:10:24 PDT 2018


On 24 April 2018 at 19:42, Faisal Vali via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> 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">;
>

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:

<source>:2:7: error: name defined in alias declaration must be an identifier
using N::a = int;
      ^~~

... which is admittedly also not very good, but making the two consistent
seems like a good idea.

+def err_concept_nontemplate : Error<"concept definition must be a
> template; "
> +                                    "missing template parameter list">;
>

This is not how we wrap lines in .td files :)


> +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">;
>

I don't think we need/want single-quotes around "concept" in these. We're
talking about concepts abstractly, not the 'concept' keyword.


> +}
> +
>  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'">;
>

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:

"constraint expression is of type '%0' but must be of type 'bool'"


> +def err_concept_no_associated_constraints : Error<
> +  "concept may not have associated constraints">;
>

may not -> cannot. This is a restriction, not a permission.


> +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 = getDeclSpecContextFromDeclarat
> orContext(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,
>                               getDeclSpecContextFromDeclarat
> orContext(Context));
>
>    if (Tok.is(tok::semi)) {
> @@ -322,6 +328,149 @@ Parser::ParseSingleDeclarationAfterTempl
>    return ThisDecl;
>  }
>
> +
> +void
>

Shouldn't this be returning a Decl*? This approach is presumably failing to
hand the declaration off to ActOnTopLevelDecl in the outer parse loop.


> +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);
> +  };
>

Why the explicit "this->"s here?

+
> +
> +  // 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) {
>

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.


> +      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);
>

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.


> +  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()) {
>

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.


> +    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";
>

This is not acceptable; diagnostics should be localizable, so you should
not use English phrases here.


> +    return;
> +  }
> +
> +  IdentifierInfo *Id = Tok.getIdentifierInfo();
> +  SourceLocation IdLoc = ConsumeToken();
> +
> +  // If attributes exist after the identifier, parse them and diagnose
>

Missing period at end of comment.


> +  DiagnoseAttributes();
> +
> +  if (!TryConsumeToken(tok::equal)) {
> +    Diag(Tok.getLocation(), diag::err_expected) << "equal";
>

This is likewise wrong. You can use tok::equal, or "'='", but not the
English word "equal".


> +    return;
> +  }
> +
> +  ExprResult ConstraintExprResult = ParseConstraintExpression();
> +  if (ConstraintExprResult.isInvalid()) {
> +    Diag(Tok.getLocation(), diag::err_expected_expression)
> +      << "constraint-expression";
>

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.

+    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");
>

Again, the use of "concept" here is inappropriate.


> +    // 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);
>

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.


> +    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))
> {
>

Is the problem here that NonTemplateTarget is null for a ConceptDecl? If
so, please express that directly with a null check.


>      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");
>

This assert is incorrect; concept definitions can also appear in
ExportDecls, for instance.


> +
> +  // 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;
>

This is impossible.


> +  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();
> +  }
>

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.


> +  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;
>

This return statement is dead code, remove it.


> +}
> +
>  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
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180425/4812bce0/attachment-0001.html>


More information about the cfe-commits mailing list