diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 2f1438c2c3e8..59502c4edbf9 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -4247,7 +4247,7 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, // a pointer operand and a null pointer constant) to bring // them to their composite pointer type. [...] // - // C++ [expr.eq]p2 uses the same notion for (in)equality + // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. QualType T = FindCompositePointerType(lex, rex); if (T.isNull()) { @@ -4285,20 +4285,53 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, ImpCastExprToType(rex, lType); // promote the pointer to pointer return ResultTy; } - // C++ allows comparison of pointers with null pointer constants. + if (getLangOptions().CPlusPlus) { - if (lType->isPointerType() && RHSIsNull) { + // Comparison of pointers with null pointer constants and equality + // comparisons of member pointers to null pointer constants. + if (RHSIsNull && + (lType->isPointerType() || + (!isRelational && lType->isMemberPointerType()))) { ImpCastExprToType(rex, lType); return ResultTy; } - if (rType->isPointerType() && LHSIsNull) { + if (LHSIsNull && + (rType->isPointerType() || + (!isRelational && rType->isMemberPointerType()))) { ImpCastExprToType(lex, rType); return ResultTy; } - // And comparison of nullptr_t with itself. + + // Comparison of member pointers. + if (!isRelational && + lType->isMemberPointerType() && rType->isMemberPointerType()) { + // C++ [expr.eq]p2: + // In addition, pointers to members can be compared, or a pointer to + // member and a null pointer constant. Pointer to member conversions + // (4.11) and qualification conversions (4.4) are performed to bring + // them to a common type. If one operand is a null pointer constant, + // the common type is the type of the other operand. Otherwise, the + // common type is a pointer to member type similar (4.4) to the type + // of one of the operands, with a cv-qualification signature (4.4) + // that is the union of the cv-qualification signatures of the operand + // types. + QualType T = FindCompositePointerType(lex, rex); + if (T.isNull()) { + Diag(Loc, diag::err_typecheck_comparison_of_distinct_pointers) + << lType << rType << lex->getSourceRange() << rex->getSourceRange(); + return QualType(); + } + + ImpCastExprToType(lex, T); + ImpCastExprToType(rex, T); + return ResultTy; + } + + // Comparison of nullptr_t with itself. if (lType->isNullPtrType() && rType->isNullPtrType()) return ResultTy; } + // Handle block pointer types. if (!isRelational && lType->isBlockPointerType() && rType->isBlockPointerType()) { QualType lpointee = lType->getAs()->getPointeeType(); diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0434f304d877..d89a0909aa14 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1510,15 +1510,20 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, /// \brief Find a merged pointer type and convert the two expressions to it. /// -/// This finds the composite pointer type for @p E1 and @p E2 according to -/// C++0x 5.9p2. It converts both expressions to this type and returns it. +/// This finds the composite pointer type (or member pointer type) for @p E1 +/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this +/// type and returns it. /// It does not emit diagnostics. QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { assert(getLangOptions().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if(!T1->isAnyPointerType() && !T2->isAnyPointerType()) - return QualType(); + + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) + return QualType(); + // FIXME: Do we need to work on the canonical types? + // C++0x 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If @@ -1532,8 +1537,10 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { ImpCastExprToType(E2, T1); return T1; } - // Now both have to be pointers. - if(!T1->isPointerType() || !T2->isPointerType()) + + // Now both have to be pointers or member pointers. + if (!T1->isPointerType() && !T1->isMemberPointerType() && + !T2->isPointerType() && !T2->isMemberPointerType()) return QualType(); // Otherwise, of one of the operands has type "pointer to cv1 void," then @@ -1547,20 +1554,56 @@ QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) { // conversions in both directions. If only one works, or if the two composite // types are the same, we have succeeded. llvm::SmallVector QualifierUnion; + llvm::SmallVector, 4> MemberOfClass; QualType Composite1 = T1, Composite2 = T2; - const PointerType *Ptr1, *Ptr2; - while ((Ptr1 = Composite1->getAs()) && - (Ptr2 = Composite2->getAs())) { - Composite1 = Ptr1->getPointeeType(); - Composite2 = Ptr2->getPointeeType(); - QualifierUnion.push_back( - Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); - } - // Rewrap the composites as pointers with the union CVRs. - for (llvm::SmallVector::iterator I = QualifierUnion.begin(), - E = QualifierUnion.end(); I != E; ++I) { - Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); - Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + do { + const PointerType *Ptr1, *Ptr2; + if ((Ptr1 = Composite1->getAs()) && + (Ptr2 = Composite2->getAs())) { + Composite1 = Ptr1->getPointeeType(); + Composite2 = Ptr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair((const Type *)0, (const Type *)0)); + continue; + } + + const MemberPointerType *MemPtr1, *MemPtr2; + if ((MemPtr1 = Composite1->getAs()) && + (MemPtr2 = Composite2->getAs())) { + Composite1 = MemPtr1->getPointeeType(); + Composite2 = MemPtr2->getPointeeType(); + QualifierUnion.push_back( + Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); + MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), + MemPtr2->getClass())); + continue; + } + + // FIXME: block pointer types? + + // Cannot unwrap any more types. + break; + } while (true); + + // Rewrap the composites as pointers or member pointers with the union CVRs. + llvm::SmallVector, 4>::iterator MOC + = MemberOfClass.begin(); + for (llvm::SmallVector::iterator + I = QualifierUnion.begin(), + E = QualifierUnion.end(); + I != E; (void)++I, ++MOC) { + if (MOC->first && MOC->second) { + // Rebuild member pointer type + Composite1 = Context.getMemberPointerType(Composite1.getQualifiedType(*I), + MOC->first); + Composite2 = Context.getMemberPointerType(Composite2.getQualifiedType(*I), + MOC->second); + } else { + // Rebuild pointer type + Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I)); + Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I)); + } } ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1); diff --git a/clang/test/SemaCXX/composite-pointer-type.cpp b/clang/test/SemaCXX/composite-pointer-type.cpp index b4a5c884f755..ebc40c14b743 100644 --- a/clang/test/SemaCXX/composite-pointer-type.cpp +++ b/clang/test/SemaCXX/composite-pointer-type.cpp @@ -25,3 +25,11 @@ void f1(volatile Base *b, Derived1 *d1, const Derived2 *d2) { if (d1 == d2) // expected-error{{comparison of distinct}} return; } + +// PR4691 +int ptrcmp1(void *a, int *b) { + return a < b; +} +int ptrcmp2(long *a, int *b) { + return a < b; // expected-error{{distinct}} +} \ No newline at end of file diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index 3f4d7159a0f8..65fbd83e6d25 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -170,7 +170,7 @@ void test() 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}} + (void)(i1 ? &MixedFields::ci : &MixedFields::vi); // Conversion of primitives does not result in an lvalue. &(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}} diff --git a/clang/test/SemaCXX/member-pointer.cpp b/clang/test/SemaCXX/member-pointer.cpp index 3b106d5576fe..9e407a184c30 100644 --- a/clang/test/SemaCXX/member-pointer.cpp +++ b/clang/test/SemaCXX/member-pointer.cpp @@ -40,6 +40,14 @@ void f() { // Conversion to member of base. pdi1 = pdid; // expected-error {{incompatible type assigning 'int struct D::*', expected 'int struct A::*'}} + + // Comparisons + int (A::*pf2)(int, int); + int (D::*pf3)(int, int) = 0; + bool b1 = (pf == pf2); (void)b1; + bool b2 = (pf != pf2); (void)b2; + bool b3 = (pf == pf3); (void)b3; + bool b4 = (pf != 0); (void)b4; } struct TheBase diff --git a/clang/test/SemaCXX/overloaded-builtin-operators.cpp b/clang/test/SemaCXX/overloaded-builtin-operators.cpp index 2a6c24a6778a..a8c94f182225 100644 --- a/clang/test/SemaCXX/overloaded-builtin-operators.cpp +++ b/clang/test/SemaCXX/overloaded-builtin-operators.cpp @@ -20,11 +20,21 @@ struct Enum2 { operator E2(); }; + +struct X { + void f(); +}; + +typedef void (X::*pmf)(); +struct Xpmf { + operator pmf(); +}; + yes& islong(long); yes& islong(unsigned long); // FIXME: shouldn't be needed no& islong(int); -void f(Short s, Long l, Enum1 e1, Enum2 e2) { +void f(Short s, Long l, Enum1 e1, Enum2 e2, Xpmf pmf) { // C++ [over.built]p8 int i1 = +e1; int i2 = -e2; @@ -37,6 +47,10 @@ void f(Short s, Long l, Enum1 e1, Enum2 e2) { (void)static_cast(islong(s + l)); (void)static_cast(islong(s + s)); + // C++ [over.built]p16 + (void)(pmf == &X::f); + (void)(pmf == 0); + // C++ [over.built]p17 (void)static_cast(islong(s % l)); (void)static_cast(islong(l << s)); @@ -53,7 +67,15 @@ struct LongRef { operator volatile long&(); }; -void g(ShortRef sr, LongRef lr) { +struct XpmfRef { + operator pmf&(); +}; + +struct E2Ref { + operator E2&(); +}; + +void g(ShortRef sr, LongRef lr, E2Ref e2_ref, XpmfRef pmf_ref) { // C++ [over.built]p3 short s1 = sr++; @@ -64,6 +86,14 @@ void g(ShortRef sr, LongRef lr) { short& sr1 = (sr *= lr); volatile long& lr1 = (lr *= sr); + // C++ [over.built]p20: + E2 e2r2; + e2r2 = e2_ref; + + pmf &pmr = (pmf_ref = &X::f); // expected-error{{no viable overloaded '='}} + pmf pmr2; + pmr2 = pmf_ref; + // C++ [over.built]p22 short& sr2 = (sr %= lr); volatile long& lr2 = (lr <<= sr); diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index 05f3a0d00c4b..d01c5a7752b6 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1764,7 +1764,7 @@ welcome!

N/A - Missing pointer-to-member versions (p11, p16) and support for + Missing support for the ->* operator (p11, p16) and support for the ternary operator (p24, p25).