Add handling of member pointers to reinterpret_cast.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63150 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaNamedCast.cpp b/lib/Sema/SemaNamedCast.cpp
index 17de732..e88a3b2 100644
--- a/lib/Sema/SemaNamedCast.cpp
+++ b/lib/Sema/SemaNamedCast.cpp
@@ -237,6 +237,32 @@
   // Canonicalize source for comparison.
   SrcType = Self.Context.getCanonicalType(SrcType);
 
+  const MemberPointerType *DestMemPtr = DestType->getAsMemberPointerType(),
+                          *SrcMemPtr = SrcType->getAsMemberPointerType();
+  if (DestMemPtr && SrcMemPtr) {
+    // C++ 5.2.10p9: An rvalue of type "pointer to member of X of type T1"
+    //   can be explicitly converted to an rvalue of type "pointer to member
+    //   of Y of type T2" if T1 and T2 are both function types or both object
+    //   types.
+    if (DestMemPtr->getPointeeType()->isFunctionType() !=
+        SrcMemPtr->getPointeeType()->isFunctionType()) {
+      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_generic)
+        << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+      return;
+    }
+
+    // C++ 5.2.10p2: The reinterpret_cast operator shall not cast away
+    //   constness.
+    if (CastsAwayConstness(Self, SrcType, DestType)) {
+      Self.Diag(OpRange.getBegin(), diag::err_bad_cxx_cast_const_away)
+        << "reinterpret_cast" << OrigDestType << OrigSrcType << OpRange;
+      return;
+    }
+
+    // A valid member pointer cast.
+    return;
+  }
+
   bool destIsPtr = DestType->isPointerType();
   bool srcIsPtr = SrcType->isPointerType();
   if (!destIsPtr && !srcIsPtr) {
@@ -253,8 +279,8 @@
     // restrictions, a cast to the same type is allowed. The intent is not
     // entirely clear here, since all other paragraphs explicitly forbid casts
     // to the same type. However, the behavior of compilers is pretty consistent
-    // on this point: allow same-type conversion if the involved are pointers,
-    // disallow otherwise.
+    // on this point: allow same-type conversion if the involved types are
+    // pointers, disallow otherwise.
     return;
   }
 
@@ -304,8 +330,6 @@
       return;
     }
 
-    // FIXME: Handle member pointers.
-
     // C++0x 5.2.10p8: Converting a pointer to a function into a pointer to
     //   an object type or vice versa is conditionally-supported.
     // Compilers support it in C++03 too, though, because it's necessary for
@@ -319,8 +343,6 @@
     return;
   }
 
-  // FIXME: Handle member pointers.
-
   if (DestType->isFunctionPointerType()) {
     // See above.
     if (!Self.getLangOptions().CPlusPlus0x) {
@@ -337,18 +359,21 @@
   // object pointers.
 }
 
-/// CastsAwayConstness - Check if the pointer conversion from SrcType
-/// to DestType casts away constness as defined in C++
-/// 5.2.11p8ff. This is used by the cast checkers.  Both arguments
-/// must denote pointer types.
+/// CastsAwayConstness - Check if the pointer conversion from SrcType to
+/// DestType casts away constness as defined in C++ 5.2.11p8ff. This is used by
+/// the cast checkers.  Both arguments must denote pointer (possibly to member)
+/// types.
 bool
 CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType)
 {
- // Casting away constness is defined in C++ 5.2.11p8 with reference to
-  // C++ 4.4.
-  // We piggyback on Sema::IsQualificationConversion for this, since the rules
-  // are non-trivial. So first we construct Tcv *...cv* as described in
-  // C++ 5.2.11p8.
+  // Casting away constness is defined in C++ 5.2.11p8 with reference to
+  // C++ 4.4. We piggyback on Sema::IsQualificationConversion for this, since
+  // the rules are non-trivial. So first we construct Tcv *...cv* as described
+  // in C++ 5.2.11p8.
+  assert((SrcType->isPointerType() || SrcType->isMemberPointerType()) &&
+         "Source type is not pointer or pointer to member.");
+  assert((DestType->isPointerType() || DestType->isMemberPointerType()) &&
+         "Destination type is not pointer or pointer to member.");
 
   QualType UnwrappedSrcType = SrcType, UnwrappedDestType = DestType;
   llvm::SmallVector<unsigned, 8> cv1, cv2;
diff --git a/test/SemaCXX/reinterpret-cast.cpp b/test/SemaCXX/reinterpret-cast.cpp
index 6172c9f..e6d6352 100644
--- a/test/SemaCXX/reinterpret-cast.cpp
+++ b/test/SemaCXX/reinterpret-cast.cpp
@@ -70,3 +70,21 @@
   // Bad: from rvalue
   (void)reinterpret_cast<int&>(&c); // expected-error {{reinterpret_cast from rvalue to reference type 'int &'}}
 }
+
+void memptrs()
+{
+  const int structure::*psi = 0;
+  (void)reinterpret_cast<const float structure::*>(psi);
+  (void)reinterpret_cast<int structure::*>(psi); // expected-error {{reinterpret_cast from 'int const struct structure::*' to 'int struct structure::*' casts away constness}}
+
+  void (structure::*psf)() = 0;
+  (void)reinterpret_cast<int (structure::*)()>(psf);
+
+  (void)reinterpret_cast<void (structure::*)()>(psi); // expected-error {{reinterpret_cast from 'int const struct structure::*' to 'void (struct structure::*)(void)' is not allowed}}
+  (void)reinterpret_cast<int structure::*>(psf); // expected-error {{reinterpret_cast from 'void (struct structure::*)(void)' to 'int struct structure::*' is not allowed}}
+
+  // Cannot cast from integers to member pointers, not even the null pointer
+  // literal.
+  (void)reinterpret_cast<void (structure::*)()>(0); // expected-error {{reinterpret_cast from 'int' to 'void (struct structure::*)(void)' is not allowed}}
+  (void)reinterpret_cast<int structure::*>(0); // expected-error {{reinterpret_cast from 'int' to 'int struct structure::*' is not allowed}}
+}
diff --git a/www/cxx_status.html b/www/cxx_status.html
index 5c57f91..a83157b 100644
--- a/www/cxx_status.html
+++ b/www/cxx_status.html
@@ -579,10 +579,10 @@
 <tr>

   <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.10 [expr.reinterpret.cast]</td>

   <td class="complete" align="center">&#x2713;</td>

-  <td class="advanced" align="center"></td>

-  <td class="advanced" align="center"></td>

+  <td class="complete" align="center">&#x2713;</td>

+  <td class="complete" align="center">&#x2713;</td>

   <td></td>

-  <td>Missing member pointer conversions</td>

+  <td></td>

 </tr>

 <tr>

   <td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.11 [expr.const.cast]</td>