summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExprObjC.cpp
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2015-07-07 03:57:53 +0000
committerDouglas Gregor <dgregor@apple.com>2015-07-07 03:57:53 +0000
commite83b95641f911e44c8c092bc0eef7743df0cd73d (patch)
tree88c82874e35786d877ab648a3d792dc62bcfda68 /clang/lib/Sema/SemaExprObjC.cpp
parente9d95f1ecc98ced831cace8b4b78cb7cc380f4aa (diff)
downloadbcm5719-llvm-e83b95641f911e44c8c092bc0eef7743df0cd73d.tar.gz
bcm5719-llvm-e83b95641f911e44c8c092bc0eef7743df0cd73d.zip
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 *). llvm-svn: 241543
Diffstat (limited to 'clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp77
1 files changed, 49 insertions, 28 deletions
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp
index 7280f588c8b..51ab68a8ab1 100644
--- a/clang/lib/Sema/SemaExprObjC.cpp
+++ b/clang/lib/Sema/SemaExprObjC.cpp
@@ -1281,7 +1281,7 @@ static QualType getBaseMessageSendResultType(Sema &S,
bool isSuperMessage) {
assert(Method && "Must have a method");
if (!Method->hasRelatedResultType())
- return Method->getSendResultType();
+ return Method->getSendResultType(ReceiverType);
ASTContext &Context = S.Context;
@@ -1289,7 +1289,8 @@ static QualType getBaseMessageSendResultType(Sema &S,
// result type to the returned result.
auto transferNullability = [&](QualType type) -> QualType {
// If the method's result type has nullability, extract it.
- if (auto nullability = Method->getSendResultType()->getNullability(Context)){
+ if (auto nullability = Method->getSendResultType(ReceiverType)
+ ->getNullability(Context)){
// Strip off any outer nullability sugar from the provided type.
(void)AttributedType::stripOuterNullability(type);
@@ -1308,7 +1309,8 @@ static QualType getBaseMessageSendResultType(Sema &S,
// was a class message send, T is the declared return type of the method
// found
if (Method->isInstanceMethod() && isClassMessage)
- return stripObjCInstanceType(Context, Method->getSendResultType());
+ return stripObjCInstanceType(Context,
+ Method->getSendResultType(ReceiverType));
// - if the receiver is super, T is a pointer to the class of the
// enclosing method definition
@@ -1322,14 +1324,14 @@ static QualType getBaseMessageSendResultType(Sema &S,
}
// - if the receiver is the name of a class U, T is a pointer to U
- if (ReceiverType->getAs<ObjCInterfaceType>() ||
- ReceiverType->isObjCQualifiedInterfaceType())
+ if (ReceiverType->getAsObjCInterfaceType())
return transferNullability(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 stripObjCInstanceType(Context, Method->getSendResultType());
+ return stripObjCInstanceType(Context,
+ Method->getSendResultType(ReceiverType));
// - if the receiver is id, qualified id, Class, or qualified Class, T
// is the receiver type, otherwise
@@ -1592,6 +1594,10 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
return false;
}
+ // Compute the set of type arguments to be substituted into each parameter
+ // type.
+ Optional<ArrayRef<QualType>> typeArgs
+ = ReceiverType->getObjCSubstitutions(Method->getDeclContext());
bool IsError = false;
for (unsigned i = 0; i < NumNamedArgs; i++) {
// We can't do any type-checking on a type-dependent argument.
@@ -1625,18 +1631,37 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType,
continue;
}
+ QualType origParamType = param->getType();
+ QualType paramType = param->getType();
+ if (typeArgs)
+ paramType = paramType.substObjCTypeArgs(
+ Context,
+ *typeArgs,
+ ObjCSubstitutionContext::Parameter);
+
if (RequireCompleteType(argExpr->getSourceRange().getBegin(),
- param->getType(),
+ paramType,
diag::err_call_incomplete_argument, argExpr))
return true;
- InitializedEntity Entity = InitializedEntity::InitializeParameter(Context,
- param);
+ InitializedEntity Entity
+ = InitializedEntity::InitializeParameter(Context, param, paramType);
ExprResult ArgE = PerformCopyInitialization(Entity, SourceLocation(), argExpr);
if (ArgE.isInvalid())
IsError = true;
- else
+ else {
Args[i] = ArgE.getAs<Expr>();
+
+ // If we are type-erasing a block to a block-compatible
+ // Objective-C pointer type, we may need to extend the lifetime
+ // of the block object.
+ if (typeArgs && Args[i]->isRValue() && paramType->isBlockPointerType() &&
+ origParamType->isBlockCompatibleObjCPointerType(Context)) {
+ ExprResult arg = Args[i];
+ maybeExtendBlockObject(arg);
+ Args[i] = arg.get();
+ }
+ }
}
// Promote additional arguments to variadic methods.
@@ -1904,27 +1929,24 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr,
receiverNameLoc);
- bool IsSuper = false;
+ QualType SuperType;
if (!IFace) {
// 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(receiverNameLoc)) {
- if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) {
+ if (auto classDecl = CurMethod->getClassInterface()) {
+ SuperType = QualType(classDecl->getSuperClassType(), 0);
if (CurMethod->isInstanceMethod()) {
- ObjCInterfaceDecl *Super = Class->getSuperClass();
- if (!Super) {
+ if (SuperType.isNull()) {
// The current class does not have a superclass.
Diag(receiverNameLoc, diag::error_root_class_cannot_use_super)
- << Class->getIdentifier();
+ << CurMethod->getClassInterface()->getIdentifier();
return ExprError();
}
- QualType T = Context.getObjCInterfaceType(Super);
- T = Context.getObjCObjectPointerType(T);
+ QualType T = Context.getObjCObjectPointerType(SuperType);
- return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(),
+ return HandleExprPropertyRefExpr(T->castAs<ObjCObjectPointerType>(),
/*BaseExpr*/nullptr,
SourceLocation()/*OpLoc*/,
&propertyName,
@@ -1934,7 +1956,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
// Otherwise, if this is a class method, try dispatching to our
// superclass.
- IFace = Class->getSuperClass();
+ IFace = CurMethod->getClassInterface()->getSuperClass();
}
}
}
@@ -1964,7 +1986,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
// Look for the matching setter, in case it is needed.
Selector SetterSel =
SelectorTable::constructSetterSelector(PP.getIdentifierTable(),
- PP.getSelectorTable(),
+ PP.getSelectorTable(),
&propertyName);
ObjCMethodDecl *Setter = IFace->lookupClassMethod(SetterSel);
@@ -1981,11 +2003,11 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
return ExprError();
if (Getter || Setter) {
- if (IsSuper)
+ if (!SuperType.isNull())
return new (Context)
ObjCPropertyRefExpr(Getter, Setter, Context.PseudoObjectTy, VK_LValue,
OK_ObjCProperty, propertyNameLoc, receiverNameLoc,
- Context.getObjCInterfaceType(IFace));
+ SuperType);
return new (Context) ObjCPropertyRefExpr(
Getter, Setter, Context.PseudoObjectTy, VK_LValue, OK_ObjCProperty,
@@ -2132,8 +2154,8 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
return ExprError();
}
- ObjCInterfaceDecl *Super = Class->getSuperClass();
- if (!Super) {
+ QualType SuperTy(Class->getSuperClassType(), 0);
+ if (SuperTy.isNull()) {
// The current class does not have a superclass.
Diag(SuperLoc, diag::error_root_class_cannot_use_super)
<< Class->getIdentifier();
@@ -2148,7 +2170,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
if (Method->isInstanceMethod()) {
// Since we are in an instance method, this is an instance
// message to the superclass instance.
- QualType SuperTy = Context.getObjCInterfaceType(Super);
SuperTy = Context.getObjCObjectPointerType(SuperTy);
return BuildInstanceMessage(nullptr, SuperTy, SuperLoc,
Sel, /*Method=*/nullptr,
@@ -2158,7 +2179,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
// Since we are in a class method, this is a class message to
// the superclass.
return BuildClassMessage(/*ReceiverTypeInfo=*/nullptr,
- Context.getObjCInterfaceType(Super),
+ SuperTy,
SuperLoc, Sel, /*Method=*/nullptr,
LBracLoc, SelectorLocs, RBracLoc, Args);
}
OpenPOWER on IntegriCloud