]> granicus.if.org Git - clang/commitdiff
ObjectiveC arc[qoi]: When due to change of certain methods'
authorFariborz Jahanian <fjahanian@apple.com>
Thu, 11 Jul 2013 16:48:06 +0000 (16:48 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Thu, 11 Jul 2013 16:48:06 +0000 (16:48 +0000)
result type, a diagnostic being issued, issue a 'note'
mentioning reason behind the unexpected warning.
// rdar://14121570.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@186105 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/Initialization.h
lib/Sema/SemaInit.cpp
lib/Sema/SemaStmt.cpp
test/SemaObjC/related-result-type-inference.m

index 9a075fe8c8a33418aba3b4204818463a23d769b5..d6b42533a01707eb4d96af7d8e5c67a2c74521ed 100644 (file)
@@ -4683,6 +4683,8 @@ def note_parameter_named_here : Note<
   "passing argument to parameter %0 here">;
 def note_parameter_here : Note<
   "passing argument to parameter here">;
+def note_method_return_type_change : Note<
+  "compiler has implicitly changed method %0 return type">;
 
 // C++ casts
 // These messages adhere to the TryCast pattern: %0 is an int specifying the
index 97311a0bb4dcd2c72ecaf6c5d64fb99522d6885a..d695e33a64c26feb36fdf0ae35ffd3923194c402 100644 (file)
@@ -35,6 +35,7 @@ class ParmVarDecl;
 class Sema;
 class TypeLoc;
 class VarDecl;
+class ObjCMethodDecl;
   
 /// \brief Describes an entity that is being initialized.
 class InitializedEntity {
@@ -78,7 +79,10 @@ public:
     EK_LambdaCapture,
     /// \brief The entity being initialized is the initializer for a compound
     /// literal.
-    EK_CompoundLiteralInit
+    EK_CompoundLiteralInit,
+    /// \brief The entity being implicitly initialized back to the formal
+    /// result type.
+    EK_RelatedResult
   };
   
 private:
@@ -116,6 +120,10 @@ private:
     /// \brief When Kind == EK_Variable, or EK_Member, the VarDecl or
     /// FieldDecl, respectively.
     DeclaratorDecl *VariableOrMember;
+    
+    /// \brief When Kind == EK_RelatedResult, the ObjectiveC method where
+    /// result type was implicitly changed to accomodate ARC semantics.
+    ObjCMethodDecl *MethodDecl;
 
     /// \brief When Kind == EK_Parameter, the ParmVarDecl, with the
     /// low bit indicating whether the parameter is "consumed".
@@ -254,6 +262,15 @@ public:
     Result.TypeInfo = TypeInfo;
     return Result;
   }
+  
+  /// \brief Create the initialization entity for a related result.
+  static InitializedEntity InitializeRelatedResult(ObjCMethodDecl *MD,
+                                                   QualType Type) {
+    InitializedEntity Result(EK_RelatedResult, SourceLocation(), Type);
+    Result.MethodDecl = MD;
+    return Result;
+  }
+
 
   /// \brief Create the initialization entity for a base class subobject.
   static InitializedEntity InitializeBase(ASTContext &Context,
@@ -326,6 +343,9 @@ public:
   /// \brief Retrieve the variable, parameter, or field being
   /// initialized.
   DeclaratorDecl *getDecl() const;
+  
+  /// \brief Retrieve the ObjectiveC method being initialized.
+  ObjCMethodDecl *getMethodDecl() const { return MethodDecl; }
 
   /// \brief Determine whether this initialization allows the named return 
   /// value optimization, which also applies to thrown objects.
index 96291923bd2b73e3d7d80cea17112a712443b3f6..1898a159306f115eb5ae1d6774780e495e8d6f26 100644 (file)
@@ -2495,6 +2495,7 @@ DeclarationName InitializedEntity::getName() const {
   case EK_ComplexElement:
   case EK_BlockElement:
   case EK_CompoundLiteralInit:
+  case EK_RelatedResult:
     return DeclarationName();
   }
 
@@ -2522,6 +2523,7 @@ DeclaratorDecl *InitializedEntity::getDecl() const {
   case EK_BlockElement:
   case EK_LambdaCapture:
   case EK_CompoundLiteralInit:
+  case EK_RelatedResult:
     return 0;
   }
 
@@ -2547,6 +2549,7 @@ bool InitializedEntity::allowsNRVO() const {
   case EK_ComplexElement:
   case EK_BlockElement:
   case EK_LambdaCapture:
+  case EK_RelatedResult:
     break;
   }
 
@@ -2568,6 +2571,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
   case EK_New: OS << "New"; break;
   case EK_Temporary: OS << "Temporary"; break;
   case EK_CompoundLiteralInit: OS << "CompoundLiteral";break;
+  case EK_RelatedResult: OS << "RelatedResult"; break;
   case EK_Base: OS << "Base"; break;
   case EK_Delegating: OS << "Delegating"; break;
   case EK_ArrayElement: OS << "ArrayElement " << Index; break;
@@ -4632,6 +4636,7 @@ getAssignmentAction(const InitializedEntity &Entity) {
     return Sema::AA_Passing;
 
   case InitializedEntity::EK_Result:
+  case InitializedEntity::EK_RelatedResult:
     return Sema::AA_Returning;
 
   case InitializedEntity::EK_Temporary:
@@ -4672,6 +4677,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) {
 
   case InitializedEntity::EK_Parameter:
   case InitializedEntity::EK_Temporary:
+  case InitializedEntity::EK_RelatedResult:
     return true;
   }
 
@@ -4699,6 +4705,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) {
     case InitializedEntity::EK_ArrayElement:
     case InitializedEntity::EK_Exception:
     case InitializedEntity::EK_CompoundLiteralInit:
+    case InitializedEntity::EK_RelatedResult:
       return true;
   }
 
