diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-09-08 01:46:34 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-09-08 01:46:34 +0000 |
commit | e97179c675b341927807c718be215c8d1aab8acb (patch) | |
tree | b1dbf4795e91cd0cea64fc6c3085952b76860141 /lib | |
parent | 4fe4d73bce7aba5446dcbfa36ee8782c6d496710 (diff) |
Implement the Objective-C 'instancetype' type, which is an alias of
'id' that can be used (only!) via a contextual keyword as the result
type of an Objective-C message send. 'instancetype' then gives the
method a related result type, which we have already been inferring for
a variety of methods (new, alloc, init, self, retain). Addresses
<rdar://problem/9267640>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@139275 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 13 | ||||
-rw-r--r-- | lib/Lex/PPMacroExpansion.cpp | 1 | ||||
-rw-r--r-- | lib/Parse/ParseObjc.cpp | 10 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclObjC.cpp | 53 | ||||
-rw-r--r-- | lib/Sema/SemaExprObjC.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 4 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 2 |
9 files changed, 76 insertions, 19 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c300894456..3a3fba5d61 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -225,7 +225,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, GlobalNestedNameSpecifier(0), Int128Decl(0), UInt128Decl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), - CFConstantStringTypeDecl(0), + CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), @@ -3844,6 +3844,17 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { return getPointerType(getTagDeclType(T)); } +TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { + if (!ObjCInstanceTypeDecl) + ObjCInstanceTypeDecl = TypedefDecl::Create(*this, + getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + &Idents.get("instancetype"), + getTrivialTypeSourceInfo(getObjCIdType())); + return ObjCInstanceTypeDecl; +} + // This returns true if a type has been typedefed to BOOL: // typedef <type> BOOL; static bool isTypeTypedefedAsBOOL(QualType T) { diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index fce593fe9e..2bf172dec1 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -599,6 +599,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("objc_arc", LangOpts.ObjCAutoRefCount) .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && LangOpts.ObjCRuntimeHasWeak) + .Case("objc_instancetype", LangOpts.ObjC2) .Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI) .Case("objc_weak_class", LangOpts.ObjCNonFragileABI) .Case("ownership_holds", true) diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index 5be5a6c3c2..1f1266cab7 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -801,8 +801,16 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS, ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS); if (!TypeSpec.isInvalid()) Ty = TypeSpec.get(); + } else if (Context == OTN_ResultType && Tok.is(tok::identifier)) { + if (!Ident_instancetype) + Ident_instancetype = PP.getIdentifierInfo("instancetype"); + + if (Tok.getIdentifierInfo() == Ident_instancetype) { + Ty = Actions.ActOnObjCInstanceType(Tok.getLocation()); + ConsumeToken(); + } } - + if (Tok.is(tok::r_paren)) ConsumeParen(); else if (Tok.getLocation() == TypeStartLoc) { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 9a26a5a399..c31e1634a0 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -443,6 +443,7 @@ void Parser::Initialize() { ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref"); } + Ident_instancetype = 0; Ident_final = 0; Ident_override = 0; diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 3e657c70e6..8dfdeb4b60 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -148,8 +148,13 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod, << ResultTypeRange; } - Diag(Overridden->getLocation(), diag::note_related_result_type_overridden) - << Overridden->getMethodFamily(); + if (ObjCMethodFamily Family = Overridden->getMethodFamily()) + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden_family) + << Family; + else + Diag(Overridden->getLocation(), + diag::note_related_result_type_overridden); } return false; @@ -2261,16 +2266,22 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) { return false; } +namespace { + /// \brief Describes the compatibility of a result type with its method. + enum ResultTypeCompatibilityKind { + RTC_Compatible, + RTC_Incompatible, + RTC_Unknown + }; +} + /// \brief Check whether the declared result type of the given Objective-C /// method declaration is compatible with the method's class. /// -static bool +static ResultTypeCompatibilityKind 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 @@ -2280,23 +2291,27 @@ CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method, // - it is id or qualified id, or if (ResultObjectType->isObjCIdType() || ResultObjectType->isObjCQualifiedIdType()) - return false; + return RTC_Compatible; if (CurrentClass) { if (ObjCInterfaceDecl *ResultClass = ResultObjectType->getInterfaceDecl()) { // - it is the same as the method's class type, or if (CurrentClass == ResultClass) - return false; + return RTC_Compatible; // - it is a superclass of the method's class type if (ResultClass->isSuperClassOf(CurrentClass)) - return false; + return RTC_Compatible; } + } else { + // Any Objective-C pointer type might be acceptable for a protocol + // method; we just don't know. + return RTC_Unknown; } } - return true; + return RTC_Incompatible; } namespace { @@ -2457,6 +2472,7 @@ Decl *Sema::ActOnMethodDeclaration( Decl *ClassDecl = cast<Decl>(OCD); QualType resultDeclType; + bool HasRelatedResultType = false; TypeSourceInfo *ResultTInfo = 0; if (ReturnType) { resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo); @@ -2468,6 +2484,8 @@ Decl *Sema::ActOnMethodDeclaration( << 0 << resultDeclType; return 0; } + + HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType()); } else { // get the type for "id". resultDeclType = Context.getObjCIdType(); Diag(MethodLoc, diag::warn_missing_method_return_type) @@ -2484,7 +2502,7 @@ Decl *Sema::ActOnMethodDeclaration( MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required, - false); + HasRelatedResultType); SmallVector<ParmVarDecl*, 16> Params; @@ -2604,9 +2622,8 @@ Decl *Sema::ActOnMethodDeclaration( CurrentClass = CatImpl->getClassInterface(); } - bool isRelatedResultTypeCompatible = - (getLangOptions().ObjCInferRelatedResultType && - !CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass)); + ResultTypeCompatibilityKind RTC + = CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass); // Search for overridden methods and merge information down from them. OverrideSearch overrides(*this, ObjCMethod); @@ -2615,7 +2632,7 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethodDecl *overridden = *i; // Propagate down the 'related result type' bit from overridden methods. - if (isRelatedResultTypeCompatible && overridden->hasRelatedResultType()) + if (RTC != RTC_Incompatible && overridden->hasRelatedResultType()) ObjCMethod->SetRelatedResultType(); // Then merge the declarations. @@ -2633,8 +2650,10 @@ Decl *Sema::ActOnMethodDeclaration( if (getLangOptions().ObjCAutoRefCount) ARCError = CheckARCMethodDecl(*this, ObjCMethod); - if (!ARCError && isRelatedResultTypeCompatible && - !ObjCMethod->hasRelatedResultType()) { + // Infer the related result type when possible. + if (!ARCError && RTC == RTC_Compatible && + !ObjCMethod->hasRelatedResultType() && + LangOpts.ObjCInferRelatedResultType) { bool InferRelatedResultType = false; switch (ObjCMethod->getMethodFamily()) { case OMF_None: diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index aa9b4748a0..9f2696e128 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -328,6 +328,10 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) { MsgSend->getType())) return; + if (!Context.hasSameUnqualifiedType(Method->getResultType(), + Context.getObjCInstanceType())) + return; + Diag(Method->getLocation(), diag::note_related_result_type_inferred) << Method->isInstanceMethod() << Method->getSelector() << MsgSend->getType(); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c89423037b..e48704ca1d 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -3053,6 +3053,13 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { return CreateParsedType(T, TInfo); } +ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { + QualType T = Context.getObjCInstanceType(); + TypeSourceInfo *TInfo = Context.getTrivialTypeSourceInfo(T, Loc); + return CreateParsedType(T, TInfo); +} + + //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 37a23faf0d..251d0f6e31 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -4126,6 +4126,10 @@ Decl *ASTReader::GetDecl(DeclID ID) { case PREDEF_DECL_UNSIGNED_INT_128_ID: assert(Context && "No context available?"); return Context->getUInt128Decl(); + + case PREDEF_DECL_OBJC_INSTANCETYPE_ID: + assert(Context && "No context available?"); + return Context->getObjCInstanceTypeDecl(); } return 0; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 733f5d0583..bdca689d6f 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -2880,6 +2880,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID; if (Context.UInt128Decl) DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID; + if (Context.ObjCInstanceTypeDecl) + DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID; if (!Chain) { // Make sure that we emit IdentifierInfos (and any attached |