]> granicus.if.org Git - clang/commitdiff
Objective-C++ ARC: Improve the conversion to a const __unsafe_unretained reference.
authorDouglas Gregor <dgregor@apple.com>
Fri, 8 Nov 2013 02:04:24 +0000 (02:04 +0000)
committerDouglas Gregor <dgregor@apple.com>
Fri, 8 Nov 2013 02:04:24 +0000 (02:04 +0000)
Under ARC++, a reference to a const Objective-C pointer is implicitly
treated as __unsafe_unretained, and can be initialized with (e.g.) a
__strong lvalue. Make sure this behavior does not break template
argument deduction and (related) that partial ordering still prefers a
'T* const&' template over a 'T const&' template when this case kicks
in. Fixes <rdar://problem/14467941>.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194239 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaOverload.cpp
lib/Sema/SemaTemplateDeduction.cpp
test/SemaObjCXX/arc-templates.mm

index acfa8a3ac744208309cdb63430698a0fe03335f8..2c2cfd03b17ead2b24906ae2334eb48512a30c60 100644 (file)
@@ -2790,6 +2790,18 @@ bool Sema::CheckMemberPointerConversion(Expr *From, QualType ToType,
   return false;
 }
 
+/// Determine whether the lifetime conversion between the two given
+/// qualifiers sets is nontrivial.
+static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
+                                               Qualifiers ToQuals) {
+  // Converting anything to const __unsafe_unretained is trivial.
+  if (ToQuals.hasConst() && 
+      ToQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone)
+    return false;
+
+  return true;
+}
+
 /// IsQualificationConversion - Determines whether the conversion from
 /// an rvalue of type FromType to ToType is a qualification conversion
 /// (C++ 4.4).
@@ -2831,7 +2843,8 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
     if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
         UnwrappedAnyPointer) {
       if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
-        ObjCLifetimeConversion = true;
+        if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
+          ObjCLifetimeConversion = true;
         FromQuals.removeObjCLifetime();
         ToQuals.removeObjCLifetime();
       } else {
@@ -3996,9 +4009,11 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
   // space 2.
   if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
       T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
+    if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
+      ObjCLifetimeConversion = true;
+
     T1Quals.removeObjCLifetime();
     T2Quals.removeObjCLifetime();    
-    ObjCLifetimeConversion = true;
   }
     
   if (T1Quals == T2Quals)
index 6e510c2dbcb63ac2acc669ef3fc3593f651d7e71..b401db21a82cff9ceff96688f392175492818eac 100644 (file)
@@ -2687,13 +2687,16 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
     Qualifiers AQuals = A.getQualifiers();
     Qualifiers DeducedAQuals = DeducedA.getQualifiers();
 
-    // Under Objective-C++ ARC, the deduced type may have implicitly been
-    // given strong lifetime. If so, update the original qualifiers to
-    // include this strong lifetime.
+    // Under Objective-C++ ARC, the deduced type may have implicitly
+    // been given strong or (when dealing with a const reference)
+    // unsafe_unretained lifetime. If so, update the original
+    // qualifiers to include this lifetime.
     if (S.getLangOpts().ObjCAutoRefCount &&
-        DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
-        AQuals.getObjCLifetime() == Qualifiers::OCL_None) {
-      AQuals.setObjCLifetime(Qualifiers::OCL_Strong);
+        ((DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_Strong &&
+          AQuals.getObjCLifetime() == Qualifiers::OCL_None) ||
+         (DeducedAQuals.hasConst() &&
+          DeducedAQuals.getObjCLifetime() == Qualifiers::OCL_ExplicitNone))) {
+      AQuals.setObjCLifetime(DeducedAQuals.getObjCLifetime());
     }
 
     if (AQuals == DeducedAQuals) {
@@ -2714,7 +2717,7 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg,
   //
   // Also allow conversions which merely strip [[noreturn]] from function types
   // (recursively) as an extension.
-  // FIXME: Currently, this doesn't place nicely with qualfication conversions.
+  // FIXME: Currently, this doesn't play nicely with qualification conversions.
   bool ObjCLifetimeConversion = false;
   QualType ResultTy;
   if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
index ef68b94e7284170fbe5262937cef93556bd57e5a..b3519b9573729d645e8e422317911257f2c4556c 100644 (file)
@@ -292,3 +292,13 @@ namespace rdar12367446 {
     A<id()> value;
   }
 }
+
+namespace rdar14467941 {
+  template<typename T> int &takePtr(const T &);
+  template<typename T> float &takePtr(T * const &);
+
+  void testTakePtr(A *a) {
+    float &fr1 = takePtr(a);
+    float &fr2 = takePtr<A>(a);
+  }
+}