aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2011-09-08 01:46:34 +0000
committerDouglas Gregor <dgregor@apple.com>2011-09-08 01:46:34 +0000
commite97179c675b341927807c718be215c8d1aab8acb (patch)
treeb1dbf4795e91cd0cea64fc6c3085952b76860141 /lib
parent4fe4d73bce7aba5446dcbfa36ee8782c6d496710 (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.cpp13
-rw-r--r--lib/Lex/PPMacroExpansion.cpp1
-rw-r--r--lib/Parse/ParseObjc.cpp10
-rw-r--r--lib/Parse/Parser.cpp1
-rw-r--r--lib/Sema/SemaDeclObjC.cpp53
-rw-r--r--lib/Sema/SemaExprObjC.cpp4
-rw-r--r--lib/Sema/SemaType.cpp7
-rw-r--r--lib/Serialization/ASTReader.cpp4
-rw-r--r--lib/Serialization/ASTWriter.cpp2
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