Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4088,6 +4088,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 ext_pointer_to_const_ref_member_on_rvalue : Extension< + "invoking a pointer to a 'const &' member function on an rvalue is a C++2a extension">, + InGroup, SFINAEFailure; +def warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : Warning< + "invoking a pointer to a 'const &' member function on an rvalue is " + "incompatible with C++ standards before C++2a">, + InGroup, DefaultIgnore; 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 @@ -5175,9 +5175,16 @@ 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()) { + // C++2a allows functions with ref-qualifier & if they are also 'const'. + if (Proto->isConst()) + Diag(Loc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue + : diag::ext_pointer_to_const_ref_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/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp =================================================================== --- test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp +++ test/SemaCXX/cxx2a-pointer-to-const-ref-member.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++2a %s -verify + +struct X { + void ref() & {} + void cref() const& {} +}; + +void test() { + X{}.ref(); // expected-error{{cannot initialize object parameter of type 'X' with an expression of type 'X'}} + X{}.cref(); // expected-no-error + + (X{}.*&X::ref)(); // expected-error{{pointer-to-member function type 'void (X::*)() &' can only be called on an lvalue}} + (X{}.*&X::cref)(); // expected-no-error +}