[cfe-commits] r133303 - in /cfe/trunk: docs/AutomaticReferenceCounting.html lib/AST/TemplateBase.cpp lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/TreeTransform.h lib/Sema/TypeLocBuilder.h test/SemaObjCXX/arc-templates.mm

Douglas Gregor dgregor at apple.com
Fri Jun 17 15:11:49 PDT 2011


Author: dgregor
Date: Fri Jun 17 17:11:49 2011
New Revision: 133303

URL: http://llvm.org/viewvc/llvm-project?rev=133303&view=rev
Log:
Objective-ARC++: infer template type arguments of
ownership-unqualified retainable object type as __strong. This allows
us to write, e.g.,

  std::vector<id>

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<typename T>
  struct X {
    typedef __weak T type;
  };

X<id> 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 <rdar://problem/9595486>.


Modified:
    cfe/trunk/docs/AutomaticReferenceCounting.html
    cfe/trunk/lib/AST/TemplateBase.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Sema/TypeLocBuilder.h
    cfe/trunk/test/SemaObjCXX/arc-templates.mm

Modified: cfe/trunk/docs/AutomaticReferenceCounting.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/AutomaticReferenceCounting.html?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/docs/AutomaticReferenceCounting.html (original)
+++ cfe/trunk/docs/AutomaticReferenceCounting.html Fri Jun 17 17:11:49 2011
@@ -978,9 +978,23 @@
 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>
 

Modified: cfe/trunk/lib/AST/TemplateBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateBase.cpp?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/lib/AST/TemplateBase.cpp (original)
+++ cfe/trunk/lib/AST/TemplateBase.cpp Fri Jun 17 17:11:49 2011
@@ -277,8 +277,10 @@
     break;
     
   case Type: {
+    PrintingPolicy SubPolicy(Policy);
+    SubPolicy.SuppressStrongLifetime = true;
     std::string TypeStr;
-    getAsType().getAsStringInternal(TypeStr, Policy);
+    getAsType().getAsStringInternal(TypeStr, SubPolicy);
     Out << TypeStr;
     break;
   }

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Fri Jun 17 17:11:49 2011
@@ -2357,8 +2357,20 @@
     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;
 }
 

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 17 17:11:49 2011
@@ -1016,6 +1016,15 @@
       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);
     

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Jun 17 17:11:49 2011
@@ -3173,12 +3173,34 @@
     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);

Modified: cfe/trunk/lib/Sema/TypeLocBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TypeLocBuilder.h?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TypeLocBuilder.h (original)
+++ cfe/trunk/lib/Sema/TypeLocBuilder.h Fri Jun 17 17:11:49 2011
@@ -91,7 +91,6 @@
   /// 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
   }

Modified: cfe/trunk/test/SemaObjCXX/arc-templates.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/arc-templates.mm?rev=133303&r1=133302&r2=133303&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjCXX/arc-templates.mm (original)
+++ cfe/trunk/test/SemaObjCXX/arc-templates.mm Fri Jun 17 17:11:49 2011
@@ -17,15 +17,13 @@
 // 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 @@
   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 @@
   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 @@
 
 // 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 { };





More information about the cfe-commits mailing list