forked from OSchip/llvm-project
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>. llvm-svn: 139275
This commit is contained in:
parent
af3d4af4eb
commit
bab8a96f2f
|
@ -723,7 +723,19 @@ related result type. Similarly, the type of the expression
|
||||||
<code>init</code> has a related result type and its receiver is known
|
<code>init</code> has a related result type and its receiver is known
|
||||||
to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
|
to have the type <code>NSArray *</code>. If neither <code>alloc</code> nor <code>init</code> had a related result type, the expressions would have had type <code>id</code>, as declared in the method signature.</p>
|
||||||
|
|
||||||
<p>To determine whether a method has a related result type, the first
|
<p>A method with a related result type can be declared by using the
|
||||||
|
type <tt>instancetype</tt> as its result type. <tt>instancetype</tt>
|
||||||
|
is a contextual keyword that is only permitted in the result type of
|
||||||
|
an Objective-C method, e.g.</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
@interface A
|
||||||
|
+ (<b>instancetype</b>)constructAnA;
|
||||||
|
@end
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>The related result type can also be inferred for some methods.
|
||||||
|
To determine whether a method has an inferred related result type, the first
|
||||||
word in the camel-case selector (e.g., "init" in "initWithObjects") is
|
word in the camel-case selector (e.g., "init" in "initWithObjects") is
|
||||||
considered, and the method will a related result type if its return
|
considered, and the method will a related result type if its return
|
||||||
type is compatible with the type of its class and if</p>
|
type is compatible with the type of its class and if</p>
|
||||||
|
@ -752,8 +764,8 @@ with the subclass type. For example:</p>
|
||||||
|
|
||||||
<p>Related result types only affect the type of a message send or
|
<p>Related result types only affect the type of a message send or
|
||||||
property access via the given method. In all other respects, a method
|
property access via the given method. In all other respects, a method
|
||||||
with a related result type is treated the same way as method without a
|
with a related result type is treated the same way as method that
|
||||||
related result type.</p>
|
returns <tt>id</tt>.</p>
|
||||||
|
|
||||||
<!-- ======================================================================= -->
|
<!-- ======================================================================= -->
|
||||||
<h2 id="objc_arc">Automatic reference counting </h2>
|
<h2 id="objc_arc">Automatic reference counting </h2>
|
||||||
|
|
|
@ -211,6 +211,9 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> {
|
||||||
QualType ObjCConstantStringType;
|
QualType ObjCConstantStringType;
|
||||||
mutable RecordDecl *CFConstantStringTypeDecl;
|
mutable RecordDecl *CFConstantStringTypeDecl;
|
||||||
|
|
||||||
|
/// \brief The typedef declaration for the Objective-C "instancetype" type.
|
||||||
|
TypedefDecl *ObjCInstanceTypeDecl;
|
||||||
|
|
||||||
/// \brief The type for the C FILE type.
|
/// \brief The type for the C FILE type.
|
||||||
TypeDecl *FILEDecl;
|
TypeDecl *FILEDecl;
|
||||||
|
|
||||||
|
@ -884,6 +887,16 @@ public:
|
||||||
ObjCSelRedefinitionType = RedefType;
|
ObjCSelRedefinitionType = RedefType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the Objective-C "instancetype" type, if already known;
|
||||||
|
/// otherwise, returns a NULL type;
|
||||||
|
QualType getObjCInstanceType() {
|
||||||
|
return getTypeDeclType(getObjCInstanceTypeDecl());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the typedef declaration corresponding to the Objective-C
|
||||||
|
/// "instancetype" type.
|
||||||
|
TypedefDecl *getObjCInstanceTypeDecl();
|
||||||
|
|
||||||
/// \brief Set the type for the C FILE type.
|
/// \brief Set the type for the C FILE type.
|
||||||
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
|
void setFILEDecl(TypeDecl *FILEDecl) { this->FILEDecl = FILEDecl; }
|
||||||
|
|
||||||
|
|
|
@ -4696,9 +4696,12 @@ def warn_related_result_type_compatibility_class : Warning<
|
||||||
def warn_related_result_type_compatibility_protocol : Warning<
|
def warn_related_result_type_compatibility_protocol : Warning<
|
||||||
"protocol method is expected to return an instance of the implementing "
|
"protocol method is expected to return an instance of the implementing "
|
||||||
"class, but is declared to return %0">;
|
"class, but is declared to return %0">;
|
||||||
def note_related_result_type_overridden : Note<
|
def note_related_result_type_overridden_family : Note<
|
||||||
"overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
|
"overridden method is part of the '%select{|alloc|copy|init|mutableCopy|"
|
||||||
"new|autorelease|dealloc|release|retain|retainCount|self}0' method family">;
|
"new|autorelease|dealloc|finalize|release|retain|retainCount|self}0' method "
|
||||||
|
"family">;
|
||||||
|
def note_related_result_type_overridden : Note<
|
||||||
|
"overridden method returns an instance of its class type">;
|
||||||
def note_related_result_type_inferred : Note<
|
def note_related_result_type_inferred : Note<
|
||||||
"%select{class|instance}0 method %1 is assumed to return an instance of "
|
"%select{class|instance}0 method %1 is assumed to return an instance of "
|
||||||
"its receiver type (%2)">;
|
"its receiver type (%2)">;
|
||||||
|
|
|
@ -120,6 +120,9 @@ class Parser : public CodeCompletionHandler {
|
||||||
IdentifierInfo *Ident_vector;
|
IdentifierInfo *Ident_vector;
|
||||||
IdentifierInfo *Ident_pixel;
|
IdentifierInfo *Ident_pixel;
|
||||||
|
|
||||||
|
/// Objective-C contextual keywords.
|
||||||
|
mutable IdentifierInfo *Ident_instancetype;
|
||||||
|
|
||||||
/// \brief Identifier for "introduced".
|
/// \brief Identifier for "introduced".
|
||||||
IdentifierInfo *Ident_introduced;
|
IdentifierInfo *Ident_introduced;
|
||||||
|
|
||||||
|
|
|
@ -832,6 +832,10 @@ public:
|
||||||
|
|
||||||
TypeResult ActOnTypeName(Scope *S, Declarator &D);
|
TypeResult ActOnTypeName(Scope *S, Declarator &D);
|
||||||
|
|
||||||
|
/// \brief The parser has parsed the context-sensitive type 'instancetype'
|
||||||
|
/// in an Objective-C message declaration. Return the appropriate type.
|
||||||
|
ParsedType ActOnObjCInstanceType(SourceLocation Loc);
|
||||||
|
|
||||||
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
bool RequireCompleteType(SourceLocation Loc, QualType T,
|
||||||
const PartialDiagnostic &PD,
|
const PartialDiagnostic &PD,
|
||||||
std::pair<SourceLocation, PartialDiagnostic> Note);
|
std::pair<SourceLocation, PartialDiagnostic> Note);
|
||||||
|
|
|
@ -693,14 +693,17 @@ namespace clang {
|
||||||
PREDEF_DECL_INT_128_ID = 5,
|
PREDEF_DECL_INT_128_ID = 5,
|
||||||
|
|
||||||
/// \brief The unsigned 128-bit integer type.
|
/// \brief The unsigned 128-bit integer type.
|
||||||
PREDEF_DECL_UNSIGNED_INT_128_ID = 6
|
PREDEF_DECL_UNSIGNED_INT_128_ID = 6,
|
||||||
|
|
||||||
|
/// \brief The internal 'instancetype' typedef.
|
||||||
|
PREDEF_DECL_OBJC_INSTANCETYPE_ID = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief The number of declaration IDs that are predefined.
|
/// \brief The number of declaration IDs that are predefined.
|
||||||
///
|
///
|
||||||
/// For more information about predefined declarations, see the
|
/// For more information about predefined declarations, see the
|
||||||
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
|
/// \c PredefinedDeclIDs type and the PREDEF_DECL_*_ID constants.
|
||||||
const unsigned int NUM_PREDEF_DECL_IDS = 7;
|
const unsigned int NUM_PREDEF_DECL_IDS = 8;
|
||||||
|
|
||||||
/// \brief Record codes for each kind of declaration.
|
/// \brief Record codes for each kind of declaration.
|
||||||
///
|
///
|
||||||
|
|
|
@ -225,7 +225,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM,
|
||||||
GlobalNestedNameSpecifier(0),
|
GlobalNestedNameSpecifier(0),
|
||||||
Int128Decl(0), UInt128Decl(0),
|
Int128Decl(0), UInt128Decl(0),
|
||||||
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0),
|
ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0),
|
||||||
CFConstantStringTypeDecl(0),
|
CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0),
|
||||||
FILEDecl(0),
|
FILEDecl(0),
|
||||||
jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
|
jmp_bufDecl(0), sigjmp_bufDecl(0), BlockDescriptorType(0),
|
||||||
BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
|
BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0),
|
||||||
|
@ -3844,6 +3844,17 @@ ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const {
|
||||||
return getPointerType(getTagDeclType(T));
|
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:
|
// This returns true if a type has been typedefed to BOOL:
|
||||||
// typedef <type> BOOL;
|
// typedef <type> BOOL;
|
||||||
static bool isTypeTypedefedAsBOOL(QualType T) {
|
static bool isTypeTypedefedAsBOOL(QualType T) {
|
||||||
|
|
|
@ -599,6 +599,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) {
|
||||||
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
|
.Case("objc_arc", LangOpts.ObjCAutoRefCount)
|
||||||
.Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
|
.Case("objc_arc_weak", LangOpts.ObjCAutoRefCount &&
|
||||||
LangOpts.ObjCRuntimeHasWeak)
|
LangOpts.ObjCRuntimeHasWeak)
|
||||||
|
.Case("objc_instancetype", LangOpts.ObjC2)
|
||||||
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
|
.Case("objc_nonfragile_abi", LangOpts.ObjCNonFragileABI)
|
||||||
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
|
.Case("objc_weak_class", LangOpts.ObjCNonFragileABI)
|
||||||
.Case("ownership_holds", true)
|
.Case("ownership_holds", true)
|
||||||
|
|
|
@ -801,8 +801,16 @@ ParsedType Parser::ParseObjCTypeName(ObjCDeclSpec &DS,
|
||||||
ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
|
ParseTypeName(0, Declarator::ObjCPrototypeContext, &DS);
|
||||||
if (!TypeSpec.isInvalid())
|
if (!TypeSpec.isInvalid())
|
||||||
Ty = TypeSpec.get();
|
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))
|
if (Tok.is(tok::r_paren))
|
||||||
ConsumeParen();
|
ConsumeParen();
|
||||||
else if (Tok.getLocation() == TypeStartLoc) {
|
else if (Tok.getLocation() == TypeStartLoc) {
|
||||||
|
|
|
@ -443,6 +443,7 @@ void Parser::Initialize() {
|
||||||
ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
|
ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ident_instancetype = 0;
|
||||||
Ident_final = 0;
|
Ident_final = 0;
|
||||||
Ident_override = 0;
|
Ident_override = 0;
|
||||||
|
|
||||||
|
|
|
@ -148,8 +148,13 @@ bool Sema::CheckObjCMethodOverride(ObjCMethodDecl *NewMethod,
|
||||||
<< ResultTypeRange;
|
<< ResultTypeRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
Diag(Overridden->getLocation(), diag::note_related_result_type_overridden)
|
if (ObjCMethodFamily Family = Overridden->getMethodFamily())
|
||||||
<< 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;
|
return false;
|
||||||
|
@ -2261,16 +2266,22 @@ bool containsInvalidMethodImplAttribute(const AttrVec &A) {
|
||||||
return false;
|
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
|
/// \brief Check whether the declared result type of the given Objective-C
|
||||||
/// method declaration is compatible with the method's class.
|
/// method declaration is compatible with the method's class.
|
||||||
///
|
///
|
||||||
static bool
|
static ResultTypeCompatibilityKind
|
||||||
CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
|
CheckRelatedResultTypeCompatibility(Sema &S, ObjCMethodDecl *Method,
|
||||||
ObjCInterfaceDecl *CurrentClass) {
|
ObjCInterfaceDecl *CurrentClass) {
|
||||||
QualType ResultType = Method->getResultType();
|
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
|
// 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 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
|
// - it is id or qualified id, or
|
||||||
if (ResultObjectType->isObjCIdType() ||
|
if (ResultObjectType->isObjCIdType() ||
|
||||||
ResultObjectType->isObjCQualifiedIdType())
|
ResultObjectType->isObjCQualifiedIdType())
|
||||||
return false;
|
return RTC_Compatible;
|
||||||
|
|
||||||
if (CurrentClass) {
|
if (CurrentClass) {
|
||||||
if (ObjCInterfaceDecl *ResultClass
|
if (ObjCInterfaceDecl *ResultClass
|
||||||
= ResultObjectType->getInterfaceDecl()) {
|
= ResultObjectType->getInterfaceDecl()) {
|
||||||
// - it is the same as the method's class type, or
|
// - it is the same as the method's class type, or
|
||||||
if (CurrentClass == ResultClass)
|
if (CurrentClass == ResultClass)
|
||||||
return false;
|
return RTC_Compatible;
|
||||||
|
|
||||||
// - it is a superclass of the method's class type
|
// - it is a superclass of the method's class type
|
||||||
if (ResultClass->isSuperClassOf(CurrentClass))
|
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 {
|
namespace {
|
||||||
|
@ -2457,6 +2472,7 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
Decl *ClassDecl = cast<Decl>(OCD);
|
Decl *ClassDecl = cast<Decl>(OCD);
|
||||||
QualType resultDeclType;
|
QualType resultDeclType;
|
||||||
|
|
||||||
|
bool HasRelatedResultType = false;
|
||||||
TypeSourceInfo *ResultTInfo = 0;
|
TypeSourceInfo *ResultTInfo = 0;
|
||||||
if (ReturnType) {
|
if (ReturnType) {
|
||||||
resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
|
resultDeclType = GetTypeFromParser(ReturnType, &ResultTInfo);
|
||||||
|
@ -2468,6 +2484,8 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
<< 0 << resultDeclType;
|
<< 0 << resultDeclType;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
|
||||||
} else { // get the type for "id".
|
} else { // get the type for "id".
|
||||||
resultDeclType = Context.getObjCIdType();
|
resultDeclType = Context.getObjCIdType();
|
||||||
Diag(MethodLoc, diag::warn_missing_method_return_type)
|
Diag(MethodLoc, diag::warn_missing_method_return_type)
|
||||||
|
@ -2484,7 +2502,7 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
MethodDeclKind == tok::objc_optional
|
MethodDeclKind == tok::objc_optional
|
||||||
? ObjCMethodDecl::Optional
|
? ObjCMethodDecl::Optional
|
||||||
: ObjCMethodDecl::Required,
|
: ObjCMethodDecl::Required,
|
||||||
false);
|
HasRelatedResultType);
|
||||||
|
|
||||||
SmallVector<ParmVarDecl*, 16> Params;
|
SmallVector<ParmVarDecl*, 16> Params;
|
||||||
|
|
||||||
|
@ -2604,9 +2622,8 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
CurrentClass = CatImpl->getClassInterface();
|
CurrentClass = CatImpl->getClassInterface();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isRelatedResultTypeCompatible =
|
ResultTypeCompatibilityKind RTC
|
||||||
(getLangOptions().ObjCInferRelatedResultType &&
|
= CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass);
|
||||||
!CheckRelatedResultTypeCompatibility(*this, ObjCMethod, CurrentClass));
|
|
||||||
|
|
||||||
// Search for overridden methods and merge information down from them.
|
// Search for overridden methods and merge information down from them.
|
||||||
OverrideSearch overrides(*this, ObjCMethod);
|
OverrideSearch overrides(*this, ObjCMethod);
|
||||||
|
@ -2615,7 +2632,7 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
ObjCMethodDecl *overridden = *i;
|
ObjCMethodDecl *overridden = *i;
|
||||||
|
|
||||||
// Propagate down the 'related result type' bit from overridden methods.
|
// Propagate down the 'related result type' bit from overridden methods.
|
||||||
if (isRelatedResultTypeCompatible && overridden->hasRelatedResultType())
|
if (RTC != RTC_Incompatible && overridden->hasRelatedResultType())
|
||||||
ObjCMethod->SetRelatedResultType();
|
ObjCMethod->SetRelatedResultType();
|
||||||
|
|
||||||
// Then merge the declarations.
|
// Then merge the declarations.
|
||||||
|
@ -2633,8 +2650,10 @@ Decl *Sema::ActOnMethodDeclaration(
|
||||||
if (getLangOptions().ObjCAutoRefCount)
|
if (getLangOptions().ObjCAutoRefCount)
|
||||||
ARCError = CheckARCMethodDecl(*this, ObjCMethod);
|
ARCError = CheckARCMethodDecl(*this, ObjCMethod);
|
||||||
|
|
||||||
if (!ARCError && isRelatedResultTypeCompatible &&
|
// Infer the related result type when possible.
|
||||||
!ObjCMethod->hasRelatedResultType()) {
|
if (!ARCError && RTC == RTC_Compatible &&
|
||||||
|
!ObjCMethod->hasRelatedResultType() &&
|
||||||
|
LangOpts.ObjCInferRelatedResultType) {
|
||||||
bool InferRelatedResultType = false;
|
bool InferRelatedResultType = false;
|
||||||
switch (ObjCMethod->getMethodFamily()) {
|
switch (ObjCMethod->getMethodFamily()) {
|
||||||
case OMF_None:
|
case OMF_None:
|
||||||
|
|
|
@ -328,6 +328,10 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) {
|
||||||
MsgSend->getType()))
|
MsgSend->getType()))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!Context.hasSameUnqualifiedType(Method->getResultType(),
|
||||||
|
Context.getObjCInstanceType()))
|
||||||
|
return;
|
||||||
|
|
||||||
Diag(Method->getLocation(), diag::note_related_result_type_inferred)
|
Diag(Method->getLocation(), diag::note_related_result_type_inferred)
|
||||||
<< Method->isInstanceMethod() << Method->getSelector()
|
<< Method->isInstanceMethod() << Method->getSelector()
|
||||||
<< MsgSend->getType();
|
<< MsgSend->getType();
|
||||||
|
|
|
@ -3053,6 +3053,13 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
|
||||||
return CreateParsedType(T, TInfo);
|
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
|
// Type Attribute Processing
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -4126,6 +4126,10 @@ Decl *ASTReader::GetDecl(DeclID ID) {
|
||||||
case PREDEF_DECL_UNSIGNED_INT_128_ID:
|
case PREDEF_DECL_UNSIGNED_INT_128_ID:
|
||||||
assert(Context && "No context available?");
|
assert(Context && "No context available?");
|
||||||
return Context->getUInt128Decl();
|
return Context->getUInt128Decl();
|
||||||
|
|
||||||
|
case PREDEF_DECL_OBJC_INSTANCETYPE_ID:
|
||||||
|
assert(Context && "No context available?");
|
||||||
|
return Context->getObjCInstanceTypeDecl();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -2880,6 +2880,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls,
|
||||||
DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
|
DeclIDs[Context.Int128Decl] = PREDEF_DECL_INT_128_ID;
|
||||||
if (Context.UInt128Decl)
|
if (Context.UInt128Decl)
|
||||||
DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
|
DeclIDs[Context.UInt128Decl] = PREDEF_DECL_UNSIGNED_INT_128_ID;
|
||||||
|
if (Context.ObjCInstanceTypeDecl)
|
||||||
|
DeclIDs[Context.ObjCInstanceTypeDecl] = PREDEF_DECL_OBJC_INSTANCETYPE_ID;
|
||||||
|
|
||||||
if (!Chain) {
|
if (!Chain) {
|
||||||
// Make sure that we emit IdentifierInfos (and any attached
|
// Make sure that we emit IdentifierInfos (and any attached
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
@interface TestPCH
|
@interface TestPCH
|
||||||
+ alloc;
|
+ alloc;
|
||||||
- (id)init;
|
- (instancetype)instMethod;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@class TestForwardClassDecl;
|
@class TestForwardClassDecl;
|
||||||
|
|
|
@ -12,5 +12,5 @@ void func() {
|
||||||
// AliasForTestPCH *zz;
|
// AliasForTestPCH *zz;
|
||||||
|
|
||||||
xx = [TestPCH alloc];
|
xx = [TestPCH alloc];
|
||||||
[xx init];
|
[xx instMethod];
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,190 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -verify %s
|
||||||
|
|
||||||
|
#if !__has_feature(objc_instancetype)
|
||||||
|
# error Missing 'instancetype' feature macro.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@interface Root
|
||||||
|
+ (instancetype)alloc;
|
||||||
|
- (instancetype)init; // expected-note{{overridden method is part of the 'init' method family}}
|
||||||
|
- (instancetype)self;
|
||||||
|
- (Class)class;
|
||||||
|
|
||||||
|
@property (assign) Root *selfProp;
|
||||||
|
- (instancetype)selfProp;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol Proto1
|
||||||
|
@optional
|
||||||
|
- (instancetype)methodInProto1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol Proto2
|
||||||
|
@optional
|
||||||
|
- (instancetype)methodInProto2; // expected-note{{overridden method returns an instance of its class type}}
|
||||||
|
- (instancetype)otherMethodInProto2; // expected-note{{overridden method returns an instance of its class type}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface Subclass1 : Root
|
||||||
|
- (instancetype)initSubclass1;
|
||||||
|
- (void)methodOnSubclass1;
|
||||||
|
+ (instancetype)allocSubclass1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface Subclass2 : Root
|
||||||
|
- (instancetype)initSubclass2;
|
||||||
|
- (void)methodOnSubclass2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Sanity check: the basic initialization pattern.
|
||||||
|
void test_instancetype_alloc_init_simple() {
|
||||||
|
Root *r1 = [[Root alloc] init];
|
||||||
|
Subclass1 *sc1 = [[Subclass1 alloc] init];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that message sends to instancetype methods have the right type.
|
||||||
|
void test_instancetype_narrow_method_search() {
|
||||||
|
// instancetype on class methods
|
||||||
|
Subclass1 *sc1 = [[Subclass1 alloc] initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
|
||||||
|
Subclass2 *sc2 = [[Subclass2 alloc] initSubclass2]; // okay
|
||||||
|
|
||||||
|
// instancetype on instance methods
|
||||||
|
[[[Subclass1 alloc] init] methodOnSubclass2]; // expected-warning{{'Subclass1' may not respond to 'methodOnSubclass2'}}
|
||||||
|
[[[Subclass2 alloc] init] methodOnSubclass2];
|
||||||
|
|
||||||
|
// instancetype on class methods using protocols
|
||||||
|
typedef Subclass1<Proto1> SC1Proto1;
|
||||||
|
typedef Subclass1<Proto2> SC1Proto2;
|
||||||
|
[[SC1Proto1 alloc] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
|
||||||
|
[[SC1Proto2 alloc] methodInProto2];
|
||||||
|
|
||||||
|
// instancetype on instance methods
|
||||||
|
Subclass1<Proto1> *sc1proto1 = 0;
|
||||||
|
[[sc1proto1 self] methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
|
||||||
|
Subclass1<Proto2> *sc1proto2 = 0;
|
||||||
|
[[sc1proto2 self] methodInProto2];
|
||||||
|
|
||||||
|
// Exact type checks
|
||||||
|
typeof([[Subclass1 alloc] init]) *ptr1 = (Subclass1 **)0;
|
||||||
|
typeof([[Subclass2 alloc] init]) *ptr2 = (Subclass2 **)0;
|
||||||
|
|
||||||
|
// Message sends to Class.
|
||||||
|
Subclass1<Proto1> *sc1proto1_2 = [[[sc1proto1 class] alloc] init];
|
||||||
|
|
||||||
|
// Property access
|
||||||
|
[sc1proto1.self methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
|
||||||
|
[sc1proto2.self methodInProto2];
|
||||||
|
[Subclass1.alloc initSubclass2]; // expected-warning{{'Subclass1' may not respond to 'initSubclass2'}}
|
||||||
|
[Subclass2.alloc initSubclass2];
|
||||||
|
|
||||||
|
[sc1proto1.selfProp methodInProto2]; // expected-warning{{method '-methodInProto2' not found (return type defaults to 'id')}}
|
||||||
|
[sc1proto2.selfProp methodInProto2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test that message sends to super methods have the right type.
|
||||||
|
@interface Subsubclass1 : Subclass1
|
||||||
|
- (instancetype)initSubclass1;
|
||||||
|
+ (instancetype)allocSubclass1;
|
||||||
|
|
||||||
|
- (void)onlyInSubsubclass1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Subsubclass1
|
||||||
|
- (instancetype)initSubclass1 {
|
||||||
|
// Check based on method search.
|
||||||
|
[[super initSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
|
||||||
|
[super.initSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
|
||||||
|
|
||||||
|
self = [super init]; // common pattern
|
||||||
|
|
||||||
|
// Exact type check.
|
||||||
|
typeof([super initSubclass1]) *ptr1 = (Subsubclass1**)0;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ (instancetype)allocSubclass1 {
|
||||||
|
// Check based on method search.
|
||||||
|
[[super allocSubclass1] methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
|
||||||
|
|
||||||
|
// The ASTs don't model super property accesses well enough to get this right
|
||||||
|
[super.allocSubclass1 methodOnSubclass2]; // expected-warning{{'Subsubclass1' may not respond to 'methodOnSubclass2'}}
|
||||||
|
|
||||||
|
// Exact type check.
|
||||||
|
typeof([super allocSubclass1]) *ptr1 = (Subsubclass1**)0;
|
||||||
|
|
||||||
|
return [super allocSubclass1];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)onlyInSubsubclass1 {}
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Check compatibility rules for inheritance of related return types.
|
||||||
|
@class Subclass4;
|
||||||
|
|
||||||
|
@interface Subclass3 <Proto1, Proto2>
|
||||||
|
- (Subclass3 *)methodInProto1;
|
||||||
|
- (Subclass4 *)methodInProto2; // expected-warning{{method is expected to return an instance of its class type 'Subclass3', but is declared to return 'Subclass4 *'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface Subclass4 : Root
|
||||||
|
+ (Subclass4 *)alloc; // okay
|
||||||
|
- (Subclass3 *)init; // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
|
||||||
|
- (id)self; // expected-note{{overridden method is part of the 'self' method family}}
|
||||||
|
- (instancetype)initOther;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol Proto3 <Proto1, Proto2>
|
||||||
|
@optional
|
||||||
|
- (id)methodInProto1;
|
||||||
|
- (Subclass1 *)methodInProto2;
|
||||||
|
- (int)otherMethodInProto2; // expected-warning{{protocol method is expected to return an instance of the implementing class, but is declared to return 'int'}}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation Subclass4
|
||||||
|
+ (id)alloc {
|
||||||
|
return self; // expected-warning{{incompatible pointer types returning 'Class' from a function with result type 'Subclass4 *'}}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Subclass3 *)init { return 0; } // don't complain: we lost the related return type
|
||||||
|
|
||||||
|
- (Subclass3 *)self { return 0; } // expected-warning{{method is expected to return an instance of its class type 'Subclass4', but is declared to return 'Subclass3 *'}}
|
||||||
|
|
||||||
|
- (Subclass4 *)initOther { return 0; }
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
// Check that inherited related return types influence the types of
|
||||||
|
// message sends.
|
||||||
|
void test_instancetype_inherited() {
|
||||||
|
[[Subclass4 alloc] initSubclass1]; // expected-warning{{'Subclass4' may not respond to 'initSubclass1'}}
|
||||||
|
[[Subclass4 alloc] initOther];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that related return types tighten up the semantics of
|
||||||
|
// Objective-C method implementations.
|
||||||
|
@implementation Subclass2
|
||||||
|
- (instancetype)initSubclass2 {
|
||||||
|
Subclass1 *sc1 = [[Subclass1 alloc] init];
|
||||||
|
return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
|
||||||
|
}
|
||||||
|
- (void)methodOnSubclass2 {}
|
||||||
|
- (id)self {
|
||||||
|
Subclass1 *sc1 = [[Subclass1 alloc] init];
|
||||||
|
return sc1; // expected-warning{{incompatible pointer types returning 'Subclass1 *' from a function with result type 'Subclass2 *'}}
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyClass : Root
|
||||||
|
+ (int)myClassMethod;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyClass
|
||||||
|
+ (int)myClassMethod { return 0; }
|
||||||
|
|
||||||
|
- (void)blah {
|
||||||
|
int i = [[MyClass self] myClassMethod];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
Loading…
Reference in New Issue