[cfe-commits] r132868 - in /cfe/trunk: docs/ include/clang/AST/ include/clang/Basic/ include/clang/Driver/ include/clang/Sema/ lib/AST/ lib/Analysis/ lib/Basic/ lib/CodeGen/ lib/Driver/ lib/Frontend/ lib/Parse/ lib/Sema/ lib/Serialization/ test/Driver/ test/PCH/ test/SemaObjC/ test/SemaObjCXX/

Douglas Gregor dgregor at apple.com
Fri Jun 10 18:09:30 PDT 2011


Author: dgregor
Date: Fri Jun 10 20:09:30 2011
New Revision: 132868

URL: http://llvm.org/viewvc/llvm-project?rev=132868&view=rev
Log:
Implement Objective-C Related Result Type semantics.

Related result types apply Cocoa conventions to the type of message
sends and property accesses to Objective-C methods that are known to
always return objects whose type is the same as the type of the
receiving class (or a subclass thereof), such as +alloc and
-init. This tightens up static type safety for Objective-C, so that we
now diagnose mistakes like this:

t.m:4:10: warning: incompatible pointer types initializing 'NSSet *'
with an
      expression of type 'NSArray *' [-Wincompatible-pointer-types]
  NSSet *array = [[NSArray alloc] init];
         ^       ~~~~~~~~~~~~~~~~~~~~~~
/System/Library/Frameworks/Foundation.framework/Headers/NSObject.h:72:1:
note: 
      instance method 'init' is assumed to return an instance of its
      receiver
      type ('NSArray *')
- (id)init;
^

It also means that we get decent type inference when writing code in
Objective-C++0x:

  auto array = [[NSMutableArray alloc] initWithObjects:@"one",  @"two",nil];
  //    ^ now infers NSMutableArray* rather than id



Added:
    cfe/trunk/test/SemaObjC/related-result-type-inference.m
    cfe/trunk/test/SemaObjCXX/related-result-type-inference.mm
Modified:
    cfe/trunk/docs/LanguageExtensions.html
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/IdentifierTable.h
    cfe/trunk/include/clang/Basic/LangOptions.h
    cfe/trunk/include/clang/Driver/CC1Options.td
    cfe/trunk/include/clang/Driver/Options.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/DumpXML.cpp
    cfe/trunk/lib/Analysis/CocoaConventions.cpp
    cfe/trunk/lib/Basic/IdentifierTable.cpp
    cfe/trunk/lib/CodeGen/CGObjC.cpp
    cfe/trunk/lib/Driver/Tools.cpp
    cfe/trunk/lib/Frontend/CompilerInvocation.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaInit.cpp
    cfe/trunk/lib/Sema/SemaStmt.cpp
    cfe/trunk/lib/Serialization/ASTReader.cpp
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriter.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Driver/rewrite-objc.m
    cfe/trunk/test/PCH/objc_methods.h
    cfe/trunk/test/PCH/objc_methods.m

Modified: cfe/trunk/docs/LanguageExtensions.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LanguageExtensions.html?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/docs/LanguageExtensions.html (original)
+++ cfe/trunk/docs/LanguageExtensions.html Fri Jun 10 20:09:30 2011
@@ -62,6 +62,11 @@
   </ul>
 <li><a href="#checking_type_traits">Checks for Type Traits</a></li>
 <li><a href="#blocks">Blocks</a></li>
+<li><a href="#objc_features">Objective-C Features</a>
+  <ul>
+    <li><a href="#objc_instancetype">Related result types</a></li>
+  </ul>
+</li>
 <li><a href="#overloading-in-c">Function Overloading in C</a></li>
 <li><a href="#builtins">Builtin Functions</a>
   <ul>
@@ -598,6 +603,73 @@
 <p>Query for this feature with __has_extension(blocks).</p>
 
 <!-- ======================================================================= -->
+<h2 id="objc_features">Objective-C Features</h2>
+<!-- ======================================================================= -->
+
+<h3 id="objc_instancetype">Related result types</h3>
+
+<p>According to Cocoa conventions, Objective-C methods with certain names ("init", "alloc", etc.) always return objects that are an instance of the receiving class's type. Such methods are said to have a "related result type", meaning that a message send to one of these methods will have the same static type as an instance of the receiver class. For example, given the following classes:</p>
+
+<blockquote>
+<pre>
+ at interface NSObject
++ (id)alloc;
+- (id)init;
+ at end
+
+ at interface NSArray : NSObject
+ at end
+</pre>
+</blockquote>
+
+<p>and this common initialization pattern</p>
+
+<blockquote>
+<pre>
+NSArray *array = [[NSArray alloc] init];
+</pre>
+</blockquote>
+
+<p>the type of the expression <code>[NSArray alloc]</code> is
+<code>NSArray*</code> because <code>alloc</code> implicitly has a
+related result type. Similarly, the type of the expression
+<code>[[NSArray alloc] init]</code> is <code>NSArray*</code>, since
+<code>init</code> has a related result type and its receiver is known
+to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
+
+<p>To determine whether a method has a related result type, the first
+word in the camel-case selector (e.g., "init" in "initWithObjects") is
+considered, and the method will a related result type if its return
+type is compatible with the type of its class and if
+
+<ul>
+  
+  <li>the first word is "alloc" or "new", and the method is a class
+  method, or</li>
+  
+  <li>the first word is "autorelease", "init", "retain", or "self",
+  and the method is an instance method.</li>
+  
+</ul></p>
+
+<p>If a method with a related result type is overridden by a subclass
+method, the subclass method must also return a type that is compatible
+with the subclass type. For example:</p>
+
+<blockquote>
+<pre>
+ at interface NSString : NSObject
+- (NSUnrelated *)init; // incorrect usage: NSUnrelated is not NSString or a superclass of NSString
+ at end
+</pre>
+</blockquote>
+
+<p>Related result types only affect the type of a message send or
+property access via the given method. In all other respects, a method
+with a related result type is treated the same way as method without a
+related result type.</p>
+
+<!-- ======================================================================= -->
 <h2 id="overloading-in-c">Function Overloading in C</h2>
 <!-- ======================================================================= -->
 

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Fri Jun 10 20:09:30 2011
@@ -135,6 +135,9 @@
   /// in, inout, etc.
   unsigned objcDeclQualifier : 6;
 
+  /// \brief Indicates whether this method has a related result type.
+  unsigned RelatedResultType : 1;
+  
   // Number of args separated by ':' in a method declaration.
   unsigned NumSelectorArgs;
 
@@ -171,6 +174,7 @@
                  bool isSynthesized = false,
                  bool isDefined = false,
                  ImplementationControl impControl = None,
+                 bool HasRelatedResultType = false,
                  unsigned numSelectorArgs = 0)
   : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo),
     DeclContext(ObjCMethod), Family(InvalidObjCMethodFamily),
@@ -178,8 +182,8 @@
     IsSynthesized(isSynthesized),
     IsDefined(isDefined),
     DeclImplementation(impControl), objcDeclQualifier(OBJC_TQ_None),
-    NumSelectorArgs(numSelectorArgs), MethodDeclType(T), 
-    ResultTInfo(ResultTInfo),
+    RelatedResultType(HasRelatedResultType), NumSelectorArgs(numSelectorArgs), 
+    MethodDeclType(T), ResultTInfo(ResultTInfo),
     EndLoc(endLoc), Body(0), SelfDecl(0), CmdDecl(0) {}
 
   /// \brief A definition will return its interface declaration.
@@ -199,6 +203,7 @@
                                 bool isSynthesized = false,
                                 bool isDefined = false,
                                 ImplementationControl impControl = None,
+                                bool HasRelatedResultType = false,
                                 unsigned numSelectorArgs = 0);
 
   virtual ObjCMethodDecl *getCanonicalDecl();
@@ -211,6 +216,13 @@
   }
   void setObjCDeclQualifier(ObjCDeclQualifier QV) { objcDeclQualifier = QV; }
 
+  /// \brief Determine whether this method has a result type that is related
+  /// to the message receiver's type.
+  bool hasRelatedResultType() const { return RelatedResultType; }
+  
+  /// \brief Note whether this method has a related result type.
+  void SetRelatedResultType(bool RRT = true) { RelatedResultType = RRT; }
+  
   unsigned getNumSelectorArgs() const { return NumSelectorArgs; }
   void setNumSelectorArgs(unsigned numSelectorArgs) { 
     NumSelectorArgs = numSelectorArgs; 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 10 20:09:30 2011
@@ -4117,5 +4117,22 @@
 
 } // end of sema category
 
