Add support for GCC ObjC extension "Class<protocol>". Sigh.
Found while researching <rdar://problem/6497631> Message lookup is sometimes different than gcc's.
Will never be seen in user code. Needed to pass dejagnu testsuite.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65244 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 387120e..0353a89 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -73,6 +73,7 @@
ClassTemplateSpecializationTypes;
llvm::FoldingSet<ObjCQualifiedInterfaceType> ObjCQualifiedInterfaceTypes;
llvm::FoldingSet<ObjCQualifiedIdType> ObjCQualifiedIdTypes;
+ llvm::FoldingSet<ObjCQualifiedClassType> ObjCQualifiedClassTypes;
/// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts.
/// This is lazily created. This is intentionally not serialized.
llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*> ASTRecordLayouts;
@@ -291,6 +292,10 @@
QualType getObjCQualifiedIdType(ObjCProtocolDecl **ProtocolList,
unsigned NumProtocols);
+ /// getObjCQualifiedClassType - Return an ObjCQualifiedClassType for a
+ /// given 'Class' and conforming protocol list.
+ QualType getObjCQualifiedClassType(ObjCProtocolDecl **ProtocolList,
+ unsigned NumProtocols);
/// getTypeOfType - GCC extension.
QualType getTypeOfExpr(Expr *e);
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index ab7acc4..5dc2c31 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -69,6 +69,7 @@
class BuiltinType;
class ObjCInterfaceType;
class ObjCQualifiedIdType;
+ class ObjCQualifiedClassType;
class ObjCQualifiedInterfaceType;
class StmtIteratorBase;
class ClassTemplateSpecializationType;
@@ -384,6 +385,7 @@
bool isObjCInterfaceType() const; // NSString or NSString<foo>
bool isObjCQualifiedInterfaceType() const; // NSString<foo>
bool isObjCQualifiedIdType() const; // id<foo>
+ bool isObjCQualifiedClassType() const; // Class<foo>
bool isTemplateTypeParmType() const; // C++ template type parameter
/// isDependentType - Whether this type is a dependent type, meaning
@@ -417,6 +419,7 @@
const ObjCInterfaceType *getAsObjCInterfaceType() const;
const ObjCQualifiedInterfaceType *getAsObjCQualifiedInterfaceType() const;
const ObjCQualifiedIdType *getAsObjCQualifiedIdType() const;
+ const ObjCQualifiedClassType *getAsObjCQualifiedClassType() const;
const TemplateTypeParmType *getAsTemplateTypeParmType() const;
const ClassTemplateSpecializationType *
@@ -1744,6 +1747,49 @@
};
+/// ObjCQualifiedClassType - to represent Class<protocol-list>.
+///
+/// Duplicate protocols are removed and protocol list is canonicalized to be in
+/// alphabetical order.
+class ObjCQualifiedClassType : public Type,
+ public llvm::FoldingSetNode {
+ // List of protocols for this protocol conforming 'id' type
+ // List is sorted on protocol name. No protocol is enterred more than once.
+ llvm::SmallVector<ObjCProtocolDecl*, 8> Protocols;
+
+ ObjCQualifiedClassType(ObjCProtocolDecl **Protos, unsigned NumP)
+ : Type(ObjCQualifiedId, QualType()/*these are always canonical*/,
+ /*Dependent=*/false),
+ Protocols(Protos, Protos+NumP) { }
+ friend class ASTContext; // ASTContext creates these.
+public:
+
+ ObjCProtocolDecl *getProtocols(unsigned i) const {
+ return Protocols[i];
+ }
+ unsigned getNumProtocols() const {
+ return Protocols.size();
+ }
+ ObjCProtocolDecl **getReferencedProtocols() {
+ return &Protocols[0];
+ }
+
+ typedef llvm::SmallVector<ObjCProtocolDecl*, 8>::const_iterator qual_iterator;
+ qual_iterator qual_begin() const { return Protocols.begin(); }
+ qual_iterator qual_end() const { return Protocols.end(); }
+
+ virtual void getAsStringInternal(std::string &InnerString) const;
+
+ void Profile(llvm::FoldingSetNodeID &ID);
+ static void Profile(llvm::FoldingSetNodeID &ID,
+ ObjCProtocolDecl **protocols, unsigned NumProtocols);
+
+ static bool classof(const Type *T) {
+ return T->getTypeClass() == ObjCQualifiedId;
+ }
+ static bool classof(const ObjCQualifiedClassType *) { return true; }
+
+};
// Inline function definitions.
@@ -1899,6 +1945,9 @@
inline bool Type::isObjCQualifiedIdType() const {
return isa<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType());
}
+inline bool Type::isObjCQualifiedClassType() const {
+ return isa<ObjCQualifiedClassType>(CanonicalType.getUnqualifiedType());
+}
inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType.getUnqualifiedType());
}
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 830cc6a..cdd61cd 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1394,6 +1394,29 @@
return QualType(QType, 0);
}
+/// getObjCQualifiedClassType - Return an ObjCQualifiedIdType for the 'Class'
+/// decl and the conforming protocol list.
+QualType ASTContext::getObjCQualifiedClassType(ObjCProtocolDecl **Protocols,
+ unsigned NumProtocols) {
+ // Sort the protocol list alphabetically to canonicalize it.
+ SortAndUniqueProtocols(Protocols, NumProtocols);
+
+ llvm::FoldingSetNodeID ID;
+ ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols);
+
+ void *InsertPos = 0;
+ if (ObjCQualifiedClassType *QT =
+ ObjCQualifiedClassTypes.FindNodeOrInsertPos(ID, InsertPos))
+ return QualType(QT, 0);
+
+ // No Match;
+ ObjCQualifiedClassType *QType =
+ new (*this,8) ObjCQualifiedClassType(Protocols, NumProtocols);
+ Types.push_back(QType);
+ ObjCQualifiedClassTypes.InsertNode(QType, InsertPos);
+ return QualType(QType, 0);
+}
+
/// getTypeOfExpr - Unlike many "get<Type>" functions, we can't unique
/// TypeOfExpr AST's (since expression's are never shared). For example,
/// multiple declarations that refer to "typeof(x)" all contain different
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 65c4fab..ba8b463 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -869,6 +869,17 @@
Profile(ID, &Protocols[0], getNumProtocols());
}
+void ObjCQualifiedClassType::Profile(llvm::FoldingSetNodeID &ID,
+ ObjCProtocolDecl **protocols,
+ unsigned NumProtocols) {
+ for (unsigned i = 0; i != NumProtocols; i++)
+ ID.AddPointer(protocols[i]);
+}
+
+void ObjCQualifiedClassType::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, &Protocols[0], getNumProtocols());
+}
+
/// LookThroughTypedefs - Return the ultimate type this typedef corresponds to
/// potentially looking through *all* consequtive typedefs. This returns the
/// sum of the type qualifiers, so if you have:
@@ -1345,6 +1356,22 @@
InnerString = ObjCQIString + InnerString;
}
+void ObjCQualifiedClassType::getAsStringInternal(std::string &InnerString) const
+{
+ if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
+ InnerString = ' ' + InnerString;
+ std::string ObjCQIString = "Class";
+ ObjCQIString += '<';
+ int num = getNumProtocols();
+ for (int i = 0; i < num; i++) {
+ ObjCQIString += getProtocols(i)->getNameAsString();
+ if (i < num-1)
+ ObjCQIString += ',';
+ }
+ ObjCQIString += '>';
+ InnerString = ObjCQIString + InnerString;
+}
+
void TagType::getAsStringInternal(std::string &InnerString) const {
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
InnerString = ' ' + InnerString;
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index acdeec6..6975241 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -151,6 +151,10 @@
// id<protocol-list>
Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ,
DS.getNumProtocolQualifiers());
+ else if (Result == Context.getObjCClassType())
+ // Support the following GCC extension: Class<protocol-list>
+ Result = Context.getObjCQualifiedClassType((ObjCProtocolDecl**)PQ,
+ DS.getNumProtocolQualifiers());
else
Diag(DS.getSourceRange().getBegin(),
diag::warn_ignoring_objc_qualifiers) << DS.getSourceRange();
diff --git a/test/SemaObjC/protocol-archane.m b/test/SemaObjC/protocol-archane.m
index 2cba1fa..ff08a17 100644
--- a/test/SemaObjC/protocol-archane.m
+++ b/test/SemaObjC/protocol-archane.m
@@ -27,3 +27,8 @@
// GCC doesn't diagnose this.
NotAnObjCObjectType <SomeProtocol> *obj; // expected-warning {{ignoring protocol qualifiers on non-ObjC type}}
+
+// GCC extension (sigh). Found while researching rdar://6497631
+typedef struct objc_class *Class;
+
+Class <SomeProtocol> UnfortunateGCCExtension;