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> 5.2.10 [expr.reinterpret.cast]</td>
<td class="complete" align="center">✓</td>
- <td class="advanced" align="center"></td>
- <td class="advanced" align="center"></td>
+ <td class="complete" align="center">✓</td>
+ <td class="complete" align="center">✓</td>
<td></td>
- <td>Missing member pointer conversions</td>
+ <td></td>
</tr>
<tr>
<td> 5.2.11 [expr.const.cast]</td>