From: Douglas Gregor Date: Fri, 17 Jun 2011 22:11:49 +0000 (+0000) Subject: Objective-ARC++: infer template type arguments of X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e559ca1672ecef59345a928af0a6809b09282d2c;p=clang Objective-ARC++: infer template type arguments of ownership-unqualified retainable object type as __strong. This allows us to write, e.g., std::vector and we'll infer that the vector's element types have __strong ownership semantics, which is far nicer than requiring: std::vector<__strong id> Note that we allow one to override the ownership qualifier of a substituted template type parameter, e.g., given template struct X { typedef __weak T type; }; X is treated the same as X<__strong id>. At instantiation type, the __weak in "__weak T" overrides the (inferred or specified) __strong on the template argument type, so that we can still provide metaprogramming transformations. This is part of . git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133303 91177308-0d34-0410-b5e6-96231b3b80d8 --- 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.

to be intentional in template code.

+ +
+

Template arguments

+ +

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 __strong +qualification. This adjustment occurs both regardless of whether the +template argument was deduced or explicitly specified.

+ +

Rationale: __strong is a useful default for containers (e.g., std::vector<id>), 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.

+ +
+

Method families

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::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(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(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 { // adjustments. template 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 x0id; // expected-note{{in instantiation of template class 'X0' requested here}} - X0 x0a; // expected-note{{in instantiation of template class 'X0' requested here}} + X0 x0id; + X0 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::value? 1 : -1]; + // Check template argument deduction (e.g., for specialization) using // lifetime qualifiers. template @@ -58,6 +58,21 @@ struct make_strong_pointer { typedef __strong T *type; }; +template +struct make_strong_pointer<__weak T> { + typedef __strong T *type; +}; + +template +struct make_strong_pointer<__autoreleasing T> { + typedef __strong T *type; +}; + +template +struct make_strong_pointer<__unsafe_unretained T> { + typedef __strong T *type; +}; + // Adding qualifiers int check_make_strong1[is_same::type, __strong id *>::value ? 1 : -1]; int check_make_strong2[is_same::type, A* __strong *>::value ? 1 : -1]; @@ -68,7 +83,17 @@ int check_make_strong4[is_same::type, A* __stro // Adding nonsensical qualifiers. int check_make_strong5[is_same::type, int *>::value ? 1 : -1]; -int check_make_strong6[is_same::type, __weak id *>::value ? 1 : -1]; +int check_make_strong6[is_same::type, __strong id *>::value ? 1 : -1]; + +template +struct make_weak { + typedef __weak T type; +}; + +int check_make_weak0[is_same::type, __weak id>::value? 1 : -1]; +int check_make_weak1[is_same::type, __weak id>::value? 1 : -1]; +int check_make_weak2[is_same::type, __weak id>::value? 1 : -1]; + // Check template argument deduction from function templates. template struct identity { };