Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -9678,21 +9678,20 @@ /// \param Method - May be null. /// \param [out] ReturnType - The return type of the send. /// \return true iff there were any incompatible types. - bool CheckMessageArgumentTypes(QualType ReceiverType, + bool CheckMessageArgumentTypes(const Expr *Receiver, QualType ReceiverType, MultiExprArg Args, Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, bool isClassMessage, - bool isSuperMessage, - SourceLocation lbrac, SourceLocation rbrac, - SourceRange RecRange, + bool isSuperMessage, SourceLocation lbrac, + SourceLocation rbrac, SourceRange RecRange, 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); + QualType getMessageSendResultType(const Expr *Receiver, 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. Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -1343,7 +1343,8 @@ return transferNullability(ReceiverType); } -QualType Sema::getMessageSendResultType(QualType ReceiverType, +QualType Sema::getMessageSendResultType(const Expr *Receiver, + QualType ReceiverType, ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage) { @@ -1354,8 +1355,31 @@ isSuperMessage); // If this is a class message, ignore the nullability of the receiver. - if (isClassMessage) + if (isClassMessage) { + // Messages to 'self' that return 'instancetype' in class methods return + // pointer to the parent interface of the method when ARC is enabled ( + // because self can't be reassigned when ARC is on). + if (Receiver && Receiver->isObjCSelfExpr()) { + assert(ReceiverType->isObjCClassType() && "expected a Class self"); + QualType T = Method->getSendResultType(ReceiverType); + AttributedType::stripOuterNullability(T); + if (T == Context.getObjCInstanceType()) { + const ObjCMethodDecl *MD = cast( + cast( + cast(Receiver->IgnoreParenImpCasts())->getDecl()) + ->getDeclContext()); + assert(MD->isClassMethod() && "expected a class method"); + QualType NewResultType = Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(MD->getClassInterface())); + if (auto Nullability = resultType->getNullability(Context)) + NewResultType = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*Nullability), + NewResultType, NewResultType); + return NewResultType; + } + } return resultType; + } // Map the nullability of the result into a table index. unsigned receiverNullabilityIdx = 0; @@ -1497,15 +1521,12 @@ << MsgSend->getType(); } -bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, - MultiExprArg Args, - Selector Sel, - ArrayRef SelectorLocs, - ObjCMethodDecl *Method, - bool isClassMessage, bool isSuperMessage, - SourceLocation lbrac, SourceLocation rbrac, - SourceRange RecRange, - QualType &ReturnType, ExprValueKind &VK) { +bool Sema::CheckMessageArgumentTypes( + const Expr *Receiver, QualType ReceiverType, MultiExprArg Args, + Selector Sel, ArrayRef SelectorLocs, ObjCMethodDecl *Method, + bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, + SourceLocation rbrac, SourceRange RecRange, QualType &ReturnType, + ExprValueKind &VK) { SourceLocation SelLoc; if (!SelectorLocs.empty() && SelectorLocs.front().isValid()) SelLoc = SelectorLocs.front(); @@ -1582,8 +1603,8 @@ return false; } - ReturnType = getMessageSendResultType(ReceiverType, Method, isClassMessage, - isSuperMessage); + ReturnType = getMessageSendResultType(Receiver, ReceiverType, Method, + isClassMessage, isSuperMessage); VK = Expr::getValueKindForType(Method->getReturnType()); unsigned NumNamedArgs = Sel.getNumArgs(); @@ -2467,12 +2488,10 @@ unsigned NumArgs = ArgsIn.size(); Expr **Args = ArgsIn.data(); - if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), - Sel, SelectorLocs, - Method, true, - SuperLoc.isValid(), LBracLoc, RBracLoc, - SourceRange(), - ReturnType, VK)) + if (CheckMessageArgumentTypes(/*Receiver=*/nullptr, ReceiverType, + MultiExprArg(Args, NumArgs), Sel, SelectorLocs, + Method, true, SuperLoc.isValid(), LBracLoc, + RBracLoc, SourceRange(), ReturnType, VK)) return ExprError(); if (Method && !Method->getReturnType()->isVoidType() && @@ -2961,9 +2980,9 @@ ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(ReceiverType, MultiExprArg(Args, NumArgs), - Sel, SelectorLocs, Method, - ClassMessage, SuperLoc.isValid(), + if (CheckMessageArgumentTypes(Receiver, ReceiverType, + MultiExprArg(Args, NumArgs), Sel, SelectorLocs, + Method, ClassMessage, SuperLoc.isValid(), LBracLoc, RBracLoc, RecRange, ReturnType, VK)) return ExprError(); Index: test/SemaObjC/multiple-method-names-in-class-self.m =================================================================== --- /dev/null +++ test/SemaObjC/multiple-method-names-in-class-self.m @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify %s +// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify -fobjc-arc %s +// expected-no-diagnostics + +@interface NSObj + ++ (instancetype) alloc; + ++ (_Nonnull instancetype) globalObject; + +@end + +@interface SelfAllocReturn: NSObj + +- (instancetype)initWithFoo:(int)x; + +@end + +@interface SelfAllocReturn2: NSObj + +- (instancetype)initWithFoo:(SelfAllocReturn *)x; + +@end + +@implementation SelfAllocReturn + +- (instancetype)initWithFoo:(int)x { + return self; +} + ++ (instancetype) thingWithFoo:(int)x { + return [[self alloc] initWithFoo: x]; +} + ++ (void) initGlobal { + (void)[[self globalObject] initWithFoo: 20]; +} + +@end