+let CategoryName = "Related Result Type Issue" in {
+// Objective-C related result type compatibility
+def warn_related_result_type_compatibility_class : Warning<
+  "method is expected to return an instance of its class type %0, but "
+  "is declared to return %1">;
+def warn_related_result_type_compatibility_protocol : Warning<
+  "protocol method is expected to return an instance of the implementing "
+  "class, but is declared to return %0">;
+def note_related_result_type_overridden : Note<
+  "overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
+  "new|autorelease|dealloc|release|retain|retainCount|self}0' method family">;
+def note_related_result_type_inferred : Note<
+  "%select{class|instance}0 method %1 is assumed to return an instance of "
+  "its receiver type (%2)">;
+
+}
+
 } // end of sema component.
 

Modified: cfe/trunk/include/clang/Basic/IdentifierTable.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/IdentifierTable.h?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/IdentifierTable.h (original)
+++ cfe/trunk/include/clang/Basic/IdentifierTable.h Fri Jun 10 20:09:30 2011
@@ -498,7 +498,8 @@
   OMF_dealloc,
   OMF_release,
   OMF_retain,
-  OMF_retainCount
+  OMF_retainCount,
+  OMF_self
 };
 
 /// Enough bits to store any enumerator in ObjCMethodFamily or

Modified: cfe/trunk/include/clang/Basic/LangOptions.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/LangOptions.h?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/LangOptions.h (original)
+++ cfe/trunk/include/clang/Basic/LangOptions.h Fri Jun 10 20:09:30 2011
@@ -46,6 +46,8 @@
   unsigned ObjCNonFragileABI : 1;  // Objective-C modern abi enabled
   unsigned ObjCNonFragileABI2 : 1;  // Objective-C enhanced modern abi enabled
   unsigned ObjCDefaultSynthProperties : 1; // Objective-C auto-synthesized properties.
+  unsigned ObjCInferRelatedResultType : 1; // Infer Objective-C related return
+                                           // types
   unsigned AppleKext         : 1;  // Allow apple kext features.
 
   unsigned PascalStrings     : 1;  // Allow Pascal strings
@@ -173,6 +175,7 @@
     GC = ObjC1 = ObjC2 = ObjCNonFragileABI = ObjCNonFragileABI2 = 0;
     AppleKext = 0;
     ObjCDefaultSynthProperties = 0;
+    ObjCInferRelatedResultType = 0;
     NoConstantCFStrings = 0; InlineVisibilityHidden = 0;
     C99 = C1X = Microsoft = Borland = CPlusPlus = CPlusPlus0x = 0;
     CXXOperatorNames = PascalStrings = WritableStrings = ConstStrings = 0;

Modified: cfe/trunk/include/clang/Driver/CC1Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/CC1Options.td (original)
+++ cfe/trunk/include/clang/Driver/CC1Options.td Fri Jun 10 20:09:30 2011
@@ -493,6 +493,8 @@
   HelpText<"Enable Objective-C Ivar layout bitmap print trace">;
 def fobjc_nonfragile_abi : Flag<"-fobjc-nonfragile-abi">,
   HelpText<"enable objective-c's nonfragile abi">;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">,
+  HelpText<"infer Objective-C related result type based on method family">;
 def ftrapv : Flag<"-ftrapv">,
   HelpText<"Trap on integer overflow">;
 def ftrapv_handler : Separate<"-ftrapv-handler">,

Modified: cfe/trunk/include/clang/Driver/Options.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Options.td (original)
+++ cfe/trunk/include/clang/Driver/Options.td Fri Jun 10 20:09:30 2011
@@ -392,6 +392,10 @@
 def fobjc_gc : Flag<"-fobjc-gc">, Group<f_Group>;
 def fobjc_legacy_dispatch : Flag<"-fobjc-legacy-dispatch">, Group<f_Group>;
 def fobjc_new_property : Flag<"-fobjc-new-property">, Group<clang_ignored_f_Group>;
+def fobjc_infer_related_result_type : Flag<"-fobjc-infer-related-result-type">, 
+                                      Group<f_Group>;
+def fno_objc_infer_related_result_type : Flag<
+  "-fno-objc-infer-related-result-type">, Group<f_Group>;
 
 // Objective-C ABI options.
 def fobjc_abi_version_EQ : Joined<"-fobjc-abi-version=">, Group<f_Group>;

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 10 20:09:30 2011
@@ -4981,7 +4981,7 @@
     SourceLocation EndLoc,   // location of the ; or {.
     tok::TokenKind MethodType,
     Decl *ClassDecl, ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
-    Selector Sel,
+    SourceLocation SelectorStartLoc, Selector Sel,
     // optional arguments. The number of types/arguments is obtained
     // from the Sel.getNumArgs().
     ObjCArgInfo *ArgInfo,
@@ -5079,7 +5079,18 @@
                                   SourceLocation RBracLoc,
                                   MultiExprArg Args);
 
-
+  /// \brief Check whether the given new method is a valid override of the
+  /// given overridden method, and set any properties that should be inherited.
+  ///
+  /// \returns True if an error occurred.
+  bool CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
+                               const ObjCMethodDecl *Overridden,
+                               bool IsImplementation);
+    
+  /// \brief Check whether the given method overrides any methods in its class,
+  /// calling \c CheckObjCMethodOverride for each overridden method.
+  bool CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, DeclContext *DC);
+  
   enum PragmaOptionsAlignKind {
     POAK_Native,  // #pragma options align=native
     POAK_Natural, // #pragma options align=natural
@@ -5501,11 +5512,24 @@
   /// \param Method - May be null.
   /// \param [out] ReturnType - The return type of the send.
   /// \return true iff there were any incompatible types.
-  bool CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, Selector Sel,
+  bool CheckMessageArgumentTypes(QualType ReceiverType,
+                                 Expr **Args, unsigned NumArgs, Selector Sel,
                                  ObjCMethodDecl *Method, bool isClassMessage,
+                                 bool isSuperMessage,
                                  SourceLocation lbrac, SourceLocation rbrac,
                                  QualType &ReturnType, ExprValueKind &VK);
 
+  /// \brief Determine the result of a message send expression based on
+  /// the type of the receiver, the method expected to receive the message,
+  /// and the form of the message send.
+  QualType getMessageSendResultType(QualType ReceiverType,
+                                    ObjCMethodDecl *Method,
+                                    bool isClassMessage, bool isSuperMessage);
+    
+  /// \brief If the given expression involves a message send to a method
+  /// with a related result type, emit a note describing what happened.
+  void EmitRelatedResultTypeNote(const Expr *E);
+  
   /// CheckBooleanCondition - Diagnose problems involving the use of
   /// the given expression as a boolean condition (e.g. in an if
   /// statement).  Also performs the standard function and array

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Jun 10 20:09:30 2011
@@ -2870,7 +2870,8 @@
                              D->isVariadic(),
                              D->isSynthesized(),
                              D->isDefined(),
-                             D->getImplementationControl());
+                             D->getImplementationControl(),
+                             D->hasRelatedResultType());
 
   // FIXME: When we decide to merge method definitions, we'll need to
   // deal with implicit parameters.

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Fri Jun 10 20:09:30 2011
@@ -339,12 +339,14 @@
                                        bool isSynthesized,
                                        bool isDefined,
                                        ImplementationControl impControl,
+                                       bool HasRelatedResultType,
                                        unsigned numSelectorArgs) {
   return new (C) ObjCMethodDecl(beginLoc, endLoc,
                                 SelInfo, T, ResultTInfo, contextDecl,
                                 isInstance,
                                 isVariadic, isSynthesized, isDefined,
                                 impControl,
+                                HasRelatedResultType,
                                 numSelectorArgs);
 }
 
@@ -446,6 +448,7 @@
   case OMF_release:
   case OMF_autorelease:
   case OMF_retainCount:
+  case OMF_self:
     if (!isInstanceMethod())
       family = OMF_None;
     break;

