aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/AutomaticReferenceCounting.html14
-rw-r--r--lib/AST/TemplateBase.cpp4
-rw-r--r--lib/Sema/SemaTemplate.cpp16
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp9
-rw-r--r--lib/Sema/TreeTransform.h34
-rw-r--r--lib/Sema/TypeLocBuilder.h1
-rw-r--r--test/SemaObjCXX/arc-templates.mm39
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&lt;id&gt;</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 { };