forked from OSchip/llvm-project
Improve our handling of cv-qualifiers in Objective-C pointer
conversions. Previously, we would end up collapsing qualification conversions into the Objective-C pointer conversion step, including (possibly) stripping qualifiers that shouldn't be removed. This generalizes BuildSimilarlyQualifiedPointerType() to also work on Objective-C object pointers, then eliminates the (redundant, not totally correct) BuildSimilarlyQualifiedObjCObjectPointerType() function. Fixes <rdar://problem/8714395>. llvm-svn: 120607
This commit is contained in:
parent
3670ba5c87
commit
8d6d06761f
|
@ -1358,10 +1358,14 @@ bool Sema::IsComplexPromotion(QualType FromType, QualType ToType) {
|
|||
/// if non-empty, will be a pointer to ToType that may or may not have
|
||||
/// the right set of qualifiers on its pointee.
|
||||
static QualType
|
||||
BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
|
||||
BuildSimilarlyQualifiedPointerType(const Type *FromPtr,
|
||||
QualType ToPointee, QualType ToType,
|
||||
ASTContext &Context) {
|
||||
QualType CanonFromPointee = Context.getCanonicalType(FromPtr->getPointeeType());
|
||||
assert((FromPtr->getTypeClass() == Type::Pointer ||
|
||||
FromPtr->getTypeClass() == Type::ObjCObjectPointer) &&
|
||||
"Invalid similarly-qualified pointer type");
|
||||
QualType CanonFromPointee
|
||||
= Context.getCanonicalType(FromPtr->getPointeeType());
|
||||
QualType CanonToPointee = Context.getCanonicalType(ToPointee);
|
||||
Qualifiers Quals = CanonFromPointee.getQualifiers();
|
||||
|
||||
|
@ -1373,32 +1377,18 @@ BuildSimilarlyQualifiedPointerType(const PointerType *FromPtr,
|
|||
|
||||
// Build a pointer to ToPointee. It has the right qualifiers
|
||||
// already.
|
||||
if (isa<ObjCObjectPointerType>(ToType))
|
||||
return Context.getObjCObjectPointerType(ToPointee);
|
||||
return Context.getPointerType(ToPointee);
|
||||
}
|
||||
|
||||
// Just build a canonical type that has the right qualifiers.
|
||||
return Context.getPointerType(
|
||||
Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(),
|
||||
Quals));
|
||||
}
|
||||
|
||||
/// BuildSimilarlyQualifiedObjCObjectPointerType - In a pointer conversion from
|
||||
/// the FromType, which is an objective-c pointer, to ToType, which may or may
|
||||
/// not have the right set of qualifiers.
|
||||
static QualType
|
||||
BuildSimilarlyQualifiedObjCObjectPointerType(QualType FromType,
|
||||
QualType ToType,
|
||||
ASTContext &Context) {
|
||||
QualType CanonFromType = Context.getCanonicalType(FromType);
|
||||
QualType CanonToType = Context.getCanonicalType(ToType);
|
||||
Qualifiers Quals = CanonFromType.getQualifiers();
|
||||
|
||||
// Exact qualifier match -> return the pointer type we're converting to.
|
||||
if (CanonToType.getLocalQualifiers() == Quals)
|
||||
return ToType;
|
||||
QualType QualifiedCanonToPointee
|
||||
= Context.getQualifiedType(CanonToPointee.getLocalUnqualifiedType(), Quals);
|
||||
|
||||
// Just build a canonical type that has the right qualifiers.
|
||||
return Context.getQualifiedType(CanonToType.getLocalUnqualifiedType(), Quals);
|
||||
if (isa<ObjCObjectPointerType>(ToType))
|
||||
return Context.getObjCObjectPointerType(QualifiedCanonToPointee);
|
||||
return Context.getPointerType(QualifiedCanonToPointee);
|
||||
}
|
||||
|
||||
static bool isNullPointerConstantForConversion(Expr *Expr,
|
||||
|
@ -1482,10 +1472,11 @@ bool Sema::IsPointerConversion(Expr *From, QualType FromType, QualType ToType,
|
|||
// , including objective-c pointers.
|
||||
QualType ToPointeeType = ToTypePtr->getPointeeType();
|
||||
if (FromType->isObjCObjectPointerType() && ToPointeeType->isVoidType()) {
|
||||
ConvertedType = BuildSimilarlyQualifiedObjCObjectPointerType(FromType,
|
||||
ConvertedType = BuildSimilarlyQualifiedPointerType(
|
||||
FromType->getAs<ObjCObjectPointerType>(),
|
||||
ToPointeeType,
|
||||
ToType, Context);
|
||||
return true;
|
||||
|
||||
}
|
||||
const PointerType *FromTypePtr = FromType->getAs<PointerType>();
|
||||
if (!FromTypePtr)
|
||||
|
@ -1561,6 +1552,12 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
FromType->getAs<ObjCObjectPointerType>();
|
||||
|
||||
if (ToObjCPtr && FromObjCPtr) {
|
||||
// If the pointee types are the same (ignoring qualifications),
|
||||
// then this is not a pointer conversion.
|
||||
if (Context.hasSameUnqualifiedType(ToObjCPtr->getPointeeType(),
|
||||
FromObjCPtr->getPointeeType()))
|
||||
return false;
|
||||
|
||||
// Objective C++: We're able to convert between "id" or "Class" and a
|
||||
// pointer to any interface (in both directions).
|
||||
if (ToObjCPtr->isObjCBuiltinType() && FromObjCPtr->isObjCBuiltinType()) {
|
||||
|
@ -1584,7 +1581,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
!ToObjCPtr->getPointeeType().isAtLeastAsQualifiedAs(
|
||||
FromObjCPtr->getPointeeType()))
|
||||
return false;
|
||||
ConvertedType = ToType;
|
||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
|
||||
ToObjCPtr->getPointeeType(),
|
||||
ToType, Context);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1593,7 +1592,9 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
// interfaces, which is permitted. However, we're going to
|
||||
// complain about it.
|
||||
IncompatibleObjC = true;
|
||||
ConvertedType = FromType;
|
||||
ConvertedType = BuildSimilarlyQualifiedPointerType(FromObjCPtr,
|
||||
ToObjCPtr->getPointeeType(),
|
||||
ToType, Context);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1636,7 +1637,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
IncompatibleObjC)) {
|
||||
// We always complain about this conversion.
|
||||
IncompatibleObjC = true;
|
||||
ConvertedType = ToType;
|
||||
ConvertedType = Context.getPointerType(ConvertedType);
|
||||
return true;
|
||||
}
|
||||
// Allow conversion of pointee being objective-c pointer to another one;
|
||||
|
@ -1645,7 +1646,7 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType,
|
|||
ToPointeeType->getAs<ObjCObjectPointerType>() &&
|
||||
isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType,
|
||||
IncompatibleObjC)) {
|
||||
ConvertedType = ToType;
|
||||
ConvertedType = Context.getPointerType(ConvertedType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ void foo(const I *p, I* sel) {
|
|||
@interface DerivedFromI : I
|
||||
@end
|
||||
|
||||
void accept_derived(DerivedFromI*); // expected-note{{candidate function not viable: cannot convert from superclass 'I *' to subclass 'DerivedFromI *' for 1st argument}}
|
||||
void accept_derived(DerivedFromI*);
|
||||
|
||||
void test_base_to_derived(I* i) {
|
||||
accept_derived(i); // expected-error{{no matching function for call to 'accept_derived'}}
|
||||
accept_derived(i); // expected-warning{{incompatible pointer types converting 'I *' to type 'DerivedFromI *'}}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,8 @@ int& f(A*); // expected-note {{candidate}}
|
|||
float& f(B*); // expected-note {{candidate}}
|
||||
void g(A*);
|
||||
|
||||
int& h(A*);
|
||||
float& h(id);
|
||||
int& h(A*); // expected-note{{candidate}}
|
||||
float& h(id); // expected-note{{candidate}}
|
||||
|
||||
void test0(A* a, B* b, id val) {
|
||||
int& i1 = f(a);
|
||||
|
@ -46,13 +46,14 @@ void test0(A* a, B* b, id val) {
|
|||
g(val);
|
||||
int& i2 = h(a);
|
||||
float& f3 = h(val);
|
||||
// int& i3 = h(b); FIXME: we match GCC here, but shouldn't this work?
|
||||
|
||||
// FIXME: we match GCC here, but shouldn't this work?
|
||||
int& i3 = h(b); // expected-error{{call to 'h' is ambiguous}}
|
||||
}
|
||||
|
||||
// We make these errors instead of warnings. Is that okay?
|
||||
void test1(A* a) {
|
||||
B* b = a; // expected-error{{cannot initialize a variable of type 'B *' with an lvalue of type 'A *'}}
|
||||
B *c; c = a; // expected-error{{assigning to 'B *' from incompatible type 'A *'}}
|
||||
B* b = a; // expected-warning{{incompatible pointer types converting 'A *' to type 'B *'}}
|
||||
B *c; c = a; // expected-warning{{incompatible pointer types assigning to 'A *' from 'B *'}}
|
||||
}
|
||||
|
||||
void test2(A** ap) {
|
||||
|
@ -64,18 +65,16 @@ void test2(A** ap) {
|
|||
int& cv(A*); // expected-note {{previous declaration}} expected-note 2 {{not viable}}
|
||||
float& cv(const A*); // expected-error {{cannot be overloaded}}
|
||||
|
||||
int& cv2(void*); // expected-note 2 {{candidate}}
|
||||
float& cv2(const void*); // expected-note 2 {{candidate}}
|
||||
int& cv2(void*);
|
||||
float& cv2(const void*);
|
||||
|
||||
void cv_test(A* a, B* b, const A* ac, const B* bc) {
|
||||
int &i1 = cv(a);
|
||||
int &i2 = cv(b);
|
||||
float &f1 = cv(ac); // expected-error {{no matching function}}
|
||||
float &f2 = cv(bc); // expected-error {{no matching function}}
|
||||
|
||||
// FIXME: these should not be ambiguous
|
||||
int& i3 = cv2(a); // expected-error {{ambiguous}}
|
||||
float& f3 = cv2(ac); // expected-error {{ambiguous}}
|
||||
int& i3 = cv2(a);
|
||||
float& f3 = cv2(ac);
|
||||
}
|
||||
|
||||
// We agree with GCC that these can't be overloaded.
|
||||
|
@ -124,3 +123,22 @@ namespace test6 {
|
|||
foo(b); // expected-error {{call to 'foo' is ambiguous}}
|
||||
}
|
||||
}
|
||||
|
||||
namespace rdar8714395 {
|
||||
int &f(const void*);
|
||||
float &f(const Foo*);
|
||||
|
||||
int &f2(const void*);
|
||||
float &f2(Foo const* const *);
|
||||
|
||||
int &f3(const void*);
|
||||
float &f3(Foo const**);
|
||||
|
||||
void g(Foo *p) {
|
||||
float &fr = f(p);
|
||||
float &fr2 = f2(&p);
|
||||
int &ir = f3(&p);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue