Implement support for equality comparisons (!=, ==) of member
pointers, by extending the "composite pointer type" logic to include
member pointer types.

Introduce test cases for member pointer comparisons, including those
that involve the builtin operator candidates implemented earlier. 


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79925 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 2f1438c..59502c4 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4247,7 +4247,7 @@
       //   a pointer operand and a null pointer constant) to bring
       //   them to their composite pointer type. [...]
       //
-      // C++ [expr.eq]p2 uses the same notion for (in)equality
+      // C++ [expr.eq]p1 uses the same notion for (in)equality
       // comparisons of pointers.
       QualType T = FindCompositePointerType(lex, rex);
       if (T.isNull()) {
@@ -4285,20 +4285,53 @@
       ImpCastExprToType(rex, lType); // promote the pointer to pointer
     return ResultTy;
   }
-  // C++ allows comparison of pointers with null pointer constants.
+  
   if (getLangOptions().CPlusPlus) {
-    if (lType->isPointerType() && RHSIsNull) {
+    // Comparison of pointers with null pointer constants and equality 
+    // comparisons of member pointers to null pointer constants.
+    if (RHSIsNull && 
+        (lType->isPointerType() ||
+         (!isRelational && lType->isMemberPointerType()))) {
       ImpCastExprToType(rex, lType);
       return ResultTy;
     }
-    if (rType->isPointerType() && LHSIsNull) {
+    if (LHSIsNull &&
+        (rType->isPointerType() ||
+         (!isRelational && rType->isMemberPointerType()))) {
       ImpCastExprToType(lex, rType);
       return ResultTy;
     }
-    // And comparison of nullptr_t with itself.
+
+    // Comparison of member pointers.
+    if (!isRelational && 
+        lType->isMemberPointerType() && rType->isMemberPointerType()) {
+      // C++ [expr.eq]p2:
+      //   In addition, pointers to members can be compared, or a pointer to 
+      //   member and a null pointer constant. Pointer to member conversions 
+      //   (4.11) and qualification conversions (4.4) are performed to bring 
+      //   them to a common type. If one operand is a null pointer constant, 
+      //   the common type is the type of the other operand. Otherwise, the 
+      //   common type is a pointer to member type similar (4.4) to the type 
+      //   of one of the operands, with a cv-qualification signature (4.4) 
+      //   that is the union of the cv-qualification signatures of the operand 
+      //   types.
+      QualType T = FindCompositePointerType(lex, rex);
+      if (T.isNull()) {
+        Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers)
+        << lType << rType << lex->getSourceRange() << rex->getSourceRange();
+        return QualType();
+      }
+      
+      ImpCastExprToType(lex, T);
+      ImpCastExprToType(rex, T);
+      return ResultTy;
+    }
+    
+    // Comparison of nullptr_t with itself.
     if (lType->isNullPtrType() && rType->isNullPtrType())
       return ResultTy;
   }
+  
   // Handle block pointer types.
   if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) {
     QualType lpointee = lType->getAs<BlockPointerType>()->getPointeeType();
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 0434f30..d89a090 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1510,15 +1510,20 @@
 
 /// \brief Find a merged pointer type and convert the two expressions to it.
 ///
-/// This finds the composite pointer type for @p E1 and @p E2 according to
-/// C++0x 5.9p2. It converts both expressions to this type and returns it.
+/// This finds the composite pointer type (or member pointer type) for @p E1
+/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this
+/// type and returns it.
 /// It does not emit diagnostics.
 QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
   assert(getLangOptions().CPlusPlus && "This function assumes C++");
   QualType T1 = E1->getType(), T2 = E2->getType();
-  if(!T1->isAnyPointerType() && !T2->isAnyPointerType())
-    return QualType();
+  
+  if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+      !T2->isPointerType() && !T2->isMemberPointerType())
+   return QualType();
 
+  // FIXME: Do we need to work on the canonical types?
+  
   // C++0x 5.9p2
   //   Pointer conversions and qualification conversions are performed on
   //   pointer operands to bring them to their composite pointer type. If
