diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/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 protocolsVec; - protocolsVec.append(OTPTy->qual_begin(), OTPTy->qual_end()); - ArrayRef 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(); + + // __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(); - - // __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) { diff --git a/clang/test/SemaObjC/parameterized_classes_subst.m b/clang/test/SemaObjC/parameterized_classes_subst.m --- a/clang/test/SemaObjC/parameterized_classes_subst.m +++ b/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 : NSObject +@property (nonatomic, retain) T element; +@end +@implementation TestUnbounded +- (void)testProtocolOnTypeParameter { + (void)[self element].protocolProp; +} +@end + +@interface TestBounded> : 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; +}