Add handling of member pointers to reinterpret_cast.

llvm-svn: 63150
This commit is contained in:
Sebastian Redl 2009-01-27 23:18:31 +00:00
parent fd03bdd00c
commit a5a77a6dc6
3 changed files with 61 additions and 18 deletions

View File

@ -237,6 +237,32 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// 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 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// 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 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
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 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
return;
}
// FIXME: Handle member pointers.
if (DestType->isFunctionPointerType()) {
// See above.
if (!Self.getLangOptions().CPlusPlus0x) {
@ -337,18 +359,21 @@ CheckReinterpretCast(Sema &Self, Expr *&SrcExpr, QualType DestType,
// 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;

View File

@ -70,3 +70,21 @@ void refs()
// 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}}
}

View File

@ -579,10 +579,10 @@ welcome!</p>
<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></td>
<td>Missing member pointer conversions</td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.2.11 [expr.const.cast]</td>