forked from OSchip/llvm-project
Implement support for equality comparisons (!=, ==) of member
pointers, by extending the "composite pointer type" logic to include member pointer types. Introduce test cases for member pointer comparisons, including those that involve the builtin operator candidates implemented earlier. llvm-svn: 79925
This commit is contained in:
parent
e6434cb421
commit
b00b10eb2e
|
@ -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<BlockPointerType>()->getPointeeType();
|
||||
|
|
|
@ -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<unsigned, 4> QualifierUnion;
|
||||
llvm::SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass;
|
||||
QualType Composite1 = T1, Composite2 = T2;
|
||||
const PointerType *Ptr1, *Ptr2;
|
||||
while ((Ptr1 = Composite1->getAs<PointerType>()) &&
|
||||
(Ptr2 = Composite2->getAs<PointerType>())) {
|
||||
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<unsigned, 4>::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<PointerType>()) &&
|
||||
(Ptr2 = Composite2->getAs<PointerType>())) {
|
||||
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<MemberPointerType>()) &&
|
||||
(MemPtr2 = Composite2->getAs<MemberPointerType>())) {
|
||||
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<std::pair<const Type *, const Type *>, 4>::iterator MOC
|
||||
= MemberOfClass.begin();
|
||||
for (llvm::SmallVector<unsigned, 4>::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);
|
||||
|
|
|
@ -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}}
|
||||
}
|
|
@ -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}}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<yes&>(islong(s + l));
|
||||
(void)static_cast<no&>(islong(s + s));
|
||||
|
||||
// C++ [over.built]p16
|
||||
(void)(pmf == &X::f);
|
||||
(void)(pmf == 0);
|
||||
|
||||
// C++ [over.built]p17
|
||||
(void)static_cast<yes&>(islong(s % l));
|
||||
(void)static_cast<yes&>(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);
|
||||
|
|
|
@ -1764,7 +1764,7 @@ welcome!</p>
|
|||
<td class="advanced" align="center"></td>
|
||||
<td class="medium" align="center"></td>
|
||||
<td class="na" align="center">N/A</td>
|
||||
<td>Missing pointer-to-member versions (p11, p16) and support for
|
||||
<td>Missing support for the ->* operator (p11, p16) and support for
|
||||
the ternary operator (p24, p25).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
Loading…
Reference in New Issue