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

Reply via email to