From 3940e3b9c7cc89284117112e07ad1c925dcd0ab4 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Fri, 8 Nov 2013 02:04:24 +0000 Subject: [PATCH] Objective-C++ ARC: Improve the conversion to a const __unsafe_unretained reference. 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 . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194239 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaOverload.cpp | 19 +++++++++++++++++-- lib/Sema/SemaTemplateDeduction.cpp | 17 ++++++++++------- test/SemaObjCXX/arc-templates.mm | 10 ++++++++++ 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index acfa8a3ac7..2c2cfd03b1 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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) diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 6e510c2dbc..b401db21a8 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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()) && diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm index ef68b94e72..b3519b9573 100644 --- a/test/SemaObjCXX/arc-templates.mm +++ b/test/SemaObjCXX/arc-templates.mm @@ -292,3 +292,13 @@ namespace rdar12367446 { A value; } } + +namespace rdar14467941 { + template int &takePtr(const T &); + template float &takePtr(T * const &); + + void testTakePtr(A *a) { + float &fr1 = takePtr(a); + float &fr2 = takePtr(a); + } +} -- 2.40.0