From: Steve Naroff Date: Sat, 21 Feb 2009 20:17:11 +0000 (+0000) Subject: Add support for GCC ObjC extension "Class". Sigh. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=15509f4fe73f0e11a8cec602bce4d99d9454b7f6;p=clang Add support for GCC ObjC extension "Class". Sigh. Found while researching 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 387120ea3d..0353a892e6 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -73,6 +73,7 @@ class ASTContext { ClassTemplateSpecializationTypes; llvm::FoldingSet ObjCQualifiedInterfaceTypes; llvm::FoldingSet ObjCQualifiedIdTypes; + llvm::FoldingSet ObjCQualifiedClassTypes; /// ASTRecordLayouts - A cache mapping from RecordDecls to ASTRecordLayouts. /// This is lazily created. This is intentionally not serialized. llvm::DenseMap 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 bool isObjCQualifiedInterfaceType() const; // NSString bool isObjCQualifiedIdType() const; // id + bool isObjCQualifiedClassType() const; // Class 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. +/// +/// 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 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::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(CanonicalType.getUnqualifiedType()); } +inline bool Type::isObjCQualifiedClassType() const { + return isa(CanonicalType.getUnqualifiedType()); +} inline bool Type::isTemplateTypeParmType() const { return isa(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" 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 Result = Context.getObjCQualifiedIdType((ObjCProtocolDecl**)PQ, DS.getNumProtocolQualifiers()); + else if (Result == Context.getObjCClassType()) + // Support the following GCC extension: Class + 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 *obj; // expected-warning {{ignoring protocol qualifiers on non-ObjC type}} + +// GCC extension (sigh). Found while researching rdar://6497631 +typedef struct objc_class *Class; + +Class UnfortunateGCCExtension;