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