[cfe-commits] r79925 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Mon Aug 24 10:42:36 PDT 2009


Author: dgregor
Date: Mon Aug 24 12:42:35 2009
New Revision: 79925

URL: http://llvm.org/viewvc/llvm-project?rev=79925&view=rev
Log:
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. 

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

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Aug 24 12:42:35 2009
@@ -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();

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Mon Aug 24 12:42:35 2009
@@ -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);

Modified: cfe/trunk/test/SemaCXX/composite-pointer-type.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/composite-pointer-type.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/composite-pointer-type.cpp (original)
+++ cfe/trunk/test/SemaCXX/composite-pointer-type.cpp Mon Aug 24 12:42:35 2009
@@ -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

Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Mon Aug 24 12:42:35 2009
@@ -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}}
 

Modified: cfe/trunk/test/SemaCXX/member-pointer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/member-pointer.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/member-pointer.cpp (original)
+++ cfe/trunk/test/SemaCXX/member-pointer.cpp Mon Aug 24 12:42:35 2009
@@ -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

Modified: cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp (original)
+++ cfe/trunk/test/SemaCXX/overloaded-builtin-operators.cpp Mon Aug 24 12:42:35 2009
@@ -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);

Modified: cfe/trunk/www/cxx_status.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/www/cxx_status.html?rev=79925&r1=79924&r2=79925&view=diff

==============================================================================
--- cfe/trunk/www/cxx_status.html (original)
+++ cfe/trunk/www/cxx_status.html Mon Aug 24 12:42:35 2009
@@ -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>





More information about the cfe-commits mailing list