diff options
author | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:57:53 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2015-07-07 03:57:53 +0000 |
commit | a6620f3825bfe120c96c1bac7d62e0dcd34f33a0 (patch) | |
tree | 8f7cadb82868a652c2e93097f4213b020004cda5 /lib/CodeGen/CGObjC.cpp | |
parent | 06714fc31ec11e45aa8e395fa305bcce2da0d3c2 (diff) |
Substitute type arguments into uses of Objective-C interface members.
When messaging a method that was defined in an Objective-C class (or
category or extension thereof) that has type parameters, substitute
the type arguments for those type parameters. Similarly, substitute
into property accesses, instance variables, and other references.
This includes general infrastructure for substituting the type
arguments associated with an ObjCObject(Pointer)Type into a type
referenced within a particular context, handling all of the
substitutions required to deal with (e.g.) inheritance involving
parameterized classes. In cases where no type arguments are available
(e.g., because we're messaging via some unspecialized type, id, etc.),
we substitute in the type bounds for the type parameters instead.
Example:
@interface NSSet<T : id<NSCopying>> : NSObject <NSCopying>
- (T)firstObject;
@end
void f(NSSet<NSString *> *stringSet, NSSet *anySet) {
[stringSet firstObject]; // produces NSString*
[anySet firstObject]; // produces id<NSCopying> (the bound)
}
When substituting for the type parameters given an unspecialized
context (i.e., no specific type arguments were given), substituting
the type bounds unconditionally produces type signatures that are too
strong compared to the pre-generics signatures. Instead, use the
following rule:
- In covariant positions, such as method return types, replace type
parameters with “id” or “Class” (the latter only when the type
parameter bound is “Class” or qualified class, e.g,
“Class<NSCopying>”)
- In other positions (e.g., parameter types), replace type
parameters with their type bounds.
- When a specialized Objective-C object or object pointer type
contains a type parameter in its type arguments (e.g.,
NSArray<T>*, but not NSArray<NSString *> *), replace the entire
object/object pointer type with its unspecialized version (e.g.,
NSArray *).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@241543 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGObjC.cpp')
-rw-r--r-- | lib/CodeGen/CGObjC.cpp | 34 |
1 files changed, 16 insertions, 18 deletions
diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 747326e4c5..4178d48f25 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -31,10 +31,9 @@ using namespace CodeGen; typedef llvm::PointerIntPair<llvm::Value*,1,bool> TryEmitResult; static TryEmitResult tryEmitARCRetainScalarExpr(CodeGenFunction &CGF, const Expr *e); -static RValue AdjustRelatedResultType(CodeGenFunction &CGF, - QualType ET, - const ObjCMethodDecl *Method, - RValue Result); +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, + QualType ET, + RValue Result); /// Given the address of a variable of pointer type, find the correct /// null to store into it. @@ -248,23 +247,22 @@ llvm::Value *CodeGenFunction::EmitObjCProtocolExpr(const ObjCProtocolExpr *E) { return CGM.getObjCRuntime().GenerateProtocolRef(*this, 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, - QualType ExpT, - const ObjCMethodDecl *Method, - RValue Result) { - if (!Method) +/// \brief Adjust the type of an Objective-C object that doesn't match up due +/// to type erasure at various points, e.g., related result types or the use +/// of parameterized classes. +static RValue AdjustObjCObjectType(CodeGenFunction &CGF, QualType ExpT, + RValue Result) { + if (!ExpT->isObjCRetainableType()) return Result; - if (!Method->hasRelatedResultType() || - CGF.getContext().hasSameType(ExpT, Method->getReturnType()) || - !Result.isScalar()) + // If the converted types are the same, we're done. + llvm::Type *ExpLLVMTy = CGF.ConvertType(ExpT); + if (ExpLLVMTy == Result.getScalarVal()->getType()) return Result; - - // We have applied a related result type. Cast the rvalue appropriately. + + // We have applied a substitution. Cast the rvalue appropriately. return RValue::get(CGF.Builder.CreateBitCast(Result.getScalarVal(), - CGF.ConvertType(ExpT))); + ExpLLVMTy)); } /// Decide whether to extend the lifetime of the receiver of a @@ -449,7 +447,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, Builder.CreateStore(newSelf, selfAddr); } - return AdjustRelatedResultType(*this, E->getType(), method, result); + return AdjustObjCObjectType(*this, E->getType(), result); } namespace { |