diff options
-rw-r--r-- | docs/AutomaticReferenceCounting.html | 14 | ||||
-rw-r--r-- | lib/AST/TemplateBase.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 16 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 34 | ||||
-rw-r--r-- | lib/Sema/TypeLocBuilder.h | 1 | ||||
-rw-r--r-- | test/SemaObjCXX/arc-templates.mm | 39 |
7 files changed, 100 insertions, 17 deletions
diff --git a/docs/AutomaticReferenceCounting.html b/docs/AutomaticReferenceCounting.html index 3d34ddb310..e7b8f22365 100644 --- a/docs/AutomaticReferenceCounting.html +++ b/docs/AutomaticReferenceCounting.html @@ -978,9 +978,23 @@ pointer type. Such code is still ill-formed.</p> to be intentional in template code.</p></div> </div> <!-- ownership.inference.indirect_parameters --> + +<div id="ownership.inference.template_arguments"> +<h1>Template arguments</h1> + +<p>If a template argument for a template type parameter is an +retainable object owner type that does not have an explicit ownership +qualifier, it is adjusted to have <tt>__strong</tt> +qualification. This adjustment occurs both regardless of whether the +template argument was deduced or explicitly specified. </p> + +<div class="rationale"><p>Rationale: <tt>__strong</tt> is a useful default for containers (e.g., <tt>std::vector<id></tt>), which would otherwise require explicit qualification. Moreover, unqualified retainable object pointer types are unlikely to be useful within templates, since they generally need to have a qualifier applied to the before being used.</p></div> + +</div> <!-- ownership.inference.template_arguments --> </div> <!-- ownership.inference --> </div> <!-- ownership --> + <div id="family"> <h1>Method families</h1> diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 6114a5a051..103da1d8a4 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -277,8 +277,10 @@ void TemplateArgument::print(const PrintingPolicy &Policy, break; case Type: { + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressStrongLifetime = true; std::string TypeStr; - getAsType().getAsStringInternal(TypeStr, Policy); + getAsType().getAsStringInternal(TypeStr, SubPolicy); Out << TypeStr; break; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b8caad8af5..fa2182a2aa 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2357,8 +2357,20 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, return true; // Add the converted template type argument. - Converted.push_back( - TemplateArgument(Context.getCanonicalType(Arg.getAsType()))); + QualType ArgType = Context.getCanonicalType(Arg.getAsType()); + + // Objective-C ARC: + // If an explicitly-specified template argument type is a lifetime type + // with no lifetime qualifier, the __strong lifetime qualifier is inferred. + if (getLangOptions().ObjCAutoRefCount && + ArgType->isObjCLifetimeType() && + !ArgType.getObjCLifetime()) { + Qualifiers Qs; + Qs.setObjCLifetime(Qualifiers::OCL_Strong); + ArgType = Context.getQualifiedType(ArgType, Qs); + } + + Converted.push_back(TemplateArgument(ArgType)); return false; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index af359316da..b5e9c25d85 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -1016,6 +1016,15 @@ DeduceTemplateArguments(Sema &S, DeducedQs.removeAddressSpace(); if (ParamQs.hasObjCLifetime()) DeducedQs.removeObjCLifetime(); + + // Objective-C ARC: + // If template deduction would produce an argument type with lifetime type + // but no lifetime qualifier, the __strong lifetime qualifier is inferred. + if (S.getLangOptions().ObjCAutoRefCount && + DeducedType->isObjCLifetimeType() && + !DeducedQs.hasObjCLifetime()) + DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ba4ee3426a..d33e7a5c4c 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3173,12 +3173,34 @@ TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB, return Result; // Suppress Objective-C lifetime qualifiers if they don't make sense for the - // resulting type or if the resulting type already has one. - if (Quals.hasObjCLifetime() && - (Result.getObjCLifetime() || - (!Result->isObjCLifetimeType() && !Result->isDependentType()))) - Quals.removeObjCLifetime(); - + // resulting type. + if (Quals.hasObjCLifetime()) { + if (!Result->isObjCLifetimeType() && !Result->isDependentType()) + Quals.removeObjCLifetime(); + else if (Result.getObjCLifetime() && + Result.getObjCLifetime() != Quals.getObjCLifetime()) { + // Objective-C ARC: + // A lifetime qualifier applied to a substituted template parameter + // overrides the lifetime qualifier from the template argument. + if (const SubstTemplateTypeParmType *SubstTypeParam + = dyn_cast<SubstTemplateTypeParmType>(Result)) { + QualType Replacement = SubstTypeParam->getReplacementType(); + Qualifiers Qs = Replacement.getQualifiers(); + Qs.removeObjCLifetime(); + Replacement + = SemaRef.Context.getQualifiedType(Replacement.getUnqualifiedType(), + Qs); + Result = SemaRef.Context.getSubstTemplateTypeParmType( + SubstTypeParam->getReplacedParameter(), + Replacement); + TLB.TypeWasModifiedSafely(Result); + } else { + // Otherwise, drop the new qualifier. + // FIXME: I don't recall the justification for this! + Quals.removeObjCLifetime(); + } + } + } if (!Quals.empty()) { Result = SemaRef.BuildQualifiedType(Result, T.getBeginLoc(), Quals); TLB.push<QualifiedTypeLoc>(Result); diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index f0944f1205..792bd1fc72 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -91,7 +91,6 @@ class TypeLocBuilder { /// modified in some safe way that doesn't affect type-location information. void TypeWasModifiedSafely(QualType T) { #ifndef NDEBUG - assert(T.getLocalUnqualifiedType() == LastTy.getLocalUnqualifiedType()); LastTy = T; #endif } diff --git a/test/SemaObjCXX/arc-templates.mm b/test/SemaObjCXX/arc-templates.mm index eeaed89876..3711bd72df 100644 --- a/test/SemaObjCXX/arc-templates.mm +++ b/test/SemaObjCXX/arc-templates.mm @@ -17,15 +17,13 @@ struct is_same<T, T> { // adjustments. template<typename T> struct X0 { - typedef T* pointer; // expected-error{{pointer to non-const type 'id' with no explicit lifetime}} \ - // expected-error{{pointer to non-const type 'A *' with no explicit lifetime}} - typedef T& reference; // expected-error{{reference to non-const type 'id' with no explicit lifetime}} \ - // expected-error{{reference to non-const type 'A *' with no explicit lifetime}} + typedef T* pointer; // okay: ends up being strong. + typedef T& reference; // okay: ends up being strong }; void test_X0() { - X0<id> x0id; // expected-note{{in instantiation of template class 'X0<id>' requested here}} - X0<A*> x0a; // expected-note{{in instantiation of template class 'X0<A *>' requested here}} + X0<id> x0id; + X0<A*> x0a; X0<__strong A*> x0sa; id __strong *ptr; @@ -34,6 +32,8 @@ void test_X0() { X0<__strong id>::reference ref = val; } +int check_infer_strong[is_same<id, __strong id>::value? 1 : -1]; + // Check template argument deduction (e.g., for specialization) using // lifetime qualifiers. template<typename T> @@ -58,6 +58,21 @@ struct make_strong_pointer { typedef __strong T *type; }; +template<typename T> +struct make_strong_pointer<__weak T> { + typedef __strong T *type; +}; + +template<typename T> +struct make_strong_pointer<__autoreleasing T> { + typedef __strong T *type; +}; + +template<typename T> +struct make_strong_pointer<__unsafe_unretained T> { + typedef __strong T *type; +}; + // Adding qualifiers int check_make_strong1[is_same<make_strong_pointer<id>::type, __strong id *>::value ? 1 : -1]; int check_make_strong2[is_same<make_strong_pointer<A*>::type, A* __strong *>::value ? 1 : -1]; @@ -68,7 +83,17 @@ int check_make_strong4[is_same<make_strong_pointer<__strong A*>::type, A* __stro // Adding nonsensical qualifiers. int check_make_strong5[is_same<make_strong_pointer<int>::type, int *>::value ? 1 : -1]; -int check_make_strong6[is_same<make_strong_pointer<__weak id>::type, __weak id *>::value ? 1 : -1]; +int check_make_strong6[is_same<make_strong_pointer<__weak id>::type, __strong id *>::value ? 1 : -1]; + +template<typename T> +struct make_weak { + typedef __weak T type; +}; + +int check_make_weak0[is_same<make_weak<id>::type, __weak id>::value? 1 : -1]; +int check_make_weak1[is_same<make_weak<__strong id>::type, __weak id>::value? 1 : -1]; +int check_make_weak2[is_same<make_weak<__autoreleasing id>::type, __weak id>::value? 1 : -1]; + // Check template argument deduction from function templates. template<typename T> struct identity { }; |