diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 2c3b22a21bf466413b9eafba9e9123e781624712..2fa7f01d080153c7e4b8723e98d6de5767fc3d27 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1980,6 +1980,9 @@ 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'">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index acff354f70e8c7047aea023293f29dd2ce0acbed..c55c07efb77021f860ed639537abb9cd8d2eac46 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -5876,8 +5876,26 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (D.getDeclSpec().isConstexprSpecified()) NewVD->setConstexpr(true); - if (D.getDeclSpec().isConceptSpecified()) + if (D.getDeclSpec().isConceptSpecified()) { NewVD->setConcept(true); + + // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not + // be declared with the thread_local, inline, friend, or constexpr + // specifiers, [...] + if (D.getDeclSpec().getThreadStorageClassSpec() == TSCS_thread_local) { + Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_concept_decl_invalid_specifiers) + << 0 << 0; + NewVD->setInvalidDecl(true); + } + + if (D.getDeclSpec().isConstexprSpecified()) { + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_concept_decl_invalid_specifiers) + << 0 << 3; + NewVD->setInvalidDecl(true); + } + } } // Set the lexical context. If the declarator has a C++ scope specifier, the @@ -7502,6 +7520,30 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is // implicity defined to be a constexpr declaration (implicitly inline) NewFD->setImplicitlyInline(); + + // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not + // be declared with the thread_local, inline, friend, or constexpr + // specifiers, [...] + if (isInline) { + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_concept_decl_invalid_specifiers) + << 1 << 1; + NewFD->setInvalidDecl(true); + } + + if (isFriend) { + Diag(D.getDeclSpec().getFriendSpecLoc(), + diag::err_concept_decl_invalid_specifiers) + << 1 << 2; + NewFD->setInvalidDecl(true); + } + + if (isConstexpr) { + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_concept_decl_invalid_specifiers) + << 1 << 3; + NewFD->setInvalidDecl(true); + } } // If __module_private__ was specified, mark the function accordingly. diff --git a/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.concept/p2.cpp b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.concept/p2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..477910986de12fe46d3641495d7ff19497bf2187 --- /dev/null +++ b/test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.concept/p2.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s + +template<typename T> concept thread_local bool VCTL = true; // expected-error {{variable concept cannot be declared 'thread_local'}} + +template<typename T> concept constexpr bool VCC = true; // expected-error {{variable concept cannot be declared 'constexpr'}} + +template<typename T> concept inline bool FCI() { return true; } // expected-error {{function concept cannot be declared 'inline'}} + +struct X { + template<typename T> concept friend bool FCF() { return true; } // expected-error {{function concept cannot be declared 'friend'}} +}; + +template<typename T> concept constexpr bool FCC() { return true; } // expected-error {{function concept cannot be declared 'constexpr'}}