Modified: cfe/trunk/lib/AST/DumpXML.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DumpXML.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DumpXML.cpp (original)
+++ cfe/trunk/lib/AST/DumpXML.cpp Fri Jun 10 20:09:30 2011
@@ -848,6 +848,7 @@
     setFlag("variadic", D->isVariadic());
     setFlag("synthesized", D->isSynthesized());
     setFlag("defined", D->isDefined());
+    setFlag("related_result_type", D->hasRelatedResultType());
   }
   void visitObjCMethodDeclChildren(ObjCMethodDecl *D) {
     dispatch(D->getResultType());

Modified: cfe/trunk/lib/Analysis/CocoaConventions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/CocoaConventions.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/CocoaConventions.cpp (original)
+++ cfe/trunk/lib/Analysis/CocoaConventions.cpp Fri Jun 10 20:09:30 2011
@@ -44,6 +44,7 @@
   case OMF_release:
   case OMF_retain:
   case OMF_retainCount:
+  case OMF_self:
     return NoConvention;
 
   case OMF_init:

Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Fri Jun 10 20:09:30 2011
@@ -392,6 +392,7 @@
     if (name == "release") return OMF_release;
     if (name == "retain") return OMF_retain;
     if (name == "retainCount") return OMF_retainCount;
+    if (name == "self") return OMF_self;
   }
 
   // The other method families may begin with a prefix of underscores.

Modified: cfe/trunk/lib/CodeGen/CGObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjC.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjC.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjC.cpp Fri Jun 10 20:09:30 2011
@@ -47,6 +47,23 @@
   return CGM.getObjCRuntime().GenerateProtocolRef(Builder, E->getProtocol());
 }
 
+/// \brief Adjust the type of the result of an Objective-C message send 
+/// expression when the method has a related result type.
+static RValue AdjustRelatedResultType(CodeGenFunction &CGF,
+                                      const Expr *E,
+                                      const ObjCMethodDecl *Method,
+                                      RValue Result) {
+  if (!Method)
+    return Result;
+  if (!Method->hasRelatedResultType() ||
+      CGF.getContext().hasSameType(E->getType(), Method->getResultType()) ||
+      !Result.isScalar())
+    return Result;
+  
+  // We have applied a related result type. Cast the rvalue appropriately.
+  return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(),
+                                               CGF.ConvertType(E->getType())));
+}
 
 RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
                                             ReturnValueSlot Return) {
@@ -59,15 +76,17 @@
   bool isClassMessage = false;
   ObjCInterfaceDecl *OID = 0;
   // Find the receiver
+  QualType ReceiverType;
   llvm::Value *Receiver = 0;
   switch (E->getReceiverKind()) {
   case ObjCMessageExpr::Instance:
     Receiver = EmitScalarExpr(E->getInstanceReceiver());
+    ReceiverType = E->getInstanceReceiver()->getType();
     break;
 
   case ObjCMessageExpr::Class: {
-    const ObjCObjectType *ObjTy
-      = E->getClassReceiver()->getAs<ObjCObjectType>();
+    ReceiverType = E->getClassReceiver();
+    const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>();
     assert(ObjTy && "Invalid Objective-C class message send");
     OID = ObjTy->getInterface();
     assert(OID && "Invalid Objective-C class message send");
@@ -77,11 +96,13 @@
   }
 
   case ObjCMessageExpr::SuperInstance:
+    ReceiverType = E->getSuperType();
     Receiver = LoadObjCSelf();
     isSuperMessage = true;
     break;
 
   case ObjCMessageExpr::SuperClass:
+    ReceiverType = E->getSuperType();
     Receiver = LoadObjCSelf();
     isSuperMessage = true;
     isClassMessage = true;
@@ -94,24 +115,27 @@
   QualType ResultType =
     E->getMethodDecl() ? E->getMethodDecl()->getResultType() : E->getType();
 
+  RValue result;
   if (isSuperMessage) {
     // super is only valid in an Objective-C method
     const ObjCMethodDecl *OMD = cast<ObjCMethodDecl>(CurFuncDecl);
     bool isCategoryImpl = isa<ObjCCategoryImplDecl>(OMD->getDeclContext());
-    return Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
-                                            E->getSelector(),
-                                            OMD->getClassInterface(),
-                                            isCategoryImpl,
-                                            Receiver,
-                                            isClassMessage,
-                                            Args,
-                                            E->getMethodDecl());
+    result = Runtime.GenerateMessageSendSuper(*this, Return, ResultType,
+                                              E->getSelector(),
+                                              OMD->getClassInterface(),
+                                              isCategoryImpl,
+                                              Receiver,
+                                              isClassMessage,
+                                              Args,
+                                              E->getMethodDecl());
+  } else {
+    result = Runtime.GenerateMessageSend(*this, Return, ResultType,
+                                         E->getSelector(),
+                                         Receiver, Args, OID,
+                                         E->getMethodDecl());
   }
-
-  return Runtime.GenerateMessageSend(*this, Return, ResultType,
-                                     E->getSelector(),
-                                     Receiver, Args, OID,
-                                     E->getMethodDecl());
+  
+  return AdjustRelatedResultType(*this, E, E->getMethodDecl(), result);
 }
 
 /// StartObjCMethod - Begin emission of an ObjCMethod. This generates
@@ -711,26 +735,31 @@
   const ObjCPropertyRefExpr *E = LV.getPropertyRefExpr();
   QualType ResultType = E->getGetterResultType();
   Selector S;
+  const ObjCMethodDecl *method;
   if (E->isExplicitProperty()) {
     const ObjCPropertyDecl *Property = E->getExplicitProperty();
     S = Property->getGetterName();
+    method = Property->getGetterMethodDecl();
   } else {
-    const ObjCMethodDecl *Getter = E->getImplicitPropertyGetter();
-    S = Getter->getSelector();
+    method = E->getImplicitPropertyGetter();
+    S = method->getSelector();
   }
 
   llvm::Value *Receiver = LV.getPropertyRefBaseAddr();
 
   // Accesses to 'super' follow a different code path.
   if (E->isSuperReceiver())
-    return GenerateMessageSendSuper(*this, Return, ResultType,
-                                    S, Receiver, CallArgList());
-
+    return AdjustRelatedResultType(*this, E, method,
+                                   GenerateMessageSendSuper(*this, Return, 
+                                                            ResultType,
+                                                            S, Receiver, 
+                                                            CallArgList()));
   const ObjCInterfaceDecl *ReceiverClass
     = (E->isClassReceiver() ? E->getClassReceiver() : 0);
-  return CGM.getObjCRuntime().
-             GenerateMessageSend(*this, Return, ResultType, S,
-                                 Receiver, CallArgList(), ReceiverClass);
+  return AdjustRelatedResultType(*this, E, method,
+                                 CGM.getObjCRuntime().
+                 GenerateMessageSend(*this, Return, ResultType, S,
+                                     Receiver, CallArgList(), ReceiverClass));
 }
 
 void CodeGenFunction::EmitStoreThroughPropertyRefLValue(RValue Src,

Modified: cfe/trunk/lib/Driver/Tools.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Tools.cpp (original)
+++ cfe/trunk/lib/Driver/Tools.cpp Fri Jun 10 20:09:30 2011
@@ -1542,6 +1542,12 @@
                     options::OPT_fno_lax_vector_conversions))
     CmdArgs.push_back("-fno-lax-vector-conversions");
 
+  // -fobjc-infer-related-result-type is the default.
+  if (Args.hasFlag(options::OPT_fobjc_infer_related_result_type, 
+                   options::OPT_fno_objc_infer_related_result_type, 
+                   /*Default=*/true))
+    CmdArgs.push_back("-fobjc-infer-related-result-type");
+  
   // Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
   // takes precedence.
   const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);

Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
+++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Fri Jun 10 20:09:30 2011
@@ -670,6 +670,9 @@
       Res.push_back("-fobjc-gc-only");
     }
   }
+  if (Opts.ObjCInferRelatedResultType)
+    Res.push_back("-fobjc-infer-related-result-type");
+  
   if (Opts.AppleKext)
     Res.push_back("-fapple-kext");
   
@@ -1485,6 +1488,9 @@
   else if (Args.hasArg(OPT_fobjc_gc))
     Opts.setGCMode(LangOptions::HybridGC);
   
