Reference qualifiers for *this: implement C++0x [expr.mptr.oper]p6,

the restrictions on .* and ->* for ref-qualified pointer-to-member
functions.

llvm-svn: 124294
This commit is contained in:
Douglas Gregor 2011-01-26 16:40:18 +00:00
parent 71711a673b
commit 1d042091d3
3 changed files with 63 additions and 0 deletions

View File

@ -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<

View File

@ -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<FunctionProtoType>()) {
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

View File

@ -0,0 +1,34 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
struct X { };
template<typename T> T& lvalue();
template<typename T> T&& xvalue();
template<typename T> 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<X>().*pmf)(17);
(xvalue<X>().*pmf)(17);
(prvalue<X>().*pmf)(17);
(xp->*pmf)(17);
// Lvalue ref-qualifier.
(lvalue<X>().*l_pmf)(17);
(xvalue<X>().*l_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &' can only be called on an lvalue}}
(prvalue<X>().*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<X>().*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}}
(xvalue<X>().*r_pmf)(17);
(prvalue<X>().*r_pmf)(17);
(xp->*r_pmf)(17); // expected-error{{pointer-to-member function type 'int (X::*)(int) &&' can only be called on an rvalue}}
}