vsapsai created this revision.
vsapsai added reviewers: erik.pilkington, ahatanak.
Herald added subscribers: ributzka, jfb, dexonsmith, jkorous.
Herald added a project: clang.
When a type parameter is used with some protocols, we should keep these
protocols both when the generic type is parameterized and not
parameterized.
rdar://problem/58773533
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D76264
Files:
clang/lib/AST/Type.cpp
clang/test/SemaObjC/parameterized_classes_subst.m
Index: clang/test/SemaObjC/parameterized_classes_subst.m
===================================================================
--- clang/test/SemaObjC/parameterized_classes_subst.m
+++ clang/test/SemaObjC/parameterized_classes_subst.m
@@ -467,3 +467,34 @@
- (void)mapUsingBlock2:(id)block { // expected-warning{{conflicting parameter types in implementation}}
}
@end
+
+// --------------------------------------------------------------------------
+// Protocols on type parameter in unspecialized context.
+// --------------------------------------------------------------------------
+@protocol ContainerItem
+@property (nonatomic) int protocolProp;
+@end
+
+@interface TestUnbounded<T> : NSObject
+@property (nonatomic, retain) T<ContainerItem> element;
+@end
+@implementation TestUnbounded
+- (void)testProtocolOnTypeParameter {
+ (void)[self element].protocolProp;
+}
+@end
+
+@interface TestBounded<T : id<ContainerItem>> : NSObject
+@property (nonatomic, retain) T element;
+@end
+@implementation TestBounded
+- (void)testProtocolOnTypeParameter {
+ (void)[self element].protocolProp;
+}
+@end
+
+void accessNonParameterizedGenerics(
+ TestUnbounded *protocolOnProperty, TestBounded *protocolOnTypeBound) {
+ (void)[protocolOnProperty element].protocolProp;
+ (void)[protocolOnTypeBound element].protocolProp;
+}
Index: clang/lib/AST/Type.cpp
===================================================================
--- clang/lib/AST/Type.cpp
+++ clang/lib/AST/Type.cpp
@@ -1195,51 +1195,53 @@
QualType VisitObjCTypeParamType(const ObjCTypeParamType *OTPTy) {
// Replace an Objective-C type parameter reference with the corresponding
// type argument.
+ QualType newType;
ObjCTypeParamDecl *typeParam = OTPTy->getDecl();
// If we have type arguments, use them.
if (!TypeArgs.empty()) {
- QualType argType = TypeArgs[typeParam->getIndex()];
- if (OTPTy->qual_empty())
- return argType;
-
- // Apply protocol lists if exists.
- bool hasError;
- SmallVector<ObjCProtocolDecl *, 8> protocolsVec;
- protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end());
- ArrayRef<ObjCProtocolDecl *> protocolsToApply = protocolsVec;
- return Ctx.applyObjCProtocolQualifiers(
- argType, protocolsToApply, hasError, true/*allowOnPointerType*/);
+ newType = TypeArgs[typeParam->getIndex()];
+ } else {
+ switch (SubstContext) {
+ case ObjCSubstitutionContext::Ordinary:
+ case ObjCSubstitutionContext::Parameter:
+ case ObjCSubstitutionContext::Superclass:
+ // Substitute the bound.
+ newType = typeParam->getUnderlyingType();
+ break;
+
+ case ObjCSubstitutionContext::Result:
+ case ObjCSubstitutionContext::Property: {
+ // Substitute the __kindof form of the underlying type.
+ const auto *objPtr =
+ typeParam->getUnderlyingType()->castAs<ObjCObjectPointerType>();
+
+ // __kindof types, id, and Class don't need an additional
+ // __kindof.
+ if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType()) {
+ newType = typeParam->getUnderlyingType();
+ } else {
+ // Add __kindof.
+ const auto *obj = objPtr->getObjectType();
+ QualType resultTy = Ctx.getObjCObjectType(obj->getBaseType(),
+ obj->getTypeArgsAsWritten(),
+ obj->getProtocols(),
+ /*isKindOf=*/true);
+
+ // Rebuild object pointer type.
+ newType = Ctx.getObjCObjectPointerType(resultTy);
+ }
+ break;
+ }
+ }
}
- switch (SubstContext) {
- case ObjCSubstitutionContext::Ordinary:
- case ObjCSubstitutionContext::Parameter:
- case ObjCSubstitutionContext::Superclass:
- // Substitute the bound.
- return typeParam->getUnderlyingType();
-
- case ObjCSubstitutionContext::Result:
- case ObjCSubstitutionContext::Property: {
- // Substitute the __kindof form of the underlying type.
- const auto *objPtr =
- typeParam->getUnderlyingType()->castAs<ObjCObjectPointerType>();
-
- // __kindof types, id, and Class don't need an additional
- // __kindof.
- if (objPtr->isKindOfType() || objPtr->isObjCIdOrClassType())
- return typeParam->getUnderlyingType();
-
- // Add __kindof.
- const auto *obj = objPtr->getObjectType();
- QualType resultTy = Ctx.getObjCObjectType(
- obj->getBaseType(), obj->getTypeArgsAsWritten(), obj->getProtocols(),
- /*isKindOf=*/true);
-
- // Rebuild object pointer type.
- return Ctx.getObjCObjectPointerType(resultTy);
- }
- }
- llvm_unreachable("Unexpected ObjCSubstitutionContext!");
+ if (OTPTy->qual_empty())
+ return newType;
+
+ // Apply protocol list if exists.
+ bool hasError;
+ return Ctx.applyObjCProtocolQualifiers(
+ newType, OTPTy->getProtocols(), hasError, /*allowOnPointerType=*/true);
}
QualType VisitFunctionType(const FunctionType *funcType) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits