From 9bebfadb807aba0bc272197aff1cb4b2284c00a6 Mon Sep 17 00:00:00 2001 From: Sebastian Redl Date: Sun, 19 Apr 2009 21:15:26 +0000 Subject: [PATCH] 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 --- lib/Sema/SemaExprCXX.cpp | 57 +++++++++++++++++++++++++++++-- test/SemaCXX/conditional-expr.cpp | 22 +++++++++--- 2 files changed, 72 insertions(+), 7 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(); diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index aa71f60dc1..0366e67a1b 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -38,6 +38,14 @@ struct BadDerived : BadBase {}; struct Fields { int i1, i2, b1 : 3, b2 : 3; }; +struct MixedFields { + int i; + volatile int vi; + const int ci; + const volatile int cvi; +}; +struct MixedFieldsDerived : MixedFields { +}; enum Enum { EVal }; @@ -148,11 +156,15 @@ void test() d1 = i1 ? 4.0 : 'c'; Base *pb = i1 ? (Base*)0 : (Derived*)0; pb = i1 ? (Derived*)0 : (Base*)0; - // FIXME: member pointer conversions don't work yet. - //pfm = i1 ? &Base::fn1 : &Derived::fn2; - //pfm = i1 ? &Derived::fn2 : &Base::fn1; - //pfm = i1 ? &Derived::fn2 : 0; - //pfm = i1 ? 0 : &Derived::fn2; + pfm = i1 ? &Base::fn1 : &Derived::fn2; + pfm = i1 ? &Derived::fn2 : &Base::fn1; + pfm = i1 ? &Derived::fn2 : 0; + pfm = i1 ? 0 : &Derived::fn2; + const int (MixedFieldsDerived::*mp1) = + i1 ? &MixedFields::ci : &MixedFieldsDerived::i; + const volatile int (MixedFields::*mp2) = + i1 ? &MixedFields::ci : &MixedFields::cvi; + i1 ? &MixedFields::ci : &MixedFields::vi; // expected-error {{incompatible operand types}} // Conversion of primitives does not result in an lvalue. &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}} -- 2.50.1