+  if (Args.hasArg(OPT_fobjc_infer_related_result_type))
+    Opts.ObjCInferRelatedResultType = 1;
+  
   if (Args.hasArg(OPT_fapple_kext)) {
     if (!Opts.CPlusPlus)
       Diags.Report(diag::warn_c_kext);

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 10 20:09:30 2011
@@ -874,8 +874,8 @@
     Selector Sel = PP.getSelectorTable().getNullarySelector(SelIdent);
     Decl *Result
          = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
-                                          mType, IDecl, DSRet, ReturnType, Sel,
-                                          0, 
+                                          mType, IDecl, DSRet, ReturnType, 
+                                          selLoc, Sel, 0, 
                                           CParamInfo.data(), CParamInfo.size(),
                                           methodAttrs.getList(), MethodImplKind,
                                           false, MethodDefinition);
@@ -1000,8 +1000,8 @@
                                                    &KeyIdents[0]);
   Decl *Result
        = Actions.ActOnMethodDeclaration(getCurScope(), mLoc, Tok.getLocation(),
-                                        mType, IDecl, DSRet, ReturnType, Sel,
-                                        &ArgInfos[0], 
+                                        mType, IDecl, DSRet, ReturnType, 
+                                        selLoc, Sel, &ArgInfos[0], 
                                         CParamInfo.data(), CParamInfo.size(),
                                         methodAttrs.getList(),
                                         MethodImplKind, isVariadic, MethodDefinition);

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jun 10 20:09:30 2011
@@ -1936,7 +1936,9 @@
   for (ObjCMethodDecl::param_iterator oi = oldMethod->param_begin(),
          ni = newMethod->param_begin(), ne = newMethod->param_end();
        ni != ne; ++ni, ++oi)
-    mergeParamDeclAttributes(*ni, *oi, Context);    
+    mergeParamDeclAttributes(*ni, *oi, Context);
+  
+  CheckObjCMethodOverride(newMethod, oldMethod, true);
 }
 
 /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Jun 10 20:09:30 2011
@@ -24,6 +24,141 @@
 
 using namespace clang;
 
+bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, 
+                                   const ObjCMethodDecl *Overridden,
+                                   bool IsImplementation) {
+  if (Overridden->hasRelatedResultType() && 
+      !NewMethod->hasRelatedResultType()) {
+    // This can only happen when the method follows a naming convention that
+    // implies a related result type, and the original (overridden) method has
+    // a suitable return type, but the new (overriding) method does not have
+    // a suitable return type.
+    QualType ResultType = NewMethod->getResultType();
+    SourceRange ResultTypeRange;
+    if (const TypeSourceInfo *ResultTypeInfo 
+        = NewMethod->getResultTypeSourceInfo())
+      ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+    
+    // Figure out which class this method is part of, if any.
+    ObjCInterfaceDecl *CurrentClass 
+      = dyn_cast<ObjCInterfaceDecl>(NewMethod->getDeclContext());
+    if (!CurrentClass) {
+      DeclContext *DC = NewMethod->getDeclContext();
+      if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(DC))
+        CurrentClass = Cat->getClassInterface();
+      else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(DC))
+        CurrentClass = Impl->getClassInterface();
+      else if (ObjCCategoryImplDecl *CatImpl
+               = dyn_cast<ObjCCategoryImplDecl>(DC))
+        CurrentClass = CatImpl->getClassInterface();
+    }
+    
+    if (CurrentClass) {
+      Diag(NewMethod->getLocation(), 
+           diag::warn_related_result_type_compatibility_class)
+        << Context.getObjCInterfaceType(CurrentClass)
+        << ResultType
+        << ResultTypeRange;
+    } else {
+      Diag(NewMethod->getLocation(), 
+           diag::warn_related_result_type_compatibility_protocol)
+        << ResultType
+        << ResultTypeRange;
+    }
+    
+    Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
+      << Overridden->getMethodFamily();
+  }
+  
+  return false;
+}
+
+
+static bool CheckObjCMethodOverrides(Sema &S, ObjCMethodDecl *NewMethod,
+                                     DeclContext *DC, 
+                                     bool SkipCurrent = true) {
+  if (!DC)
+    return false;
+  
+  if (!SkipCurrent) {
+    // Look for this method. If we find it, we're done.
+    Selector Sel = NewMethod->getSelector();
+    bool IsInstance = NewMethod->isInstanceMethod();
+    DeclContext::lookup_const_iterator Meth, MethEnd;
+    for (llvm::tie(Meth, MethEnd) = DC->lookup(Sel); Meth != MethEnd; ++Meth) {
+      ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth);
+      if (MD && MD->isInstanceMethod() == IsInstance)
+        return S.CheckObjCMethodOverride(NewMethod, MD, false);
+    }
+  }
+  
+  if (ObjCInterfaceDecl *Class = llvm::dyn_cast<ObjCInterfaceDecl>(DC)) {
+    // Look through categories.
+    for (ObjCCategoryDecl *Category = Class->getCategoryList();
+         Category; Category = Category->getNextClassCategory()) {
+      if (CheckObjCMethodOverrides(S, NewMethod, Category, false))
+        return true;
+    }
+    
+    // Look through protocols.
+    for (ObjCList<ObjCProtocolDecl>::iterator I = Class->protocol_begin(),
+         IEnd = Class->protocol_end();
+         I != IEnd; ++I)
+      if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+        return true;
+    
+    // Look in our superclass.
+    return CheckObjCMethodOverrides(S, NewMethod, Class->getSuperClass(), 
+                                    false);
+  }
+  
+  if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC)) {
+    // Look through protocols.
+    for (ObjCList<ObjCProtocolDecl>::iterator I = Category->protocol_begin(),
+         IEnd = Category->protocol_end();
+         I != IEnd; ++I)
+      if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+        return true;
+    
+    return false;
+  }
+  
+  if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC)) {
+    // Look through protocols.
+    for (ObjCList<ObjCProtocolDecl>::iterator I = Protocol->protocol_begin(),
+         IEnd = Protocol->protocol_end();
+         I != IEnd; ++I)
+      if (CheckObjCMethodOverrides(S, NewMethod, *I, false))
+        return true;
+    
+    return false;
+  }
+  
+  return false;
+}
+
+bool Sema::CheckObjCMethodOverrides(ObjCMethodDecl *NewMethod, 
+                                    DeclContext *DC) {
+  if (ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(DC))
+    return ::CheckObjCMethodOverrides(*this, NewMethod, Class);
+  
+  if (ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(DC))
+    return ::CheckObjCMethodOverrides(*this, NewMethod, Category);
+  
+  if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(DC))
+    return ::CheckObjCMethodOverrides(*this, NewMethod, Protocol);
+  
+  if (ObjCImplementationDecl *Impl = dyn_cast<ObjCImplementationDecl>(DC))
+    return ::CheckObjCMethodOverrides(*this, NewMethod, 
+                                      Impl->getClassInterface());
+  
+  if (ObjCCategoryImplDecl *CatImpl = dyn_cast<ObjCCategoryImplDecl>(DC))
+    return ::CheckObjCMethodOverrides(*this, NewMethod, 
+                                      CatImpl->getClassInterface());
+  
+  return ::CheckObjCMethodOverrides(*this, NewMethod, CurContext);
+}
+
 static void DiagnoseObjCImplementedDeprecations(Sema &S,
                                                 NamedDecl *ND,
                                                 SourceLocation ImplLoc,
@@ -1717,11 +1852,71 @@
   return false;
 }
 
