Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -167,6 +167,9 @@ def CXXPre1zCompat : DiagGroup<"c++98-c++11-c++14-compat">; def CXXPre1zCompatPedantic : DiagGroup<"c++98-c++11-c++14-compat-pedantic", [CXXPre1zCompat]>; +def CXXPre2aCompat : DiagGroup<"c++98-c++11-c++14-c++1z-compat">; +def CXXPre2aCompatPedantic : DiagGroup<"c++98-c++11-c++14-c++1z-compat-pedantic", + [CXXPre2aCompat]>; def CXX98CompatBindToTemporaryCopy : DiagGroup<"c++98-compat-bind-to-temporary-copy">; @@ -780,6 +783,10 @@ // earlier C++ versions. def CXX1z : DiagGroup<"c++1z-extensions">; +// A warning group for warnings about using C++2a features as extensions in +// earlier C++ versions. +def CXX2a : DiagGroup<"c++2a-extensions">; + def : DiagGroup<"c++0x-extensions", [CXX11]>; def : DiagGroup<"c++1y-extensions", [CXX14]>; Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4111,6 +4111,13 @@ def err_pointer_to_member_oper_value_classify: Error< "pointer-to-member function type %0 can only be called on an " "%select{rvalue|lvalue}1">; +def warn_cxx1z_compat_const_amp_pointer_to_member_on_rvalue : Warning< + "invocation of a 'const&' qualified pointer-to-member function on an rvalue " + "is incompatible with C++ standards before C++2a">, + InGroup, DefaultIgnore; +def ext_const_amp_pointer_to_member_on_rvalue_cxx2a : ExtWarn< + "invocation of a 'const&' qualified pointer-to-member function on an rvalue " + "is a C++2a extension">, InGroup; def ext_ms_deref_template_argument: ExtWarn< "non-type template argument containing a dereference operation is a " "Microsoft extension">, InGroup; Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -5162,12 +5162,13 @@ QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LHSType.getCVRQualifiers()); - // C++0x [expr.mptr.oper]p6: + // C++2a [expr.mptr.oper]p6: // In a .* expression whose object expression is an rvalue, the program is - // ill-formed if the second operand is a pointer to member function with - // ref-qualifier &. In a ->* expression or in a .* expression whose object - // expression is an lvalue, the program is ill-formed if the second operand - // is a pointer to member function with ref-qualifier &&. + // ill-formed if the second operand is a pointer to member function whose + // ref-qualifier is &, unless its cv-qualifier-seq is const. In an ->* + // expression or in a .* expression whose object expression is an lvalue, + // the program is ill-formed if the second operand is a pointer to member + // function with ref-qualifier &&. if (const FunctionProtoType *Proto = Result->getAs()) { switch (Proto->getRefQualifier()) { case RQ_None: @@ -5175,9 +5176,18 @@ break; case RQ_LValue: - if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) - Diag(Loc, diag::err_pointer_to_member_oper_value_classify) - << RHSType << 1 << LHS.get()->getSourceRange(); + if (!isIndirect && !LHS.get()->Classify(Context).isLValue()) { + if (Proto->isConst() && !Proto->isVolatile()) + Diag(Loc, + !getLangOpts().CPlusPlus2a + ? diag:: + ext_const_amp_pointer_to_member_on_rvalue_cxx2a + : diag:: + warn_cxx1z_compat_const_amp_pointer_to_member_on_rvalue); + else + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RHSType << 1 << LHS.get()->getSourceRange(); + } break; case RQ_RValue: Index: test/CXX/expr/expr.mptr.oper/p6-0x.cpp =================================================================== --- test/CXX/expr/expr.mptr.oper/p6-0x.cpp +++ test/CXX/expr/expr.mptr.oper/p6-0x.cpp @@ -12,14 +12,20 @@ // expression whose object expression is an lvalue, the program is // ill-formed if the second operand is a pointer to member function // with ref-qualifier &&. -void test(X *xp, int (X::*pmf)(int), int (X::*l_pmf)(int) &, - int (X::*r_pmf)(int) &&) { +void test(X *xp, int (X::*pmf)(int), int (X::*const_l_pmf)(int) const&, + int (X::*l_pmf)(int) &, int (X::*r_pmf)(int) &&) { // No ref-qualifier. (lvalue().*pmf)(17); (xvalue().*pmf)(17); (prvalue().*pmf)(17); (xp->*pmf)(17); + // Const Lvalue ref-qualifier. + (lvalue().*const_l_pmf)(17); + (xvalue().*const_l_pmf)(17); // expected-warning {{C++2a extension}} + (prvalue().*const_l_pmf)(17); // expected-warning {{C++2a extension}} + (xp->*const_l_pmf)(17); + // Lvalue ref-qualifier. (lvalue().*l_pmf)(17); (xvalue().*l_pmf)(17); // expected-error-re{{pointer-to-member function type 'int (X::*)(int){{( __attribute__\(\(thiscall\)\))?}} &' can only be called on an lvalue}} Index: test/CXX/expr/expr.mptr.oper/p6-2a.cpp =================================================================== --- test/CXX/expr/expr.mptr.oper/p6-2a.cpp +++ test/CXX/expr/expr.mptr.oper/p6-2a.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s +// expected-no-diagnostics + +struct X { void foo() const&; }; + +void test() { + // Example from P0704R1. + X{}.foo(); + (X{}.*&X::foo)(); +} Index: www/cxx_status.html =================================================================== --- www/cxx_status.html +++ www/cxx_status.html @@ -777,13 +777,12 @@

C++2a implementation status

-

Clang does not yet support any of the proposed features of - +

Clang has experimental support for some proposed features of the C++ standard following C++17, provisionally named C++2a. Note that support for these features may change or be removed without notice, as the draft C++2a standard evolves. - +

You can use Clang in C++2a mode with the -std=c++2a option.

List of features and minimum Clang version with support @@ -803,7 +802,7 @@ const&-qualified pointers to members P0704R1 - No + SVN Allow lambda-capture [=, this]