@@ -1532,8 +1537,10 @@
     ImpCastExprToType(E2, T1);
     return T1;
   }
-  // Now both have to be pointers.
-  if(!T1->isPointerType() || !T2->isPointerType())
+  
+  // Now both have to be pointers or member pointers.
+  if (!T1->isPointerType() && !T1->isMemberPointerType() &&
+      !T2->isPointerType() && !T2->isMemberPointerType())
     return QualType();
 
   //   Otherwise, of one of the operands has type "pointer to cv1 void," then
@@ -1547,20 +1554,56 @@
   // conversions in both directions. If only one works, or if the two composite
   // types are the same, we have succeeded.
   llvm::SmallVector<unsigned, 4> QualifierUnion;
+  llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
   QualType Composite1 = T1, Composite2 = T2;
-  const PointerType *Ptr1, *Ptr2;
-  while ((Ptr1 = Composite1->getAs<PointerType>()) &&
-         (Ptr2 = Composite2->getAs<PointerType>())) {
-    Composite1 = Ptr1->getPointeeType();
-    Composite2 = Ptr2->getPointeeType();
-    QualifierUnion.push_back(
-      Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
-  }
-  // Rewrap the composites as pointers with the union CVRs.
-  for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(),
-       E = QualifierUnion.end(); I != E; ++I) {
-    Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
-    Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
+  do {
+    const PointerType *Ptr1, *Ptr2;
+    if ((Ptr1 = Composite1->getAs<PointerType>()) &&
+        (Ptr2 = Composite2->getAs<PointerType>())) {
+      Composite1 = Ptr1->getPointeeType();
+      Composite2 = Ptr2->getPointeeType();
+      QualifierUnion.push_back(
+                 Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+      MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0));
+      continue;
+    }
+    
+    const MemberPointerType *MemPtr1, *MemPtr2;
+    if ((MemPtr1 = Composite1->getAs<MemberPointerType>()) &&
+        (MemPtr2 = Composite2->getAs<MemberPointerType>())) {
+      Composite1 = MemPtr1->getPointeeType();
+      Composite2 = MemPtr2->getPointeeType();
+      QualifierUnion.push_back(
+                 Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
+      MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(),
+                                             MemPtr2->getClass()));
+      continue;
+    }
+    
+    // FIXME: block pointer types?
+    
+    // Cannot unwrap any more types.
+    break;
+  } while (true);
+  
+  // Rewrap the composites as pointers or member pointers with the union CVRs.
+  llvm::SmallVector<std::pair<const Type *, const Type *>, 4>::iterator MOC
+    = MemberOfClass.begin();
+  for (llvm::SmallVector<unsigned, 4>::iterator 
+         I = QualifierUnion.begin(),
+         E = QualifierUnion.end(); 
+       I != E; (void)++I, ++MOC) {
+    if (MOC->first && MOC->second) {
+      // Rebuild member pointer type
+      Composite1 = Context.getMemberPointerType(Composite1.getQualifiedType(*I),
+                                                MOC->first);
+      Composite2 = Context.getMemberPointerType(Composite2.getQualifiedType(*I),
+                                                MOC->second);
+    } else {
+      // Rebuild pointer type
+      Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
+      Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
+    }
   }
 
   ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
diff --git a/test/SemaCXX/composite-pointer-type.cpp b/test/SemaCXX/composite-pointer-type.cpp
index b4a5c88..ebc40c1 100644
--- a/test/SemaCXX/composite-pointer-type.cpp
+++ b/test/SemaCXX/composite-pointer-type.cpp
@@ -25,3 +25,11 @@
   if (d1 == d2) // expected-error{{comparison of distinct}}
     return;
 }
+
+// PR4691
+int ptrcmp1(void *a, int *b) {
+  return a < b;
+}
+int ptrcmp2(long *a, int *b) {
+  return a < b; // expected-error{{distinct}}
+}
\ No newline at end of file
diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp
index 3f4d715..65fbd83 100644
--- a/test/SemaCXX/conditional-expr.cpp
+++ b/test/SemaCXX/conditional-expr.cpp
@@ -170,7 +170,7 @@
     i1 ? &MixedFields::ci : &MixedFieldsDerived::i;
   const volatile int (MixedFields::*mp2) =
     i1 ? &MixedFields::ci : &MixedFields::cvi;
