aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/LanguageExtensions.html72
-rw-r--r--include/clang/AST/DeclObjC.h16
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td17
-rw-r--r--include/clang/Basic/IdentifierTable.h3
-rw-r--r--include/clang/Basic/LangOptions.h3
-rw-r--r--include/clang/Driver/CC1Options.td2
-rw-r--r--include/clang/Driver/Options.td4
-rw-r--r--include/clang/Sema/Sema.h30
-rw-r--r--lib/AST/ASTImporter.cpp3
-rw-r--r--lib/AST/DeclObjC.cpp3
-rw-r--r--lib/AST/DumpXML.cpp1
-rw-r--r--lib/Analysis/CocoaConventions.cpp1
-rw-r--r--lib/Basic/IdentifierTable.cpp1
-rw-r--r--lib/CodeGen/CGObjC.cpp75
-rw-r--r--lib/Driver/Tools.cpp6
-rw-r--r--lib/Frontend/CompilerInvocation.cpp6
-rw-r--r--lib/Parse/ParseObjc.cpp8
-rw-r--r--lib/Sema/SemaDecl.cpp4
-rw-r--r--lib/Sema/SemaDeclObjC.cpp268
-rw-r--r--lib/Sema/SemaExpr.cpp39
-rw-r--r--lib/Sema/SemaExprCXX.cpp4
-rw-r--r--lib/Sema/SemaExprObjC.cpp111
-rw-r--r--lib/Sema/SemaInit.cpp6
-rw-r--r--lib/Sema/SemaStmt.cpp28
-rw-r--r--lib/Serialization/ASTReader.cpp2
-rw-r--r--lib/Serialization/ASTReaderDecl.cpp1
-rw-r--r--lib/Serialization/ASTWriter.cpp1
-rw-r--r--lib/Serialization/ASTWriterDecl.cpp1
-rw-r--r--test/Driver/rewrite-objc.m2
-rw-r--r--test/PCH/objc_methods.h2
-rw-r--r--test/PCH/objc_methods.m2
-rw-r--r--test/SemaObjC/related-result-type-inference.m171
-rw-r--r--test/SemaObjCXX/related-result-type-inference.mm70
33 files changed, 895 insertions, 68 deletions
diff --git a/docs/LanguageExtensions.html b/docs/LanguageExtensions.html
index bc8ecb1bc9..8f43725d82 100644
--- a/docs/LanguageExtensions.html
+++ b/docs/LanguageExtensions.html
@@ -62,6 +62,11 @@ td {
</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 @@ href="Block-ABI-Apple.txt">Block-ABI-Apple.txt</a>.</p>
<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>
+@interface NSObject
++ (id)alloc;
+- (id)init;
+@end
+
+@interface NSArray : NSObject
+@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>
+@interface NSString : NSObject
+- (NSUnrelated *)init; // incorrect usage: NSUnrelated is not NSString or a superclass of NSString
+@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>
<!-- ======================================================================= -->
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 0a4d864cd8..0e698607db 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -135,6 +135,9 @@ private:
/// 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 @@ private:
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 @@ private:
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 @@ public:
bool isSynthesized = false,
bool isDefined = false,
ImplementationControl impControl = None,
+ bool HasRelatedResultType = false,
unsigned numSelectorArgs = 0);
virtual ObjCMethodDecl *getCanonicalDecl();
@@ -211,6 +216,13 @@ public:
}
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;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 17356b963d..7890aefc50 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -4117,5 +4117,22 @@ def err_invalid_astype_of_different_size : Error<
} // 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.
diff --git a/include/clang/Basic/IdentifierTable.h b/include/clang/Basic/IdentifierTable.h
index 683ec8312e..b4eca6d8fb 100644
--- a/include/clang/Basic/IdentifierTable.h
+++ b/include/clang/Basic/IdentifierTable.h
@@ -498,7 +498,8 @@ enum ObjCMethodFamily {
OMF_dealloc,
OMF_release,
OMF_retain,
- OMF_retainCount
+ OMF_retainCount,
+ OMF_self
};
/// Enough bits to store any enumerator in ObjCMethodFamily or
diff --git a/include/clang/Basic/LangOptions.h b/include/clang/Basic/LangOptions.h
index a5f6789b7d..f0f1432ca0 100644
--- a/include/clang/Basic/LangOptions.h
+++ b/include/clang/Basic/LangOptions.h
@@ -46,6 +46,8 @@ public:
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 @@ public:
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;
diff --git a/include/clang/Driver/CC1Options.td b/include/clang/Driver/CC1Options.td
index 155ecae579..14d8f67b9d 100644
--- a/include/clang/Driver/CC1Options.td
+++ b/include/clang/Driver/CC1Options.td
@@ -493,6 +493,8 @@ def print_ivar_layout : Flag<"-print-ivar-layout">,
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">,
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index 23b351c78a..72039766d9 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -392,6 +392,10 @@ def fobjc_gc_only : Flag<"-fobjc-gc-only">, Group<f_Group>;
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>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index a1c0ba9dcf..bb3ec2dbed 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -4981,7 +4981,7 @@ public:
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 @@ public:
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 @@ public:
/// \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
diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp
index 8904a9561c..fcca95cefd 100644
--- a/lib/AST/ASTImporter.cpp
+++ b/lib/AST/ASTImporter.cpp
@@ -2870,7 +2870,8 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) {
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.
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index 24d281e8b6..e2c4f38ff9 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -339,12 +339,14 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C,
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 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const {
case OMF_release:
case OMF_autorelease:
case OMF_retainCount:
+ case OMF_self:
if (!isInstanceMethod())
family = OMF_None;
break;
diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp
index 12806aad1d..dfe0119f59 100644
--- a/lib/AST/DumpXML.cpp
+++ b/lib/AST/DumpXML.cpp
@@ -848,6 +848,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>,
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());
diff --git a/lib/Analysis/CocoaConventions.cpp b/lib/Analysis/CocoaConventions.cpp
index 4c62f36e6c..946c38c875 100644
--- a/lib/Analysis/CocoaConventions.cpp
+++ b/lib/Analysis/CocoaConventions.cpp
@@ -44,6 +44,7 @@ cocoa::NamingConvention cocoa::deriveNamingConvention(Selector S) {
case OMF_release:
case OMF_retain:
case OMF_retainCount:
+ case OMF_self:
return NoConvention;
case OMF_init:
diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp
index cb1f55b757..4711faa1a5 100644
--- a/lib/Basic/IdentifierTable.cpp
+++ b/lib/Basic/IdentifierTable.cpp
@@ -392,6 +392,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
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.
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp
index 28e7e42885..fa42cd1f36 100644
--- a/lib/CodeGen/CGObjC.cpp
+++ b/lib/CodeGen/CGObjC.cpp
@@ -47,6 +47,23 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) {
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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
}
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 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
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 @@ RValue CodeGenFunction::EmitLoadOfPropertyRefLValue(LValue LV,
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,
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index bc3ff6873b..8cd7adc42e 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -1542,6 +1542,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
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);
diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index b8b5011bbf..536512a121 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -670,6 +670,9 @@ static void LangOptsToArgs(const LangOptions &Opts,
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 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK,
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);
diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp
index fdbedc54d1..a8c18c01a2 100644
--- a/lib/Parse/ParseObjc.cpp
+++ b/lib/Parse/ParseObjc.cpp
@@ -874,8 +874,8 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
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 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc,
&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);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 9967fd3ebf..c2fee32aea 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1936,7 +1936,9 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
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
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 4e41aa93e5..de9097e98b 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -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 Resul