+/// \brief Check whether the declared result type of the given Objective-C
+/// method declaration is compatible with the method's class.
+///
+static bool 
+CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
+                                    ObjCInterfaceDecl *CurrentClass) {
+  QualType ResultType = Method->getResultType();
+  SourceRange ResultTypeRange;
+  if (const TypeSourceInfo *ResultTypeInfo = Method->getResultTypeSourceInfo())
+    ResultTypeRange = ResultTypeInfo->getTypeLoc().getSourceRange();
+  
+  // If an Objective-C method inherits its related result type, then its 
+  // declared result type must be compatible with its own class type. The
+  // declared result type is compatible if:
+  if (const ObjCObjectPointerType *ResultObjectType
+                                = ResultType->getAs<ObjCObjectPointerType>()) {
+    //   - it is id or qualified id, or
+    if (ResultObjectType->isObjCIdType() ||
+        ResultObjectType->isObjCQualifiedIdType())
+      return false;
+  
+    if (CurrentClass) {
+      if (ObjCInterfaceDecl *ResultClass 
+                                      = ResultObjectType->getInterfaceDecl()) {
+        //   - it is the same as the method's class type, or
+        if (CurrentClass == ResultClass)
+          return false;
+        
+        //   - it is a superclass of the method's class type
+        if (ResultClass->isSuperClassOf(CurrentClass))
+          return false;
+      }      
+    }
+  }
+  
+  return true;
+}
+
+/// \brief Determine if any method in the global method pool has an inferred 
+/// result type.
+static bool 
+anyMethodInfersRelatedResultType(Sema &S, Selector Sel, bool IsInstance) {
+  Sema::GlobalMethodPool::iterator Pos = S.MethodPool.find(Sel);
+  if (Pos == S.MethodPool.end()) {
+    if (S.ExternalSource)
+      Pos = S.ReadMethodPool(Sel);
+    else
+      return 0;
+  }
+  
+  ObjCMethodList &List = IsInstance ? Pos->second.first : Pos->second.second;
+  for (ObjCMethodList *M = &List; M; M = M->Next) {
+    if (M->Method && M->Method->hasRelatedResultType())
+      return true;
+  }  
+  
+  return false;
+}
+
 Decl *Sema::ActOnMethodDeclaration(
     Scope *S,
     SourceLocation MethodLoc, SourceLocation EndLoc,
     tok::TokenKind MethodType, Decl *ClassDecl,
     ObjCDeclSpec &ReturnQT, ParsedType ReturnType,
+    SourceLocation SelectorStartLoc,
     Selector Sel,
     // optional arguments. The number of types/arguments is obtained
     // from the Sel.getNumArgs().
@@ -1746,7 +1941,7 @@
       Diag(MethodLoc, diag::err_object_cannot_be_passed_returned_by_value)
         << 0 << resultDeclType;
       return 0;
-    }
+    }    
   } else // get the type for "id".
     resultDeclType = Context.getObjCIdType();
 
@@ -1756,9 +1951,10 @@
                            cast<DeclContext>(ClassDecl),
                            MethodType == tok::minus, isVariadic,
                            false, false,
-                           MethodDeclKind == tok::objc_optional ?
-                           ObjCMethodDecl::Optional :
-                           ObjCMethodDecl::Required);
+                           MethodDeclKind == tok::objc_optional 
+                             ? ObjCMethodDecl::Optional
+                             : ObjCMethodDecl::Required,
+                           false);
 
   llvm::SmallVector<ParmVarDecl*, 16> Params;
 
@@ -1854,6 +2050,7 @@
     }
     InterfaceMD = ImpDecl->getClassInterface()->getMethod(Sel,
                                                    MethodType == tok::minus);
+    
     if (ObjCMethod->hasAttrs() &&
         containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
       Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1866,6 +2063,10 @@
       PrevMethod = CatImpDecl->getClassMethod(Sel);
       CatImpDecl->addClassMethod(ObjCMethod);
     }
+
+    if (ObjCCategoryDecl *Cat = CatImpDecl->getCategoryDecl())
+      InterfaceMD = Cat->getMethod(Sel, MethodType == tok::minus);
+
     if (ObjCMethod->hasAttrs() &&
         containsInvalidMethodImplAttribute(ObjCMethod->getAttrs()))
       Diag(EndLoc, diag::warn_attribute_method_def);
@@ -1879,10 +2080,65 @@
     Diag(PrevMethod->getLocation(), diag::note_previous_declaration);
   }
 
+  // If this Objective-C method does not have a related result type, but we
+  // are allowed to infer related result types, try to do so based on the
+  // method family.
+  ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(ClassDecl);
+  if (!CurrentClass) {
+    if (ObjCCategoryDecl *Cat = dyn_cast<ObjCCategoryDecl>(ClassDecl))
+      CurrentClass = Cat->getClassInterface();
+    else if (ObjCImplDecl *Impl = dyn_cast<ObjCImplDecl>(ClassDecl))
+      CurrentClass = Impl->getClassInterface();
+    else if (ObjCCategoryImplDecl *CatImpl
+                                   = dyn_cast<ObjCCategoryImplDecl>(ClassDecl))
+      CurrentClass = CatImpl->getClassInterface();
+  }
+  
   // Merge information down from the interface declaration if we have one.
-  if (InterfaceMD)
+  if (InterfaceMD) {
+    // Inherit the related result type, if we can.
+    if (InterfaceMD->hasRelatedResultType() &&
+        !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+      ObjCMethod->SetRelatedResultType();
+      
     mergeObjCMethodDecls(ObjCMethod, InterfaceMD);
-
+  }
+  
+  if (!ObjCMethod->hasRelatedResultType() && 
+      getLangOptions().ObjCInferRelatedResultType) {
+    bool InferRelatedResultType = false;
+    switch (ObjCMethod->getMethodFamily()) {
+    case OMF_None:
+    case OMF_copy:
+    case OMF_dealloc:
+    case OMF_mutableCopy:
+    case OMF_release:
+    case OMF_retainCount:
+      break;
+      
+    case OMF_alloc:
+    case OMF_new:
+      InferRelatedResultType = ObjCMethod->isClassMethod();
+      break;
+        
+    case OMF_init:
+    case OMF_autorelease:
+    case OMF_retain:
+    case OMF_self:
+      InferRelatedResultType = ObjCMethod->isInstanceMethod();
+      break;
+    }
+    
+    if (InferRelatedResultType &&
+        !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass))
+      ObjCMethod->SetRelatedResultType();
+    
+    if (!InterfaceMD && 
+        anyMethodInfersRelatedResultType(*this, ObjCMethod->getSelector(),
+                                         ObjCMethod->isInstanceMethod()))
+      CheckObjCMethodOverrides(ObjCMethod, cast<DeclContext>(ClassDecl));
+  }
+    
   return ObjCMethod;
 }
 

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Fri Jun 10 20:09:30 2011
@@ -4328,7 +4328,11 @@
           if (DiagnoseUseOfDecl(PD, MemberLoc))
             return ExprError();
 
-          return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+          QualType T = PD->getType();
+          if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+            T = getMessageSendResultType(BaseType, Getter, false, false);
+         
+          return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
                                                          VK_LValue,
                                                          OK_ObjCProperty,
                                                          MemberLoc, 
@@ -4346,7 +4350,8 @@
           if (Decl *SDecl = FindGetterSetterNameDecl(OPT, /*Property id*/0, 
                                                      SetterSel, Context))
             SMD = dyn_cast<ObjCMethodDecl>(SDecl);
