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

Faisal Vali via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 25 13:59:42 PDT 2018


On Wed, Apr 25, 2018 at 3:37 PM, Richard Smith <richard at metafoo.co.uk> wrote:
> 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.
>
>
> Is that really worth it? This seems to add complexity to decl-specifier-seq
> / declarator parsing for a construct that has nothing to do with those
> things. I prefer the simpler approach in changyu's patch. I don't think the
> diagnostics you're producing are worthwhile -- the problem is not that
> "concept" can't be combined with other specifiers, it's that it's a
> fundamentally different kind of construct (just like "using X = ...", which
> it's much more like than it is like a declarator declaration).
>

I wouldn't say that I'm certain it's worth it - but then it also
didn't seem to me that the complexity tax being paid was that high
(but probably because my bias leans towards overly-diagnosticating for
users who are still learning the syntax of the language - and i can
imagine folks trying to add types to concept declarations or
attributes - which we may choose to allow in the future..)

Eitherway - I really don't feel strongly about this - just felt it
might be a better service to provide our users - but I do see your
point and the coherence concerns regarding our structure and since you
do feel strongly about it, i'll replace it with changyu's approach.

Sorry about that and thanks for the feedback!


>> 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
>>
>>
>> _______________________________________________
>> cfe-commits mailing list
>> cfe-commits at lists.llvm.org
>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
>


More information about the cfe-commits mailing list