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 cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits