]> granicus.if.org Git - clang/commitdiff
Reference qualifiers for *this: implement C++0x [expr.mptr.oper]p6,
authorDouglas Gregor <dgregor@apple.com>
Wed, 26 Jan 2011 16:40:18 +0000 (16:40 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 26 Jan 2011 16:40:18 +0000 (16:40 +0000)
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

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/SemaExprCXX.cpp
test/CXX/expr/expr.mptr.oper/p6-0x.cpp [new file with mode: 0644]

index fe4c182cfecc9e5a803b2a0fe7f3c16bb50edad7..b186ca79edf9ed81d7740e8654f78abb7ac531eb 100644 (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<
index cb02be546e0d47e5f97d03189e37b3eb0731c532..062d4f697ab4da320c25f01543b94b422fdc6627 100644 (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
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 (file)
index 0000000..d5dc7d2
--- /dev/null
@@ -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}}
+}