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). |