diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 49 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 23 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 4 | ||||
-rw-r--r-- | test/SemaObjC/protocol-archane.m | 5 |
6 files changed, 113 insertions, 0 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 387120ea3d..0353a892e6 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -73,6 +73,7 @@ class ASTContext { 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 @@ public: 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 ab7acc449f..5dc2c31107 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -69,6 +69,7 @@ namespace clang { class BuiltinType; class ObjCInterfaceType; class ObjCQualifiedIdType; + class ObjCQualifiedClassType; class ObjCQualifiedInterfaceType; class StmtIteratorBase; class ClassTemplateSpecializationType; @@ -384,6 +385,7 @@ public: 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 @@ public: 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 @@ public: }; +/// 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::isObjCQualifiedInterfaceType() const { 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 830cc6a977..cdd61cd3f4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1394,6 +1394,29 @@ QualType ASTContext::getObjCQualifiedIdType(ObjCProtocolDecl **Protocols, 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 65c4fabf8f..ba8b463c27 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -869,6 +869,17 @@ void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID) { 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 @@ void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString) const { 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 acdeec6ba9..697524133c 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -151,6 +151,10 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) { // 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 2cba1fad05..ff08a176bf 100644 --- a/test/SemaObjC/protocol-archane.m +++ b/test/SemaObjC/protocol-archane.m @@ -27,3 +27,8 @@ typedef int NotAnObjCObjectType; // 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; |