From 8d6d06761fcb7550a47796fa7198ac3434f2ff09 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 1 Dec 2010 21:43:58 +0000 Subject: [PATCH] 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 . llvm-svn: 120607 --- clang/lib/Sema/SemaOverload.cpp | 59 +++++++++++----------- clang/test/SemaObjCXX/objc-pointer-conv.mm | 4 +- clang/test/SemaObjCXX/overload.mm | 42 ++++++++++----- 3 files changed, 62 insertions(+), 43 deletions(-) diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 5da655907cf8..ce66c3c0fc29 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -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(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(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(), + ToPointeeType, ToType, Context); return true; - } const PointerType *FromTypePtr = FromType->getAs(); if (!FromTypePtr) @@ -1561,6 +1552,12 @@ bool Sema::isObjCPointerConversion(QualType FromType, QualType ToType, FromType->getAs(); 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() && isObjCPointerConversion(FromPointeeType, ToPointeeType, ConvertedType, IncompatibleObjC)) { - ConvertedType = ToType; + ConvertedType = Context.getPointerType(ConvertedType); return true; } diff --git a/clang/test/SemaObjCXX/objc-pointer-conv.mm b/clang/test/SemaObjCXX/objc-pointer-conv.mm index 335c240c171d..e40dab749c6a 100644 --- a/clang/test/SemaObjCXX/objc-pointer-conv.mm +++ b/clang/test/SemaObjCXX/objc-pointer-conv.mm @@ -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 *'}} } diff --git a/clang/test/SemaObjCXX/overload.mm b/clang/test/SemaObjCXX/overload.mm index 7ac4d8240c60..84aedf6b69a5 100644 --- a/clang/test/SemaObjCXX/overload.mm +++ b/clang/test/SemaObjCXX/overload.mm @@ -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); + } + + +}