aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-06-11 01:09:30 +0000
committerDouglas Gregor <dgregor@apple.com>2011-06-11 01:09:30 +0000
commit926df6cfabf3eaa4afc990c097fa4619b76a9b57 (patch)
treef48a5ca74fa783c76ae30e190d130881fc5febe8 /lib/Sema
parent45937ae10a0f70f74508165aab4f2b63e18ea747 (diff)
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 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132868 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-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
7 files changed, 429 insertions, 31 deletions
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 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 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
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 @@ Decl *Sema::ActOnMethodDeclaration(
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 @@ Decl *Sema::ActOnMethodDeclaration(
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 @@ Decl *Sema::ActOnMethodDeclaration(
}
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 @@ Decl *Sema::ActOnMethodDeclaration(
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 @@ Decl *Sema::ActOnMethodDeclaration(
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;
}
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index bb6a414f44..dafd56bf34 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4328,7 +4328,11 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
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 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
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 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
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 @@ ExprResult Sema::ConvertPropertyForRValue(Expr *E) {
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 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
*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 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
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 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
Diag(Loc, DiagKind) << FirstType << SecondType << Action
<< SrcExpr->getSourceRange() << Hint;
+ if (CheckInferredResultType)
+ EmitRelatedResultTypeNote(SrcExpr);
+
if (Complained)
*Complained = true;
return isInvalid;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 2cd495bf14..27659f6507 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -2221,6 +2221,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
diag::ext_typecheck_convert_incompatible_pointer)
<< From->getType() << ToType << Action
<< From->getSourceRange();
+
+ if (From->getType()->isObjCObjectPointerType() &&
+ ToType->isObjCObjectPointerType())
+ EmitRelatedResultTypeNote(From);
}
CastKind Kind = CK_Invalid;
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 3444cb5a49..cb5c1e0d0c 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -241,10 +241,72 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf() {
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;
+}
+
+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(Expr **Args, unsigned NumArgs,
+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 @@ bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
return false;
}
- ReturnType = Method->getSendResultType();
+ ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage,
+ isSuperMessage);
VK = Expr::getValueKindForType(Method->getResultType());
unsigned NumNamedArgs = Sel.getNumArgs();
@@ -456,9 +519,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
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 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// 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 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
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 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
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 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
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 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
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 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo,
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 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
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();
diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp
index 11061d53f1..a33f5d0b2f 100644
--- a/lib/Sema/SemaInit.cpp
+++ b/lib/Sema/SemaInit.cpp
@@ -4322,6 +4322,9 @@ bool InitializationSequence::Diagnose(Sema &S,
<< 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 @@ bool InitializationSequence::Diagnose(Sema &S,
<< Args[0]->isLValue()
<< FromType
<< Args[0]->getSourceRange();
+ if (DestType.getNonReferenceType()->isObjCObjectPointerType() &&
+ Args[0]->getType()->isObjCObjectPointerType())
+ S.EmitRelatedResultTypeNote(Args[0]);
break;
}
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index d4fc980e22..d7c0a543ee 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -1682,15 +1682,26 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
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 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
}
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);
}