diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-04-19 21:15:26 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-04-19 21:15:26 +0000 |
commit | 9bebfadb807aba0bc272197aff1cb4b2284c00a6 (patch) | |
tree | 011bd0387fce55454ae1e0866b9e34e7a7c7aa32 /lib/Sema/SemaExprCXX.cpp | |
parent | af7cdf45da4925f788e87a4c318ee67404646088 (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.cpp | 57 |
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(); |