-          QualType PType = OMD->getSendResultType();
+          QualType PType = getMessageSendResultType(BaseType, OMD, false, 
+                                                    false);
           
           ExprValueKind VK = VK_LValue;
           if (!getLangOptions().CPlusPlus &&
@@ -4414,7 +4419,8 @@
 
         ExprValueKind VK = VK_LValue;
         if (Getter) {
-          PType = Getter->getSendResultType();
+          PType = getMessageSendResultType(QualType(OT, 0), Getter, true, 
+                                           false);
           if (!getLangOptions().CPlusPlus &&
               IsCForbiddenLValueType(Context, PType))
             VK = VK_RValue;
@@ -8345,20 +8351,31 @@
          E->getObjectKind() == OK_ObjCProperty);
   const ObjCPropertyRefExpr *PRE = E->getObjCProperty();
 
+  QualType T = E->getType();
+  QualType ReceiverType;
+  if (PRE->isObjectReceiver())
+    ReceiverType = PRE->getBase()->getType();
+  else if (PRE->isSuperReceiver())
+    ReceiverType = PRE->getSuperReceiverType();
+  else
+    ReceiverType = Context.getObjCInterfaceType(PRE->getClassReceiver());
+    
   ExprValueKind VK = VK_RValue;
   if (PRE->isImplicitProperty()) {
-    if (const ObjCMethodDecl *GetterMethod = 
+    if (ObjCMethodDecl *GetterMethod = 
           PRE->getImplicitPropertyGetter()) {
-      QualType Result = GetterMethod->getResultType();
-      VK = Expr::getValueKindForType(Result);
+      T = getMessageSendResultType(ReceiverType, GetterMethod, 
+                                   PRE->isClassReceiver(), 
+                                   PRE->isSuperReceiver());
+      VK = Expr::getValueKindForType(GetterMethod->getResultType());
     }
     else {
       Diag(PRE->getLocation(), diag::err_getter_not_found)
             << PRE->getBase()->getType();
     }
   }
-
-  E = ImplicitCastExpr::Create(Context, E->getType(), CK_GetObjCProperty,
+  
+  E = ImplicitCastExpr::Create(Context, T, CK_GetObjCProperty,
                                E, 0, VK);
   
   ExprResult Result = MaybeBindToTemporary(E);
@@ -9851,6 +9868,7 @@
     *Complained = false;
 
   // Decode the result (notice that AST's are still created for extensions).
+  bool CheckInferredResultType = false;
   bool isInvalid = false;
   unsigned DiagKind;
   FixItHint Hint;
@@ -9867,6 +9885,8 @@
   case IncompatiblePointer:
     MakeObjCStringLiteralFixItHint(*this, DstType, SrcExpr, Hint);
     DiagKind = diag::ext_typecheck_convert_incompatible_pointer;
+    CheckInferredResultType = DstType->isObjCObjectPointerType() &&
+      SrcType->isObjCObjectPointerType();
     break;
   case IncompatiblePointerSign:
     DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
@@ -9948,6 +9968,9 @@
 
   Diag(Loc, DiagKind) << FirstType << SecondType << Action
     << SrcExpr->getSourceRange() << Hint;
+  if (CheckInferredResultType)
+    EmitRelatedResultTypeNote(SrcExpr);
+  
   if (Complained)
     *Complained = true;
   return isInvalid;

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Jun 10 20:09:30 2011
@@ -2221,6 +2221,10 @@
              diag::ext_typecheck_convert_incompatible_pointer)
           << From->getType() << ToType << Action
           << From->getSourceRange();
+      
+      if (From->getType()->isObjCObjectPointerType() &&
+          ToType->isObjCObjectPointerType())
+        EmitRelatedResultTypeNote(From);
     }
 
     CastKind Kind = CK_Invalid;

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Jun 10 20:09:30 2011
@@ -241,10 +241,72 @@
   return method;
 }
 
+QualType Sema::getMessageSendResultType(QualType ReceiverType,
+                                        ObjCMethodDecl *Method,
+                                    bool isClassMessage, bool isSuperMessage) {
+  assert(Method && "Must have a method");
+  if (!Method->hasRelatedResultType())
+    return Method->getSendResultType();
+  
+  // If a method has a related return type:
+  //   - if the method found is an instance method, but the message send
+  //     was a class message send, T is the declared return type of the method
+  //     found
+  if (Method->isInstanceMethod() && isClassMessage)
+    return Method->getSendResultType();
+  
+  //   - if the receiver is super, T is a pointer to the class of the 
+  //     enclosing method definition
+  if (isSuperMessage) {
+    if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
+      if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface())
+        return Context.getObjCObjectPointerType(
+                                        Context.getObjCInterfaceType(Class));
+  }
+    
+  //   - if the receiver is the name of a class U, T is a pointer to U
+  if (ReceiverType->getAs<ObjCInterfaceType>() ||
+      ReceiverType->isObjCQualifiedInterfaceType())
+    return Context.getObjCObjectPointerType(ReceiverType);
+  //   - if the receiver is of type Class or qualified Class type, 
+  //     T is the declared return type of the method.
+  if (ReceiverType->isObjCClassType() ||
+      ReceiverType->isObjCQualifiedClassType())
+    return  Method->getSendResultType();
+  
+  //   - if the receiver is id, qualified id, Class, or qualified Class, T
+  //     is the receiver type, otherwise
+  //   - T is the type of the receiver expression.
+  return ReceiverType;
+}
 
-bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
+void Sema::EmitRelatedResultTypeNote(const Expr *E) {
+  E = E->IgnoreParenImpCasts();
+  const ObjCMessageExpr *MsgSend = dyn_cast<ObjCMessageExpr>(E);
+  if (!MsgSend)
+    return;
+  
+  const ObjCMethodDecl *Method = MsgSend->getMethodDecl();
+  if (!Method)
+    return;
+  
+  if (!Method->hasRelatedResultType())
+    return;
+  
+  if (Context.hasSameUnqualifiedType(Method->getResultType()
+                                                        .getNonReferenceType(),
+                                     MsgSend->getType()))
+    return;
+  
+  Diag(Method->getLocation(), diag::note_related_result_type_inferred)
+    << Method->isInstanceMethod() << Method->getSelector()
+    << MsgSend->getType();
+}
+
+bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
+                                     Expr **Args, unsigned NumArgs,
                                      Selector Sel, ObjCMethodDecl *Method,
-                                     bool isClassMessage,
+                                     bool isClassMessage, bool isSuperMessage,
                                      SourceLocation lbrac, SourceLocation rbrac,
                                      QualType &ReturnType, ExprValueKind &VK) {
   if (!Method) {
@@ -268,7 +330,8 @@
     return false;
   }
 
-  ReturnType = Method->getSendResultType();
+  ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage, 
+                                        isSuperMessage);
   VK = Expr::getValueKindForType(Method->getResultType());
 
   unsigned NumNamedArgs = Sel.getNumArgs();
@@ -456,9 +519,12 @@
     ResTy = ResTy.getNonLValueExprType(Context);
     Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
     ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
-    if (DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc))
-      ResTy = Getter->getResultType();
-
+    if (Getter &&
+        (Getter->hasRelatedResultType()
+         || DiagnosePropertyAccessorMismatch(PD, Getter, MemberLoc)))
+        ResTy = getMessageSendResultType(QualType(OPT, 0), Getter, false, 
+                                         Super);
+             
     if (Super)
       return Owned(new (Context) ObjCPropertyRefExpr(PD, ResTy,
                                                      VK_LValue, OK_ObjCProperty,
@@ -476,14 +542,18 @@
       // Check whether we can reference this property.
       if (DiagnoseUseOfDecl(PD, MemberLoc))
         return ExprError();
+      
+      QualType T = PD->getType();
+      if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl())
+        T = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
       if (Super)
-        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+        return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
                                                        VK_LValue,
                                                        OK_ObjCProperty,
                                                        MemberLoc, 
                                                        SuperLoc, SuperType));
       else
