Index: include/clang/AST/Decl.h =================================================================== --- include/clang/AST/Decl.h +++ include/clang/AST/Decl.h @@ -1624,6 +1624,7 @@ unsigned HasImplicitReturnZero : 1; unsigned IsLateTemplateParsed : 1; unsigned IsConstexpr : 1; + unsigned IsConstexprSpecified : 1; /// \brief Indicates if the function uses __try. unsigned UsesSEHTry : 1; @@ -1718,6 +1719,7 @@ IsDeleted(false), IsTrivial(false), IsDefaulted(false), IsExplicitlyDefaulted(false), HasImplicitReturnZero(false), IsLateTemplateParsed(false), IsConstexpr(isConstexprSpecified), + IsConstexprSpecified(isConstexprSpecified), UsesSEHTry(false), HasSkippedBody(false), WillHaveBody(false), EndRangeLoc(NameInfo.getEndLoc()), TemplateOrSpecialization(), DNLoc(NameInfo.getInfo()) {} @@ -1907,7 +1909,19 @@ /// Whether this is a (C++11) constexpr function or constexpr constructor. bool isConstexpr() const { return IsConstexpr; } - void setConstexpr(bool IC) { IsConstexpr = IC; } + + /// Set whether the "constexpr" keyword was specified for this function. + void setConstexprSpecified(bool IC) { + IsConstexprSpecified = IC; + IsConstexpr = IC; + } + + /// Flag that this function as implicitly constexpr + /// C++11 [dcl.constexpr]p2: constexpr functions and constexpr constructors + /// are implicitly inline functions (7.1.2). + void setImplicitlyConstexpr(bool IC) { + IsConstexpr = IC; + } /// \brief Indicates the function uses __try. bool usesSEHTry() const { return UsesSEHTry; } Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -8082,7 +8082,8 @@ } // C++ Concepts TS [dcl.spec.concept]p2: Every concept definition is - // implicity defined to be a constexpr declaration (implicitly inline) + // implicity defined to be a constexpr declaration + NewFD->setImplicitlyConstexpr(true); NewFD->setImplicitlyInline(); // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not @@ -9104,7 +9105,7 @@ if (FD->isConstexpr()) { Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_main) << FixItHint::CreateRemoval(DS.getConstexprSpecLoc()); - FD->setConstexpr(false); + FD->setImplicitlyConstexpr(false); } if (getLangOpts().OpenCL) { Index: lib/Sema/SemaDeclCXX.cpp =================================================================== --- lib/Sema/SemaDeclCXX.cpp +++ lib/Sema/SemaDeclCXX.cpp @@ -6253,7 +6253,7 @@ if (First) { // -- it is implicitly considered to be constexpr if the implicit // definition would be, - MD->setConstexpr(Constexpr); + MD->setImplicitlyConstexpr(Constexpr); // -- it is implicitly considered to have the same exception-specification // as if it had been implicitly declared, Index: lib/Sema/SemaLambda.cpp =================================================================== --- lib/Sema/SemaLambda.cpp +++ lib/Sema/SemaLambda.cpp @@ -1619,7 +1619,7 @@ !CallOperator->isConstexpr() && !Class->getDeclContext()->isDependentContext()) { TentativeAnalysisScope DiagnosticScopeGuard(*this); - CallOperator->setConstexpr( + CallOperator->setImplicitlyConstexpr( CheckConstexprFunctionDecl(CallOperator) && CheckConstexprFunctionBody(CallOperator, CallOperator->getBody())); } Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -7086,7 +7086,7 @@ // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr // function can differ from the template declaration with respect to // the constexpr specifier. - Specialization->setConstexpr(FD->isConstexpr()); + Specialization->setImplicitlyConstexpr(FD->isConstexpr()); } // FIXME: Check if the prior specialization has a point of instantiation. Index: test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp =================================================================== --- test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp +++ test/CXX/concepts-ts/dcl.dcl/dcl.spec/dcl.spec.concept/p2.cpp @@ -11,3 +11,30 @@ }; template concept constexpr bool FCC() { return true; } // expected-error {{function concept cannot be declared 'constexpr'}} + +template concept bool FCSizeOf() { return sizeof(T) == 8; } +static_assert(FCSizeOf(), ""); +static_assert(FCSizeOf(), "size of argument not equal to expected (8)"); // expected-error {{static_assert failed "size of argument not equal to expected (8)"}} + +struct TestType {}; +template concept bool FCSameType() { return __is_same(T, U); } +static_assert(FCSameType(), ""); + +template +struct remove_reference { typedef T type; }; +template +struct remove_reference { typedef T type; }; +template +struct remove_reference { typedef T type; }; + +template +constexpr T &&forward(typename remove_reference::type &t) noexcept { return static_cast(t); } +template +constexpr T &&forward(typename remove_reference::type &&t) noexcept { return static_cast(t); } + +template +constexpr decltype(auto) CFFwdCall(F &&func, Args &&... args) { + return forward(func)(forward(args)...); +} + +static_assert(CFFwdCall(FCSameType), "");