]> granicus.if.org Git - clang/commitdiff
Implement support for equality comparisons (!=, ==) of member
authorDouglas Gregor <dgregor@apple.com>
Mon, 24 Aug 2009 17:42:35 +0000 (17:42 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 24 Aug 2009 17:42:35 +0000 (17:42 +0000)
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

lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/SemaCXX/composite-pointer-type.cpp
test/SemaCXX/conditional-expr.cpp
test/SemaCXX/member-pointer.cpp
test/SemaCXX/overloaded-builtin-operators.cpp
www/cxx_status.html

index 2f1438c2c3e811c7e53a5c0bd6dba6c72fde97be..59502c4edbf9407da7bef4be123d0d6f69b16a68 100644 (file)
@@ -4247,7 +4247,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
       //   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 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
       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();
index 0434f304d8774e19c23e27ce894753ef543e0111..d89a0909aa142704363ecbc8fed92ac2f9adbfb3 100644 (file)
@@ -1510,15 +1510,20 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
 
 /// \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 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
     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 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
   // 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);
index b4a5c884f755efaae1674bcfcf2f4fea9b1fd833..ebc40c14b743c2335512bc362978a1deb9c62426 100644 (file)
@@ -25,3 +25,11 @@ void f1(volatile Base *b, Derived1 *d1, const Derived2 *d2) {
   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
index 3f4d7159a0f8f0b36476d10a92a4ce797d2d1de1..65fbd83e6d252940a426c43c3dc35a54b8a6c4f0 100644 (file)
@@ -170,7 +170,7 @@ void test()
     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}}
 
index 3b106d5576fe64193cc863c1b47abe0366027267..9e407a184c30568c22fe2ca63571725db3017db7 100644 (file)
@@ -40,6 +40,14 @@ void f() {
 
   // 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
index 2a6c24a6778ac0c76f5afe0d3d045df55935ec94..a8c94f182225cd76e74e6e93766d0061ccfe6151 100644 (file)
@@ -20,11 +20,21 @@ struct Enum2 {
   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 f(Short s, Long l, Enum1 e1, Enum2 e2) {
   (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 @@ struct LongRef {
   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 @@ void g(ShortRef sr, LongRef lr) {
   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);
index 05f3a0d00c4b175dcd6d1448debc974a3f9e16c4..d01c5a7752b649086724860691cdf89bb2e55a9c 100644 (file)
@@ -1764,7 +1764,7 @@ welcome!</p>
   <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>