]> granicus.if.org Git - clang/commitdiff
Add support for GCC ObjC extension "Class<protocol>". Sigh.
authorSteve Naroff <snaroff@apple.com>
Sat, 21 Feb 2009 20:17:11 +0000 (20:17 +0000)
committerSteve Naroff <snaroff@apple.com>
Sat, 21 Feb 2009 20:17:11 +0000 (20:17 +0000)
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

include/clang/AST/ASTContext.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/Type.cpp
lib/Sema/SemaType.cpp
test/SemaObjC/protocol-archane.m

index 387120ea3d2f4aed9fb580fca8b981fd71fa3fb7..0353a892e6a24d64dedd5b9341ea3985f6cfa3f0 100644 (file)
@@ -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);
index ab7acc449ff5d3e75fb39ff707269d4afc654c52..5dc2c31107444237f3658978867e081fd56a09e0 100644 (file)
@@ -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());
 }
index 830cc6a977e24c1a26b09b86c90c108d3797df43..cdd61cd3f4a4b3adc4baacd72ccd66b2a82f8520 100644 (file)
@@ -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
index 65c4fabf8f14486d9ce8368f7fac5f4db9b6aacf..ba8b463c27739d99cbd786eb6f694eab7abb5018 100644 (file)
@@ -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;
index acdeec6ba94dfecd055c2ee627acef9d99fc7a2c..697524133c951270cc42744f5f2dddacfb2c1b04 100644 (file)
@@ -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();
index 2cba1fad051fc9cf850b7943065eef8b1dbfff38..ff08a176bf21ec333edcb306e8708c4eb98c8949 100644 (file)
@@ -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;