diff options
| author | Douglas Gregor <dgregor@apple.com> | 2011-06-11 01:09:30 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2011-06-11 01:09:30 +0000 |
| commit | 33823727c80ad78773c09a588d8399fc0f4f0b9a (patch) | |
| tree | 50d799ac17909bce14702c0b8a689ebabd05f9e8 /clang/lib | |
| parent | 3d4e64b082717170ef918cb88b337087fb461b35 (diff) | |
| download | bcm5719-llvm-33823727c80ad78773c09a588d8399fc0f4f0b9a.tar.gz bcm5719-llvm-33823727c80ad78773c09a588d8399fc0f4f0b9a.zip | |
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
llvm-svn: 132868
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/AST/DeclObjC.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/AST/DumpXML.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Analysis/CocoaConventions.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Basic/IdentifierTable.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGObjC.cpp | 75 | ||||
| -rw-r--r-- | clang/lib/Driver/Tools.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Frontend/CompilerInvocation.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseObjc.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDeclObjC.cpp | 268 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 39 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 111 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaStmt.cpp | 28 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 1 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriterDecl.cpp | 1 |
20 files changed, 510 insertions, 59 deletions
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 8904a9561cd..fcca95cefd6 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/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/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 24d281e8b66..e2c4f38ff9b 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/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/clang/lib/AST/DumpXML.cpp b/clang/lib/AST/DumpXML.cpp index 12806aad1d7..dfe0119f597 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/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/clang/lib/Analysis/CocoaConventions.cpp b/clang/lib/Analysis/CocoaConventions.cpp index 4c62f36e6c9..946c38c875d 100644 --- a/clang/lib/Analysis/CocoaConventions.cpp +++ b/clang/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/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index cb1f55b7577..4711faa1a51 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/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/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 28e7e428857..fa42cd1f36a 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/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/clang/lib/Driver/Tools.cpp b/clang/lib/Driver/Tools.cpp index bc3ff6873b7..8cd7adc42e8 100644 --- a/clang/lib/Driver/Tools.cpp +++ b/clang/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/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index b8b5011bbfa..536512a121e 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/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/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index fdbedc54d1c..a8c18c01a29 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/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/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 9967fd3ebfd..c2fee32aea0 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 4e41aa93e5a..de9097e98b4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index bb6a414f448..dafd56bf349 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 2cd495bf146..27659f65077 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/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/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index 3444cb5a494..cb5c1e0d0cb 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/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/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 11061d53f12..a33f5d0b2f3 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/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/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d4fc980e228..d7c0a543eed 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/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); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 3c3993f412d..8fb20d22b7d 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -92,6 +92,7 @@ PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { 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 @@ bool ASTReader::ParseLanguageOptions( PARSE_LANGOPT(ObjCNonFragileABI2); PARSE_LANGOPT(AppleKext); PARSE_LANGOPT(ObjCDefaultSynthProperties); + PARSE_LANGOPT(ObjCInferRelatedResultType); PARSE_LANGOPT(NoConstantCFStrings); PARSE_LANGOPT(PascalStrings); PARSE_LANGOPT(WritableStrings); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index d2b014842c1..6e9d4d48204 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -468,6 +468,7 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { 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)); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 194d6c31cfa..ba9032e0d33 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -1050,6 +1050,7 @@ void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { 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 diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 71eb5e82313..c6b159c50bc 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -404,6 +404,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { 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); |

