Author: nwilson Date: Sun Feb 7 23:34:00 2016 New Revision: 260074 URL: http://llvm.org/viewvc/llvm-project?rev=260074&view=rev Log: [Concepts] Implement a portion of Concepts TS[dcl.spec.concept]p1 by diagnosing when 'concept' is specified on a function or template specialization.
Since a concept can only be applied to a function or variable template, the concept bit is stored in TemplateDecl as a PointerIntPair. Reviewers: rsmith, faisalv, aaron.ballman, hubert.reinterpretcast Differential Revision: http://reviews.llvm.org/D13357 Modified: cfe/trunk/include/clang/AST/DeclTemplate.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaTemplate.cpp cfe/trunk/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp Modified: cfe/trunk/include/clang/AST/DeclTemplate.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=260074&r1=260073&r2=260074&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/DeclTemplate.h (original) +++ cfe/trunk/include/clang/AST/DeclTemplate.h Sun Feb 7 23:34:00 2016 @@ -332,24 +332,23 @@ class TemplateDecl : public NamedDecl { void anchor() override; protected: // This is probably never used. - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName Name) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), - TemplateParams(nullptr) {} + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false), + TemplateParams(nullptr) {} // Construct a template decl with the given name and parameters. // Used when there is not templated element (tt-params). - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName Name, TemplateParameterList *Params) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr), - TemplateParams(Params) {} + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(nullptr, false), + TemplateParams(Params) {} // Construct a template decl with name, parameters, and templated element. - TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, - DeclarationName Name, TemplateParameterList *Params, - NamedDecl *Decl) - : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl), - TemplateParams(Params) { } + TemplateDecl(Kind DK, DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : NamedDecl(DK, DC, L, Name), TemplatedDecl(Decl, false), + TemplateParams(Params) {} + public: /// Get the list of template parameters TemplateParameterList *getTemplateParameters() const { @@ -357,7 +356,7 @@ public: } /// Get the underlying, templated declaration. - NamedDecl *getTemplatedDecl() const { return TemplatedDecl; } + NamedDecl *getTemplatedDecl() const { return TemplatedDecl.getPointer(); } // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -367,20 +366,30 @@ public: SourceRange getSourceRange() const override LLVM_READONLY { return SourceRange(TemplateParams->getTemplateLoc(), - TemplatedDecl->getSourceRange().getEnd()); + TemplatedDecl.getPointer()->getSourceRange().getEnd()); } + /// Whether this is a (C++ Concepts TS) function or variable concept. + bool isConcept() const { return TemplatedDecl.getInt(); } + void setConcept() { TemplatedDecl.setInt(true); } + protected: - NamedDecl *TemplatedDecl; + /// \brief The named declaration from which this template was instantiated. + /// (or null). + /// + /// The boolean value will be true to indicate that this template + /// (function or variable) is a concept. + llvm::PointerIntPair<NamedDecl *, 1, bool> TemplatedDecl; + TemplateParameterList* TemplateParams; public: /// \brief Initialize the underlying templated declaration and /// template parameters. void init(NamedDecl *templatedDecl, TemplateParameterList* templateParams) { - assert(!TemplatedDecl && "TemplatedDecl already set!"); + assert(!TemplatedDecl.getPointer() && "TemplatedDecl already set!"); assert(!TemplateParams && "TemplateParams already set!"); - TemplatedDecl = templatedDecl; + TemplatedDecl.setPointer(templatedDecl); TemplateParams = templateParams; } }; @@ -889,7 +898,7 @@ public: /// Get the underlying function declaration of the template. FunctionDecl *getTemplatedDecl() const { - return static_cast<FunctionDecl*>(TemplatedDecl); + return static_cast<FunctionDecl *>(TemplatedDecl.getPointer()); } /// Returns whether this template declaration defines the primary @@ -1982,7 +1991,7 @@ public: /// \brief Get the underlying class declarations of the template. CXXRecordDecl *getTemplatedDecl() const { - return static_cast<CXXRecordDecl *>(TemplatedDecl); + return static_cast<CXXRecordDecl *>(TemplatedDecl.getPointer()); } /// \brief Returns whether this template declaration defines the primary @@ -2245,7 +2254,7 @@ protected: public: /// Get the underlying function declaration of the template. TypeAliasDecl *getTemplatedDecl() const { - return static_cast<TypeAliasDecl*>(TemplatedDecl); + return static_cast<TypeAliasDecl *>(TemplatedDecl.getPointer()); } @@ -2808,7 +2817,7 @@ public: /// \brief Get the underlying variable declarations of the template. VarDecl *getTemplatedDecl() const { - return static_cast<VarDecl *>(TemplatedDecl); + return static_cast<VarDecl *>(TemplatedDecl.getPointer()); } /// \brief Returns whether this template declaration defines the primary Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=260074&r1=260073&r2=260074&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sun Feb 7 23:34:00 2016 @@ -2080,6 +2080,9 @@ def err_function_concept_bool_ret : Erro "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">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=260074&r1=260073&r2=260074&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Feb 7 23:34:00 2016 @@ -6002,6 +6002,15 @@ Sema::ActOnVariableDeclarator(Scope *S, NewVD->setInvalidDecl(true); } + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable + // template, declared in namespace scope. + if (IsVariableTemplateSpecialization) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) + << (IsPartialSpecialization ? 2 : 1); + } + // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the // following restrictions: // - The declared type shall have the type bool. @@ -7667,6 +7676,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, } if (isConcept) { + // This is a function concept. + if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate()) + FTD->setConcept(); + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template [...] if (!D.isFunctionDefinition()) { @@ -7733,6 +7746,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, << 1 << 3; NewFD->setInvalidDecl(true); } + + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable + // template, declared in namespace scope. + if (isFunctionTemplateSpecialization) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) << 1; + } } // If __module_private__ was specified, mark the function accordingly. @@ -7994,9 +8015,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - + HasExplicitTemplateArgs = true; - + if (NewFD->isInvalidDecl()) { HasExplicitTemplateArgs = false; } else if (FunctionTemplate) { Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=260074&r1=260073&r2=260074&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sun Feb 7 23:34:00 2016 @@ -7673,6 +7673,15 @@ DeclResult Sema::ActOnExplicitInstantiat Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_explicit_instantiation_constexpr); + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable template, + // declared in namespace scope. + if (D.getDeclSpec().isConceptSpecified()) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) << 0; + return true; + } + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation // definition and an explicit instantiation declaration. An explicit Modified: cfe/trunk/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp?rev=260074&r1=260073&r2=260074&view=diff ============================================================================== --- cfe/trunk/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp (original) +++ cfe/trunk/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p1.cpp Sun Feb 7 23:34:00 2016 @@ -41,3 +41,20 @@ typedef concept int CI; // expected-erro void fpc(concept int i) {} // expected-error {{'concept' can only appear on the definition of a function template or variable template}} concept bool; // expected-error {{'concept' can only appear on the definition of a function template or variable template}} + +template <typename T> concept bool VCEI{ true }; +template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}} +extern template concept bool VCEI<int>; // expected-error {{'concept' cannot be applied on an explicit instantiation}} + +template <typename T> concept bool VCPS{ true }; +template <typename T> concept bool VCPS<T *>{ true }; // expected-error {{'concept' cannot be applied on an partial specialization}} + +template <typename T> concept bool VCES{ true }; +template <> concept bool VCES<int>{ true }; // expected-error {{'concept' cannot be applied on an explicit specialization}} + +template <typename T> concept bool FCEI() { return true; } +template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}} +extern template concept bool FCEI<int>(); // expected-error {{'concept' cannot be applied on an explicit instantiation}} + +template <typename T> concept bool FCES() { return true; } +template <> concept bool FCES<bool>() { return true; } // expected-error {{'concept' cannot be applied on an explicit specialization}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits