From: Douglas Gregor Date: Wed, 26 Jan 2011 16:40:18 +0000 (+0000) Subject: Reference qualifiers for *this: implement C++0x [expr.mptr.oper]p6, X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=6b4df91dc4ed4a3fc78587c49a3ed3df96b65d9c;p=clang Reference qualifiers for *this: implement C++0x [expr.mptr.oper]p6, the restrictions on .* and ->* for ref-qualified pointer-to-member functions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124294 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index fe4c182cfe..b186ca79ed 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1581,6 +1581,9 @@ def ext_template_arg_extra_parens : ExtWarn< "address non-type template argument cannot be surrounded by parentheses">; def err_pointer_to_member_type : Error< "invalid use of pointer to member type after %select{.*|->*}0">; +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">; // C++ template specialization def err_template_spec_unknown_kind : Error< diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index cb02be546e..062d4f697a 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -2557,6 +2557,32 @@ QualType Sema::CheckPointerToMemberOperands(Expr *&lex, Expr *&rex, QualType Result = MemPtr->getPointeeType(); Result = Context.getCVRQualifiedType(Result, LType.getCVRQualifiers()); + // C++0x [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 &&. + if (const FunctionProtoType *Proto = Result->getAs()) { + switch (Proto->getRefQualifier()) { + case RQ_None: + // Do nothing + break; + + case RQ_LValue: + if (!isIndirect && !lex->Classify(Context).isLValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 1 << lex->getSourceRange(); + break; + + case RQ_RValue: + if (isIndirect || !lex->Classify(Context).isRValue()) + Diag(Loc, diag::err_pointer_to_member_oper_value_classify) + << RType << 0 << lex->getSourceRange(); + break; + } + } + // C++ [expr.mptr.oper]p6: // The result of a .* expression whose second operand is a pointer // to a data member is of the same value category as its diff --git a/test/CXX/expr/expr.mptr.oper/p6-0x.cpp b/test/CXX/expr/expr.mptr.oper/p6-0x.cpp new file mode 100644 index 0000000000..d5dc7d2cbe --- /dev/null +++ b/test/CXX/expr/expr.mptr.oper/p6-0x.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +struct X { }; + +template T& lvalue(); +template T&& xvalue(); +template T prvalue(); + +// 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 &&. +void test(X *xp, int (X::*pmf)(int), 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); + + // Lvalue ref-qualifier. + (lvalue().*l_pmf)(17); + (xvalue().*l_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &' can only be called on an lvalue}} + (prvalue().*l_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &' can only be called on an lvalue}} + (xp->*l_pmf)(17); + + // Rvalue ref-qualifier. + (lvalue().*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}} + (xvalue().*r_pmf)(17); + (prvalue().*r_pmf)(17); + (xp->*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}} +}