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 13:37: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.
>

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).

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 = 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
> +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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180425/7ed9013c/attachment-0001.html>


More information about the cfe-commits mailing list