-  i1 ? &MixedFields::ci : &MixedFields::vi; // expected-error {{incompatible operand types}}
+  (void)(i1 ? &MixedFields::ci : &MixedFields::vi);
   // Conversion of primitives does not result in an lvalue.
   &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}
 
diff --git a/test/SemaCXX/member-pointer.cpp b/test/SemaCXX/member-pointer.cpp
index 3b106d5..9e407a1 100644
--- a/test/SemaCXX/member-pointer.cpp
+++ b/test/SemaCXX/member-pointer.cpp
@@ -40,6 +40,14 @@
 
   // Conversion to member of base.
   pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}}
+  
+  // Comparisons
+  int (A::*pf2)(int, int);
+  int (D::*pf3)(int, int) = 0;
+  bool b1 = (pf == pf2); (void)b1;
+  bool b2 = (pf != pf2); (void)b2;
+  bool b3 = (pf == pf3); (void)b3;
+  bool b4 = (pf != 0); (void)b4;
 }
 
 struct TheBase
diff --git a/test/SemaCXX/overloaded-builtin-operators.cpp b/test/SemaCXX/overloaded-builtin-operators.cpp
index 2a6c24a..a8c94f1 100644
--- a/test/SemaCXX/overloaded-builtin-operators.cpp
+++ b/test/SemaCXX/overloaded-builtin-operators.cpp
@@ -20,11 +20,21 @@
   operator E2();
 };
 
+
+struct X { 
+  void f();
+};
+
+typedef void (X::*pmf)();
+struct Xpmf {
+  operator pmf();
+};
+
 yes& islong(long);
 yes& islong(unsigned long); // FIXME: shouldn't be needed
 no& islong(int);
 
-void f(Short s, Long l, Enum1 e1, Enum2 e2) {
+void f(Short s, Long l, Enum1 e1, Enum2 e2, Xpmf pmf) {
   // C++ [over.built]p8
   int i1 = +e1;
   int i2 = -e2;
@@ -37,6 +47,10 @@
   (void)static_cast<yes&>(islong(s + l));
   (void)static_cast<no&>(islong(s + s));
 
+  // C++ [over.built]p16
+  (void)(pmf == &X::f);
+  (void)(pmf == 0);
+  
   // C++ [over.built]p17
   (void)static_cast<yes&>(islong(s % l));
   (void)static_cast<yes&>(islong(l << s));
@@ -53,7 +67,15 @@
   operator volatile long&();
 };
 
-void g(ShortRef sr, LongRef lr) {
+struct XpmfRef {
+  operator pmf&();
+};
+
+struct E2Ref {
+  operator E2&();
+};
+
+void g(ShortRef sr, LongRef lr, E2Ref e2_ref, XpmfRef pmf_ref) {
   // C++ [over.built]p3
   short s1 = sr++;
 
@@ -64,6 +86,14 @@
   short& sr1 = (sr *= lr);
   volatile long& lr1 = (lr *= sr);
 
+  // C++ [over.built]p20:
+  E2 e2r2;
+  e2r2 = e2_ref;
+  
+  pmf &pmr = (pmf_ref = &X::f); // expected-error{{no viable overloaded '='}}
+  pmf pmr2;
+  pmr2 = pmf_ref;
+               
   // C++ [over.built]p22
   short& sr2 = (sr %= lr);
   volatile long& lr2 = (lr <<= sr);
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 05f3a0d..d01c5a7 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -1764,7 +1764,7 @@
   <td class="advanced" align="center"></td>
   <td class="medium" align="center"></td>
   <td class="na" align="center">N/A</td>  
-  <td>Missing pointer-to-member versions (p11, p16) and support for
+  <td>Missing support for the ->* operator (p11, p16) and support for
   the ternary operator (p24, p25).</td>
 </tr>
 <tr>