-        return Owned(new (Context) ObjCPropertyRefExpr(PD, PD->getType(),
+        return Owned(new (Context) ObjCPropertyRefExpr(PD, T,
                                                        VK_LValue,
                                                        OK_ObjCProperty,
                                                        MemberLoc,
@@ -540,7 +610,7 @@
   if (Getter || Setter) {
     QualType PType;
     if (Getter)
-      PType = Getter->getSendResultType();
+      PType = getMessageSendResultType(QualType(OPT, 0), Getter, false, Super);
     else {
       ParmVarDecl *ArgDecl = *Setter->param_begin();
       PType = ArgDecl->getType();
@@ -614,10 +684,14 @@
   IdentifierInfo *receiverNamePtr = &receiverName;
   ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
                                                   receiverNameLoc);
+
+  bool IsSuper = false;
   if (IFace == 0) {
     // If the "receiver" is 'super' in a method, handle it as an expression-like
     // property reference.
     if (receiverNamePtr->isStr("super")) {
+      IsSuper = true;
+
       if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf()) {
         if (CurMethod->isInstanceMethod()) {
           QualType T = 
@@ -686,7 +760,9 @@
 
     ExprValueKind VK = VK_LValue;
     if (Getter) {
-      PType = Getter->getSendResultType();
+      PType = getMessageSendResultType(Context.getObjCInterfaceType(IFace),
+                                       Getter, true, 
+                                       receiverNamePtr->isStr("super"));
       if (!getLangOptions().CPlusPlus &&
           !PType.hasQualifiers() && PType->isVoidType())
         VK = VK_RValue;
@@ -699,6 +775,13 @@
 
     ExprObjectKind OK = (VK == VK_RValue ? OK_Ordinary : OK_ObjCProperty);
 
+    if (IsSuper)
+    return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
+                                                   PType, VK, OK,
+                                                   propertyNameLoc,
+                                                   receiverNameLoc, 
+                                          Context.getObjCInterfaceType(IFace)));
+
     return Owned(new (Context) ObjCPropertyRefExpr(Getter, Setter,
                                                    PType, VK, OK,
                                                    propertyNameLoc,
@@ -955,8 +1038,9 @@
 
   unsigned NumArgs = ArgsIn.size();
   Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release());
-  if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, true,
-                                LBracLoc, RBracLoc, ReturnType, VK))
+  if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true,
+                                SuperLoc.isValid(), LBracLoc, RBracLoc, 
+                                ReturnType, VK))
     return ExprError();
 
   if (Method && !Method->getResultType()->isVoidType() &&
@@ -1238,7 +1322,8 @@
   ExprValueKind VK = VK_RValue;
   bool ClassMessage = (ReceiverType->isObjCClassType() ||
                        ReceiverType->isObjCQualifiedClassType());
-  if (CheckMessageArgumentTypes(Args, NumArgs, Sel, Method, ClassMessage,
+  if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, 
+                                ClassMessage, SuperLoc.isValid(), 
                                 LBracLoc, RBracLoc, ReturnType, VK))
     return ExprError();
   

Modified: cfe/trunk/lib/Sema/SemaInit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaInit.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaInit.cpp (original)
+++ cfe/trunk/lib/Sema/SemaInit.cpp Fri Jun 10 20:09:30 2011
@@ -4322,6 +4322,9 @@
       << Args[0]->isLValue()
       << Args[0]->getType()
       << Args[0]->getSourceRange();
+    if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+        Args[0]->getType()->isObjCObjectPointerType())
+      S.EmitRelatedResultTypeNote(Args[0]);
     break;
 
   case FK_ConversionFailed: {
@@ -4332,6 +4335,9 @@
       << Args[0]->isLValue()
       << FromType
       << Args[0]->getSourceRange();
+    if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+        Args[0]->getType()->isObjCObjectPointerType())
+      S.EmitRelatedResultTypeNote(Args[0]);
     break;
   }
 

Modified: cfe/trunk/lib/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/lib/Sema/SemaStmt.cpp Fri Jun 10 20:09:30 2011
@@ -1682,15 +1682,26 @@
     return ActOnBlockReturnStmt(ReturnLoc, RetValExp);
 
   QualType FnRetType;
+  QualType DeclaredRetType;
   if (const FunctionDecl *FD = getCurFunctionDecl()) {
     FnRetType = FD->getResultType();
+    DeclaredRetType = FnRetType;
     if (FD->hasAttr<NoReturnAttr>() ||
         FD->getType()->getAs<FunctionType>()->getNoReturnAttr())
       Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr)
         << getCurFunctionOrMethodDecl()->getDeclName();
-  } else if (ObjCMethodDecl *MD = getCurMethodDecl())
-    FnRetType = MD->getResultType();
-  else // If we don't have a function/method context, bail.
+  } else if (ObjCMethodDecl *MD = getCurMethodDecl()) {
+    DeclaredRetType = MD->getResultType();
+    if (MD->hasRelatedResultType() && MD->getClassInterface()) {
+      // In the implementation of a method with a related return type, the
+      // type used to type-check the validity of return statements within the 
+      // method body is a pointer to the type of the class being implemented.
+      FnRetType = Context.getObjCInterfaceType(MD->getClassInterface());
+      FnRetType = Context.getObjCObjectPointerType(FnRetType);
+    } else {
+      FnRetType = DeclaredRetType;
+    }
+  } else // If we don't have a function/method context, bail.
     return StmtError();
 
   ReturnStmt *Result = 0;
@@ -1764,6 +1775,17 @@
     }
 
     if (RetValExp) {
+      // If we type-checked an Objective-C method's return type based
+      // on a related return type, we may need to adjust the return
+      // type again. Do so now.
+      if (DeclaredRetType != FnRetType) {
+        ExprResult result = PerformImplicitConversion(RetValExp,
+                                                      DeclaredRetType,
+                                                      AA_Returning);
+        if (result.isInvalid()) return StmtError();
+        RetValExp = result.take();
+      }
+
       CheckImplicitConversions(RetValExp, ReturnLoc);
       RetValExp = MaybeCreateExprWithCleanups(RetValExp);
     }

Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Fri Jun 10 20:09:30 2011
@@ -92,6 +92,7 @@
   PARSE_LANGOPT_IMPORTANT(AppleKext, diag::warn_pch_apple_kext);
   PARSE_LANGOPT_IMPORTANT(ObjCDefaultSynthProperties,
                           diag::warn_pch_objc_auto_properties);
+  PARSE_LANGOPT_BENIGN(ObjCInferRelatedResultType)
   PARSE_LANGOPT_IMPORTANT(NoConstantCFStrings,
                           diag::warn_pch_no_constant_cfstrings);
   PARSE_LANGOPT_BENIGN(PascalStrings);
@@ -2934,6 +2935,7 @@
     PARSE_LANGOPT(ObjCNonFragileABI2);
     PARSE_LANGOPT(AppleKext);
     PARSE_LANGOPT(ObjCDefaultSynthProperties);
+    PARSE_LANGOPT(ObjCInferRelatedResultType);
     PARSE_LANGOPT(NoConstantCFStrings);
     PARSE_LANGOPT(PascalStrings);
     PARSE_LANGOPT(WritableStrings);

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Jun 10 20:09:30 2011
@@ -468,6 +468,7 @@
   MD->setDefined(Record[Idx++]);
   MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record[Idx++]);
   MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record[Idx++]);
+  MD->SetRelatedResultType(Record[Idx++]);
   MD->setNumSelectorArgs(unsigned(Record[Idx++]));
   MD->setResultType(Reader.GetType(Record[Idx++]));
   MD->setResultTypeSourceInfo(GetTypeSourceInfo(Record, Idx));

Modified: cfe/trunk/lib/Serialization/ASTWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriter.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriter.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriter.cpp Fri Jun 10 20:09:30 2011
@@ -1050,6 +1050,7 @@
   Record.push_back(LangOpts.AppleKext);          // Apple's kernel extensions ABI
   Record.push_back(LangOpts.ObjCDefaultSynthProperties); // Objective-C auto-synthesized
                                                       // properties enabled.
+  Record.push_back(LangOpts.ObjCInferRelatedResultType);
   Record.push_back(LangOpts.NoConstantCFStrings); // non cfstring generation enabled..
 
   Record.push_back(LangOpts.PascalStrings);  // Allow Pascal strings

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Jun 10 20:09:30 2011
@@ -404,6 +404,7 @@
   Record.push_back(D->getImplementationControl());
   // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
   Record.push_back(D->getObjCDeclQualifier());
+  Record.push_back(D->hasRelatedResultType());
   Record.push_back(D->getNumSelectorArgs());
   Writer.AddTypeRef(D->getResultType(), Record);
   Writer.AddTypeSourceInfo(D->getResultTypeSourceInfo(), Record);

Modified: cfe/trunk/test/Driver/rewrite-objc.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/rewrite-objc.m?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/test/Driver/rewrite-objc.m (original)
+++ cfe/trunk/test/Driver/rewrite-objc.m Fri Jun 10 20:09:30 2011
@@ -3,7 +3,7 @@
 // TEST0: clang{{.*}}" "-cc1"
 // TEST0: "-rewrite-objc"
 // FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead.
-// TEST0: "-fmessage-length" "0" "-fobjc-exceptions" "-fdiagnostics-show-option"
+// TEST0: "-fmessage-length" "0" "-fobjc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option"
 // TEST0: rewrite-objc.m"
 
 // RUN: not %clang -ccc-no-clang -ccc-host-triple unknown -rewrite-objc %s -o - -### 2>&1 | \

Modified: cfe/trunk/test/PCH/objc_methods.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_methods.h?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objc_methods.h (original)
+++ cfe/trunk/test/PCH/objc_methods.h Fri Jun 10 20:09:30 2011
@@ -2,7 +2,7 @@
 
 @interface TestPCH
 + alloc;
-- (void)instMethod;
+- (id)init;
 @end
 
 @class TestForwardClassDecl;

Modified: cfe/trunk/test/PCH/objc_methods.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/PCH/objc_methods.m?rev=132868&r1=132867&r2=132868&view=diff
==============================================================================
--- cfe/trunk/test/PCH/objc_methods.m (original)
+++ cfe/trunk/test/PCH/objc_methods.m Fri Jun 10 20:09:30 2011
@@ -12,5 +12,5 @@
 // AliasForTestPCH *zz;
  
  xx = [TestPCH alloc];
