Fix <rdar://problem/6619539> incompatible pointer types sending 'XCElementSpacer *', expected 'XCElement *' (not handling protocol signatures correctly?).
- Reworked ASTContext::canAssignObjCInterfaces().
- Added ObjCProtocolDecl::lookupProtocolNamed().
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65773 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclObjC.h b/include/clang/AST/DeclObjC.h
index 33662b2..9bb3278 100644
--- a/include/clang/AST/DeclObjC.h
+++ b/include/clang/AST/DeclObjC.h
@@ -596,6 +596,8 @@
ReferencedProtocols.set(List, Num, C);
}
+ ObjCProtocolDecl *lookupProtocolNamed(IdentifierInfo *PName);
+
// Lookup a method. First, we search locally. If a method isn't
// found, we search referenced protocols and class categories.
ObjCMethodDecl *lookupInstanceMethod(Selector Sel);
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 749655d..2100a66 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2501,33 +2501,29 @@
// Finally, we must have two protocol-qualified interfaces.
const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS);
const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS);
- ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin();
- ObjCQualifiedInterfaceType::qual_iterator LHSPE = LHSP->qual_end();
- ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin();
- ObjCQualifiedInterfaceType::qual_iterator RHSPE = RHSP->qual_end();
- // All protocols in LHS must have a presence in RHS. Since the protocol lists
- // are both sorted alphabetically and have no duplicates, we can scan RHS and
- // LHS in a single parallel scan until we run out of elements in LHS.
- assert(LHSPI != LHSPE && "Empty LHS protocol list?");
- ObjCProtocolDecl *LHSProto = *LHSPI;
+ // All LHS protocols must have a presence on the RHS.
+ assert(LHSP->qual_begin() != LHSP->qual_end() && "Empty LHS protocol list?");
- while (RHSPI != RHSPE) {
- ObjCProtocolDecl *RHSProto = *RHSPI++;
- // If the RHS has a protocol that the LHS doesn't, ignore it.
- if (RHSProto != LHSProto)
- continue;
-
- // Otherwise, the RHS does have this element.
- ++LHSPI;
- if (LHSPI == LHSPE)
- return true; // All protocols in LHS exist in RHS.
-
- LHSProto = *LHSPI;
+ for (ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(),
+ LHSPE = LHSP->qual_end();
+ LHSPI != LHSPE; LHSPI++) {
+ bool RHSImplementsProtocol = false;
+
+ // If the RHS doesn't implement the protocol on the left, the types
+ // are incompatible.
+ for (ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(),
+ RHSPE = RHSP->qual_end();
+ !RHSImplementsProtocol && (RHSPI != RHSPE); RHSPI++) {
+ if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier()))
+ RHSImplementsProtocol = true;
+ }
+ // FIXME: For better diagnostics, consider passing back the protocol name.
+ if (!RHSImplementsProtocol)
+ return false;
}
-
- // If we got here, we didn't find one of the LHS's protocols in the RHS list.
- return false;
+ // The RHS implements all protocols listed on the LHS.
+ return true;
}
bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {
diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp
index bdbcce7..4d2fcb6 100644
--- a/lib/AST/DeclObjC.cpp
+++ b/lib/AST/DeclObjC.cpp
@@ -412,6 +412,19 @@
ObjCContainerDecl::Destroy(C);
}
+ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) {
+ ObjCProtocolDecl *PDecl = this;
+
+ if (Name == getIdentifier())
+ return PDecl;
+
+ for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I)
+ if ((PDecl = (*I)->lookupProtocolNamed(Name)))
+ return PDecl;
+
+ return NULL;
+}
+
// lookupInstanceMethod - Lookup a instance method in the protocol and protocols
// it inherited.
ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) {
diff --git a/test/SemaObjC/protocol-typecheck.m b/test/SemaObjC/protocol-typecheck.m
new file mode 100644
index 0000000..5ffe73f
--- /dev/null
+++ b/test/SemaObjC/protocol-typecheck.m
@@ -0,0 +1,25 @@
+// RUN: clang -fsyntax-only -verify %s
+
+@interface NSObject @end
+@protocol XCElementP @end
+@protocol XCElementSpacerP <XCElementP> @end
+
+@protocol PWhatever @end
+
+@interface XX
+
+- (void)setFlexElement:(NSObject <PWhatever, XCElementP> *)flexer;
+- (void)setFlexElement2:(NSObject <PWhatever, XCElementSpacerP> *)flexer;
+
+@end
+
+void func() {
+ NSObject <PWhatever, XCElementSpacerP> * flexer;
+ NSObject <PWhatever, XCElementP> * flexer2;
+ XX *obj;
+ [obj setFlexElement:flexer];
+ // FIXME: GCC provides the following diagnostic (which is much better):
+ // protocol-typecheck.m:21: warning: class 'NSObject <PWhatever, XCElementP>' does not implement the 'XCElementSpacerP' protocol
+ [obj setFlexElement2:flexer2]; // expected-warning{{incompatible pointer types sending 'NSObject<PWhatever,XCElementP> *', expected 'NSObject<PWhatever,XCElementSpacerP> *'}}
+}
+
diff --git a/test/SemaObjC/protocol-undef.m b/test/SemaObjC/protocol-undef.m
index c35d3f8..a490fa2 100644
--- a/test/SemaObjC/protocol-undef.m
+++ b/test/SemaObjC/protocol-undef.m
@@ -40,8 +40,7 @@
- (void)_recalculateStoredArraysForAnchor:(OzzyAnchor *)anchor {
Ozzy * contentGroup = anchor.contentGroup;
if (contentGroup == ((void *)0)) {
- // GCC doesn't warn about the following (which seems wrong).
- contentGroup = anchor; // expected-warning{{incompatible pointer types assigning 'OzzyAnchor *', expected 'Ozzy *'}}
+ contentGroup = anchor;
}
}
@end