aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaExprCXX.cpp
diff options
context:
space:
mode:
authorSebastian Redl <sebastian.redl@getdesigned.at>2009-04-19 21:15:26 +0000
committerSebastian Redl <sebastian.redl@getdesigned.at>2009-04-19 21:15:26 +0000
commit9bebfadb807aba0bc272197aff1cb4b2284c00a6 (patch)
tree011bd0387fce55454ae1e0866b9e34e7a7c7aa32 /lib/Sema/SemaExprCXX.cpp
parentaf7cdf45da4925f788e87a4c318ee67404646088 (diff)
Bring member pointer operands of the conditional operator to a common type. We're getting there ...
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69548 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExprCXX.cpp')
-rw-r--r--lib/Sema/SemaExprCXX.cpp57
1 files changed, 55 insertions, 2 deletions
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index c4572a59d3..2497f509ae 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1311,8 +1311,61 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
if (!Composite.isNull())
return Composite;
- // Fourth bullet is same for pointers-to-member.
- // FIXME: Handle this case where both are member pointers.
+ // Fourth bullet is same for pointers-to-member. However, the possible
+ // conversions are far more limited: we have null-to-pointer, upcast of
+ // containing class, and second-level cv-ness.
+ // cv-ness is not a union, but must match one of the two operands. (Which,
+ // frankly, is stupid.)
+ const MemberPointerType *LMemPtr = LTy->getAsMemberPointerType();
+ const MemberPointerType *RMemPtr = RTy->getAsMemberPointerType();
+ if (LMemPtr && RHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(RHS, LTy);
+ return LTy;
+ }
+ if (RMemPtr && LHS->isNullPointerConstant(Context)) {
+ ImpCastExprToType(LHS, RTy);
+ return RTy;
+ }
+ if (LMemPtr && RMemPtr) {
+ QualType LPointee = LMemPtr->getPointeeType();
+ QualType RPointee = RMemPtr->getPointeeType();
+ // First, we check that the unqualified pointee type is the same. If it's
+ // not, there's no conversion that will unify the two pointers.
+ if (Context.getCanonicalType(LPointee).getUnqualifiedType() ==
+ Context.getCanonicalType(RPointee).getUnqualifiedType()) {
+ // Second, we take the greater of the two cv qualifications. If neither
+ // is greater than the other, the conversion is not possible.
+ unsigned Q = LPointee.getCVRQualifiers() | RPointee.getCVRQualifiers();
+ if (Q == LPointee.getCVRQualifiers() || Q == RPointee.getCVRQualifiers()){
+ // Third, we check if either of the container classes is derived from
+ // the other.
+ QualType LContainer(LMemPtr->getClass(), 0);
+ QualType RContainer(RMemPtr->getClass(), 0);
+ QualType MoreDerived;
+ if (Context.getCanonicalType(LContainer) ==
+ Context.getCanonicalType(RContainer))
+ MoreDerived = LContainer;
+ else if (IsDerivedFrom(LContainer, RContainer))
+ MoreDerived = LContainer;
+ else if (IsDerivedFrom(RContainer, LContainer))
+ MoreDerived = RContainer;
+
+ if (!MoreDerived.isNull()) {
+ // The type 'Q Pointee (MoreDerived::*)' is the common type.
+ // We don't use ImpCastExprToType here because this could still fail
+ // for ambiguous or inaccessible conversions.
+ QualType Common = Context.getMemberPointerType(
+ LPointee.getQualifiedType(Q), MoreDerived.getTypePtr());
+ if (PerformImplicitConversion(LHS, Common, "converting"))
+ return QualType();
+ if (PerformImplicitConversion(RHS, Common, "converting"))
+ return QualType();
+ return Common;
+ }
+ }
+ }
+ }
+
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();