- [xx instMethod];
+ [xx init];
 }

Added: cfe/trunk/test/SemaObjC/related-result-type-inference.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/related-result-type-inference.m?rev=132868&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/related-result-type-inference.m (added)
+++ cfe/trunk/test/SemaObjC/related-result-type-inference.m Fri Jun 10 20:09:30 2011
@@ -0,0 +1,171 @@
+// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+
+ at interface Unrelated
+ at end
+
+ at interface NSObject
++ (id)new;
++ (id)alloc;
+- (NSObject *)init;
+
+- (id)retain;  // expected-note{{instance method 'retain' is assumed to return an instance of its receiver type ('NSArray *')}}
+- autorelease;
+
+- (id)self;
+
+- (id)copy;
+- (id)mutableCopy;
+
+// Do not infer when instance/class mismatches
+- (id)newNotInferred;
+- (id)alloc;
++ (id)initWithBlarg;
++ (id)self;
+
+// Do not infer when the return types mismatch.
+- (Unrelated *)initAsUnrelated;
+ at end
+
+ at interface NSString : NSObject
+- (id)init;
+- (id)initWithCString:(const char*)string;
+ at end
+
+ at interface NSArray : NSObject
+- (unsigned)count;
+ at end
+
+ at interface NSBlah 
+ at end
+
+ at interface NSMutableArray : NSArray
+ at end
+
+ at interface NSBlah ()
++ (Unrelated *)newUnrelated;
+ at end
+
+void test_inference() {
+  // Inference based on method family
+  __typeof__(([[NSString alloc] init])) *str = (NSString**)0;
+  __typeof__(([[[[NSString new] self] retain] autorelease])) *str2 = (NSString **)0;
+  __typeof__(([[NSString alloc] initWithCString:"blah"])) *str3 = (NSString**)0;
+
+  // Not inferred
+  __typeof__(([[NSString new] copy])) *id1 = (id*)0;
+
+  // Not inferred due to instance/class mismatches
+  __typeof__(([[NSString new] newNotInferred])) *id2 = (id*)0;
+  __typeof__(([[NSString new] alloc])) *id3 = (id*)0;
+  __typeof__(([NSString self])) *id4 = (id*)0;
+  __typeof__(([NSString initWithBlarg])) *id5 = (id*)0;
+
+  // Not inferred due to return type mismatch
+  __typeof__(([[NSString alloc] initAsUnrelated])) *unrelated = (Unrelated**)0;
+  __typeof__(([NSBlah newUnrelated])) *unrelated2 = (Unrelated**)0;
+
+  
+  NSArray *arr = [[NSMutableArray alloc] init];
+  NSMutableArray *marr = [arr retain]; // expected-warning{{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
+}
+
+ at implementation NSBlah
++ (Unrelated *)newUnrelated {
+  return (Unrelated *)0;
+}
+ at end
+
+ at implementation NSBlah (Cat)
++ (Unrelated *)newUnrelated2 {
+  return (Unrelated *)0;
+}
+ at end
+
+ at interface A
+- (id)initBlah; // expected-note 2{{overridden method is part of the 'init' method family}}
+ at end
+
+ at interface B : A
+- (Unrelated *)initBlah; // expected-warning{{method is expected to return an instance of its class type 'B', but is declared to return 'Unrelated *'}}
+ at end
+
+ at interface C : A
+ at end
+
+ at implementation C
+- (Unrelated *)initBlah {  // expected-warning{{method is expected to return an instance of its class type 'C', but is declared to return 'Unrelated *'}}
+  return (Unrelated *)0;
+}
+ at end
+
+ at interface D
++ (id)newBlarg; // expected-note{{overridden method is part of the 'new' method family}}
+ at end
+
+ at interface D ()
++ alloc; // expected-note{{overridden method is part of the 'alloc' method family}}
+ at end
+
+ at implementation D
++ (Unrelated *)newBlarg { // expected-warning{{method is expected to return an instance of its class type 'D', but is declared to return 'Unrelated *'}}
+  return (Unrelated *)0;
+}
+
++ (Unrelated *)alloc { // expected-warning{{method is expected to return an instance of its class type 'D', but is declared to return 'Unrelated *'}}
+  return (Unrelated *)0;
+}
+ at end
+
+ at protocol P1
+- (id)initBlah; // expected-note{{overridden method is part of the 'init' method family}}
+- (int)initBlarg;
+ at end
+
+ at protocol P2 <P1>
+- (int)initBlah; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
+- (int)initBlarg;
+- (int)initBlech;
+ at end
+
+ at interface E
+- init;
+ at end
+
+ at implementation E
+- init {
+  return self;
+}
+ at end
+
+ at protocol P3
++ (NSString *)newString;
+ at end
+
+ at interface F<P3>
+ at end
+
+ at implementation F
++ (NSString *)newString { return @"blah"; }
+ at end
+
+// <rdar://problem/9340699>
+ at interface G
+- (id)_ABC_init __attribute__((objc_method_family(init)));
+ at end
+
+ at interface G (Additions)
+- (id)_ABC_init2 __attribute__((objc_method_family(init)));
+ at end
+
+ at implementation G (Additions)
+- (id)_ABC_init {
+  return 0;
+}
+- (id)_ABC_init2 {
+  return 0;
+}
+- (id)_ABC_init3 {
+  return 0;
+}
+ at end
+

Added: cfe/trunk/test/SemaObjCXX/related-result-type-inference.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/related-result-type-inference.mm?rev=132868&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjCXX/related-result-type-inference.mm (added)
+++ cfe/trunk/test/SemaObjCXX/related-result-type-inference.mm Fri Jun 10 20:09:30 2011
@@ -0,0 +1,70 @@
+// RUN: %clang_cc1 -fobjc-infer-related-result-type -verify %s
+
+ at interface Unrelated
+ at end
+
+ at interface NSObject
++ (id)new;
++ (id)alloc;
+- (NSObject *)init;
+
+- (id)retain;  // expected-note 2{{instance method 'retain' is assumed to return an instance of its receiver type ('NSArray *')}}
+- autorelease;
+
+- (id)self;
+
+- (id)copy;
+- (id)mutableCopy;
+
+// Do not infer when instance/class mismatches
+- (id)newNotInferred;
+- (id)alloc;
++ (id)initWithBlarg;
++ (id)self;
+
+// Do not infer when the return types mismatch.
+- (Unrelated *)initAsUnrelated;
+ at end
+
+ at interface NSString : NSObject
+- (id)init;
+- (id)initWithCString:(const char*)string;
+ at end
+
+ at interface NSArray : NSObject
+- (unsigned)count;
+ at end
+
+ at interface NSBlah 
+ at end
+
+ at interface NSMutableArray : NSArray
+ at end
+
+ at interface NSBlah ()
++ (Unrelated *)newUnrelated;
+ at end
+
+void test_inference() {
+  // Inference based on method family
+  __typeof__(([[NSString alloc] init])) *str = (NSString**)0;
+  __typeof__(([[[[NSString new] self] retain] autorelease])) *str2 = (NSString **)0;
+  __typeof__(([[NSString alloc] initWithCString:"blah"])) *str3 = (NSString**)0;
+
+  // Not inferred
+  __typeof__(([[NSString new] copy])) *id1 = (id*)0;
+
+  // Not inferred due to instance/class mismatches
+  __typeof__(([[NSString new] newNotInferred])) *id2 = (id*)0;
+  __typeof__(([[NSString new] alloc])) *id3 = (id*)0;
+  __typeof__(([NSString self])) *id4 = (id*)0;
+  __typeof__(([NSString initWithBlarg])) *id5 = (id*)0;
+
+  // Not inferred due to return type mismatch
+  __typeof__(([[NSString alloc] initAsUnrelated])) *unrelated = (Unrelated**)0;
+  __typeof__(([NSBlah newUnrelated])) *unrelated2 = (Unrelated**)0;  
+
+  NSArray *arr = [[NSMutableArray alloc] init];
+  NSMutableArray *marr = [arr retain]; // expected-warning{{incompatible pointer types initializing 'NSMutableArray *' with an expression of type 'NSArray *'}}
+  marr = [arr retain]; // expected-warning{{incompatible pointer types assigning to 'NSArray *' from 'NSMutableArray *'}}
+}





More information about the cfe-commits mailing list