Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -1979,6 +1979,9 @@ "variable concept declaration must be initialized">; def err_function_concept_exception_spec : Error< "function concept cannot have exception specification">; +def err_concept_decl_invalid_sepcifiers : Error< + "%select{variable|function}0 concept cannot be declared with " + "%select{thread_local|constexpr|inline}1 specified">; // C++11 char16_t/char32_t def warn_cxx98_compat_unicode_type : Warning< Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -5871,8 +5871,26 @@ 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_sepcifiers) + << 0 << 0; + NewVD->setInvalidDecl(true); + } + + if (D.getDeclSpec().isConstexprSpecified()) { + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_concept_decl_invalid_sepcifiers) + << 0 << 1; + NewVD->setInvalidDecl(true); + } + } } // Set the lexical context. If the declarator has a C++ scope specifier, the @@ -7497,6 +7515,23 @@ // 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 (isConstexpr) { + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_concept_decl_invalid_sepcifiers) + << 1 << 1; + NewFD->setInvalidDecl(true); + } + + if (isInline) { + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_concept_decl_invalid_sepcifiers) + << 1 << 2; + NewFD->setInvalidDecl(true); + } } // If __module_private__ was specified, mark the function accordingly. Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.concept/p2.cpp =================================================================== --- /dev/null +++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.concept/p2.cpp @@ -0,0 +1,9 @@ +// RUN: %clang_cc1 -std=c++14 -fconcepts-ts -x c++ -verify %s + +template concept thread_local bool VCTL = true; // expected-error {{variable concept cannot be declared with thread_local specified}} + +template concept constexpr bool VCC = true; // expected-error {{variable concept cannot be declared with constexpr specified}} + +template concept constexpr bool FCC() { return true; } // expected-error {{function concept cannot be declared with constexpr specified}} + +template concept inline bool FCI() { return true; } // expected-error {{function concept cannot be declared with inline specified}}