@@ -4781,6 +4788,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity,
   case InitializedEntity::EK_ComplexElement:
   case InitializedEntity::EK_BlockElement:
   case InitializedEntity::EK_CompoundLiteralInit:
+  case InitializedEntity::EK_RelatedResult:
     return Initializer->getLocStart();
   }
   llvm_unreachable("missed an InitializedEntity kind?");
@@ -5001,6 +5009,11 @@ void InitializationSequence::PrintInitLocationNote(Sema &S,
     else
       S.Diag(Entity.getDecl()->getLocation(), diag::note_parameter_here);
   }
+  else if (Entity.getKind() == InitializedEntity::EK_RelatedResult &&
+           Entity.getMethodDecl())
+    S.Diag(Entity.getMethodDecl()->getLocation(),
+           diag::note_method_return_type_change)
+      << Entity.getMethodDecl()->getDeclName();
 }
 
 static bool isReferenceBinding(const InitializationSequence::Step &s) {
@@ -5016,6 +5029,7 @@ static bool isExplicitTemporary(const InitializedEntity &Entity,
   switch (Entity.getKind()) {
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_CompoundLiteralInit:
+  case InitializedEntity::EK_RelatedResult:
     break;
   default:
     return false;
@@ -5186,6 +5200,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) {
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_LambdaCapture:
   case InitializedEntity::EK_CompoundLiteralInit:
+  case InitializedEntity::EK_RelatedResult:
     // The entity being initialized might not outlive the full-expression.
     return false;
   }
@@ -5232,6 +5247,7 @@ getDeclForTemporaryLifetimeExtension(const InitializedEntity &Entity,
 
   case InitializedEntity::EK_Temporary:
   case InitializedEntity::EK_CompoundLiteralInit:
+  case InitializedEntity::EK_RelatedResult:
     // We don't yet know the storage duration of the surrounding temporary.
     // Assume it's got full-expression duration for now, it will patch up our
     // storage duration if that's not correct.
index 85728619880cf4e4bbbbe868557ad5ba67c17a22..107eed35a00aa54856f079fe116b9659af1f186f 100644 (file)
@@ -2710,11 +2710,10 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
       // If we have a related result type, we need to implicitly
       // convert back to the formal result type.  We can't pretend to
       // initialize the result again --- we might end double-retaining
-      // --- so instead we initialize a notional temporary; this can
-      // lead to less-than-great diagnostics, but this stage is much
-      // less likely to fail than the previous stage.
+      // --- so instead we initialize a notional temporary.
       if (!RelatedRetType.isNull()) {
-        Entity = InitializedEntity::InitializeTemporary(FnRetType);
+        Entity = InitializedEntity::InitializeRelatedResult(getCurMethodDecl(),
+                                                            FnRetType);
         Res = PerformCopyInitialization(Entity, ReturnLoc, RetValExp);
         if (Res.isInvalid()) {
           // FIXME: Clean up temporaries here anyway?
index 50aaf2da4d9e025576782d79ebfdaffe8336e9fb..6fa27b02fadaf43e11569f8ab0dfd41a7230e495 100644 (file)
@@ -173,9 +173,9 @@ void test_inference() {
 @interface Fail @end
 @protocol X @end
 @implementation Fail
-- (id<X>) initWithX
+- (id<X>) initWithX // expected-note {{compiler has implicitly changed method 'initWithX' return type}}
 {
-  return (id)self; // expected-warning {{casting 'Fail *' to incompatible type 'id<X>'}}
+  return (id)self; // expected-warning {{returning 'Fail *' from a function with incompatible result type 'id<X>'}}
 }
 @end
 
@@ -184,3 +184,19 @@ void test_inference() {
 @interface WeirdNSString : NSString
 - (id)initWithCString:(const char*)string, void *blah;
 @end
+
+
+// rdar://14121570
+@protocol PMFilterManager
+@end
+
+@interface UIViewController : NSObject
+@end
+
+@implementation UIViewController
++ (UIViewController<PMFilterManager> *)newFilterViewControllerForType // expected-note {{compiler has implicitly changed method 'newFilterViewControllerForType' return type}}
+{
+        UIViewController<PMFilterManager> *filterVC;
+        return filterVC; // expected-warning {{incompatible pointer types returning 'UIViewController *' from a function with result type 'UIViewController<PMFilterManager> *'}}
+}
+@end