[cfe-commits] r131365 - in /cfe/trunk: include/clang/AST/ASTContext.h lib/AST/ASTContext.cpp test/CodeGenObjC/encode-test.m test/CodeGenObjCXX/encode.mm

Argyrios Kyrtzidis akyrtzi at gmail.com
Sat May 14 13:32:44 PDT 2011


Author: akirtzidis
Date: Sat May 14 15:32:43 2011
New Revision: 131365

URL: http://llvm.org/viewvc/llvm-project?rev=131365&view=rev
Log:
Create proper Objective-C @encoding for C++ classes; fixes rdar://9357400.

Go through and expand the members of bases into the encoding string (and encode the VTable as well).
Unlike gcc which expands virtual bases as many times as they appear in the
hierarchy, clang will only expand them once at the end, to reflect the actual layout.

Note that there doesn't seem to be a way to indicate in the encoding that
packing/alignment of members is different that normal, in which case
the encoding will be out-of-sync with the real layout.
If the runtime switches to just consider the size of types without
taking into account alignment, we could easily make padding explicit in the
encoding (e.g. using arrays of chars). The encoding strings would be
longer then though.

Also encode a flexible array member as array of 0 size, like gcc, not as a pointer.

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/test/CodeGenObjC/encode-test.m
    cfe/trunk/test/CodeGenObjCXX/encode.mm

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=131365&r1=131364&r2=131365&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Sat May 14 15:32:43 2011
@@ -1568,7 +1568,13 @@
                                   bool ExpandStructures,
                                   const FieldDecl *Field,
                                   bool OutermostType = false,
-                                  bool EncodingProperty = false) const;
+                                  bool EncodingProperty = false,
+                                  bool StructField = false) const;
+
+  // Adds the encoding of the structure's members.
+  void getObjCEncodingForStructureImpl(RecordDecl *RD, std::string &S,
+                                       const FieldDecl *Field,
+                                       bool includeVBases = true) const;
  
   const ASTRecordLayout &
   getObjCLayout(const ObjCInterfaceDecl *D,

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=131365&r1=131364&r2=131365&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Sat May 14 15:32:43 2011
@@ -31,6 +31,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Support/raw_ostream.h"
 #include "CXXABI.h"
+#include <map>
 
 using namespace clang;
 
@@ -4152,7 +4153,8 @@
                                             bool ExpandStructures,
                                             const FieldDecl *FD,
                                             bool OutermostType,
-                                            bool EncodingProperty) const {
+                                            bool EncodingProperty,
+                                            bool StructField) const {
   if (T->getAs<BuiltinType>()) {
     if (FD && FD->isBitField())
       return EncodeBitField(this, S, T, FD);
@@ -4237,7 +4239,7 @@
   if (const ArrayType *AT =
       // Ignore type qualifiers etc.
         dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
-    if (isa<IncompleteArrayType>(AT)) {
+    if (isa<IncompleteArrayType>(AT) && !StructField) {
       // Incomplete arrays are encoded as a pointer to the array element.
       S += '^';
 
@@ -4250,7 +4252,8 @@
         S += llvm::utostr(CAT->getSize().getZExtValue());
       else {
         //Variable length arrays are encoded as a regular array with 0 elements.
-        assert(isa<VariableArrayType>(AT) && "Unknown array type!");
+        assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) &&
+               "Unknown array type!");
         S += '0';
       }
 
@@ -4288,24 +4291,30 @@
     }
     if (ExpandStructures) {
       S += '=';
-      for (RecordDecl::field_iterator Field = RDecl->field_begin(),
-                                   FieldEnd = RDecl->field_end();
-           Field != FieldEnd; ++Field) {
-        if (FD) {
-          S += '"';
-          S += Field->getNameAsString();
-          S += '"';
-        }
+      if (!RDecl->isUnion()) {
+        getObjCEncodingForStructureImpl(RDecl, S, FD);
+      } else {
+        for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+                                     FieldEnd = RDecl->field_end();
+             Field != FieldEnd; ++Field) {
+          if (FD) {
+            S += '"';
+            S += Field->getNameAsString();
+            S += '"';
+          }
 
-        // Special case bit-fields.
-        if (Field->isBitField()) {
-          getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
-                                     (*Field));
-        } else {
-          QualType qt = Field->getType();
-          getLegacyIntegralTypeEncoding(qt);
-          getObjCEncodingForTypeImpl(qt, S, false, true,
-                                     FD);
+          // Special case bit-fields.
+          if (Field->isBitField()) {
+            getObjCEncodingForTypeImpl(Field->getType(), S, false, true,
+                                       (*Field));
+          } else {
+            QualType qt = Field->getType();
+            getLegacyIntegralTypeEncoding(qt);
+            getObjCEncodingForTypeImpl(qt, S, false, true,
+                                       FD, /*OutermostType*/false,
+                                       /*EncodingProperty*/false,
+                                       /*StructField*/true);
+          }
         }
       }
     }
@@ -4426,6 +4435,129 @@
   assert(0 && "@encode for type not implemented!");
 }
 
+void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
+                                                 std::string &S,
+                                                 const FieldDecl *FD,
+                                                 bool includeVBases) const {
+  assert(RDecl && "Expected non-null RecordDecl");
+  assert(!RDecl->isUnion() && "Should not be called for unions");
+  if (!RDecl->getDefinition())
+    return;
+
+  CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl);
+  std::map<uint64_t, NamedDecl *> FieldOrBaseOffsets;
+  const ASTRecordLayout &layout = getASTRecordLayout(RDecl);
+  
+  unsigned i = 0;
+  for (RecordDecl::field_iterator Field = RDecl->field_begin(),
+                               FieldEnd = RDecl->field_end();
+       Field != FieldEnd; ++Field, ++i) {
+    assert(!FieldOrBaseOffsets[layout.getFieldOffset(i)]);
+    FieldOrBaseOffsets[layout.getFieldOffset(i)] = *Field;
+  }
+  
+  if (CXXRec) {
+    for (CXXRecordDecl::base_class_iterator
+           BI = CXXRec->bases_begin(),
+           BE = CXXRec->bases_end(); BI != BE; ++BI) {
+      if (!BI->isVirtual()) {
+        CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+        assert(!FieldOrBaseOffsets[layout.getBaseClassOffsetInBits(base)]);
+        FieldOrBaseOffsets[layout.getBaseClassOffsetInBits(base)] = base;
+      }
+    }
+    if (includeVBases) {
+      for (CXXRecordDecl::base_class_iterator
+             BI = CXXRec->vbases_begin(),
+             BE = CXXRec->vbases_end(); BI != BE; ++BI) {
+        CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl();
+        assert(!FieldOrBaseOffsets[layout.getVBaseClassOffsetInBits(base)]);
+        FieldOrBaseOffsets[layout.getVBaseClassOffsetInBits(base)] = base;
+      }
+    }
+  }
+
+  CharUnits size;
+  if (CXXRec) {
+    size = includeVBases ? layout.getSize() : layout.getNonVirtualSize();
+  } else {
+    size = layout.getSize();
+  }
+
+  uint64_t CurOffs = 0;
+  std::map<uint64_t, NamedDecl *>::iterator
+    CurLayObj = FieldOrBaseOffsets.begin();
+
+  if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) {
+    assert(CXXRec && CXXRec->isDynamicClass() &&
+           "Offset 0 was empty but no VTable ?");
+    if (FD) {
+      S += "\"_vptr$";
+      std::string recname = CXXRec->getNameAsString();
+      if (recname.empty()) recname = "?";
+      S += recname;
+      S += '"';
+    }
+    S += "^^?";
+    CurOffs += getTypeSize(VoidPtrTy);
+  }
+
+  if (!RDecl->hasFlexibleArrayMember()) {
+    // Mark the end of the structure.
+    assert(!FieldOrBaseOffsets[toBits(size)]);
+    FieldOrBaseOffsets[toBits(size)] = 0;
+  }
+
+  for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) {
+    assert(CurOffs <= CurLayObj->first);
+
+    if (CurOffs < CurLayObj->first) {
+      uint64_t padding = CurLayObj->first - CurOffs; 
+      // FIXME: There doesn't seem to be a way to indicate in the encoding that
+      // packing/alignment of members is different that normal, in which case
+      // the encoding will be out-of-sync with the real layout.
+      // If the runtime switches to just consider the size of types without
+      // taking into account alignment, we could make padding explicit in the
+      // encoding (e.g. using arrays of chars). The encoding strings would be
+      // longer then though.
+      CurOffs += padding;
+    }
+
+    NamedDecl *dcl = CurLayObj->second;
+    if (dcl == 0)
+      break; // reached end of structure.
+
+    if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) {
+      // We expand the bases without their virtual bases since those are going
+      // in the initial structure. Note that this differs from gcc which
+      // expands virtual bases each time one is encountered in the hierarchy,
+      // making the encoding type bigger than it really is.
+      getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false);
+      CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize());
+    } else {
+      FieldDecl *field = cast<FieldDecl>(dcl);
+      if (FD) {
+        S += '"';
+        S += field->getNameAsString();
+        S += '"';
+      }
+
+      if (field->isBitField()) {
+        EncodeBitField(this, S, field->getType(), field);
+        CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue();
+      } else {
+        QualType qt = field->getType();
+        getLegacyIntegralTypeEncoding(qt);
+        getObjCEncodingForTypeImpl(qt, S, false, true, FD,
+                                   /*OutermostType*/false,
+                                   /*EncodingProperty*/false,
+                                   /*StructField*/true);
+        CurOffs += getTypeSize(field->getType());
+      }
+    }
+  }
+}
+
 void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT,
                                                  std::string& S) const {
   if (QT & Decl::OBJC_TQ_In)

Modified: cfe/trunk/test/CodeGenObjC/encode-test.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/encode-test.m?rev=131365&r1=131364&r2=131365&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/encode-test.m (original)
+++ cfe/trunk/test/CodeGenObjC/encode-test.m Sat May 14 15:32:43 2011
@@ -144,3 +144,10 @@
   long double x;
 };
 const char g8[] = @encode(struct s8);
+
+// CHECK: @g9 = constant [11 x i8] c"{S9=i[0i]}\00"
+struct S9 {
+  int x;
+  int flex[];
+};
+const char g9[] = @encode(struct S9);

Modified: cfe/trunk/test/CodeGenObjCXX/encode.mm
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjCXX/encode.mm?rev=131365&r1=131364&r2=131365&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjCXX/encode.mm (original)
+++ cfe/trunk/test/CodeGenObjCXX/encode.mm Sat May 14 15:32:43 2011
@@ -62,3 +62,60 @@
 @implementation RedBalloonHGXFormWrapper
 @end
 
+// rdar://9357400
+namespace rdar9357400 {
+  template<int Dim1 = -1, int Dim2 = -1> struct fixed {
+      template<int D> struct rebind { typedef fixed<D> other; };
+  };
+  
+  template<typename Element, int Size>
+  class fixed_1D
+  {
+  public:
+      typedef Element value_type;
+      typedef value_type array_impl[Size];
+    protected:
+      array_impl                  m_data;
+  };
+  
+  template<typename Element, typename Alloc>
+  class vector;
+  
+  template<typename Element, int Size>
+  class vector< Element, fixed<Size> >
+  : public fixed_1D<Element,Size> { };
+
+  typedef vector< float,  fixed<4> > vector4f;
+
+  // CHECK: @_ZN11rdar9357400L2ggE = internal constant [49 x i8] c"{vector<float, rdar9357400::fixed<4, -1> >=[4f]}\00"
+  const char gg[] = @encode(vector4f);
+}
+
+struct Base1 {
+  char x;
+};
+
+struct DBase : public Base1 {
+  double x;
+  virtual ~DBase();
+};
+
+struct Sub_with_virt : virtual DBase {
+  long x;
+};
+
+struct Sub2 : public Sub_with_virt, public Base1, virtual DBase {
+  float x;
+};
+
+// CHECK: @_ZL2g1 = internal constant [10 x i8] c"{Base1=c}\00"
+const char g1[] = @encode(Base1);
+
+// CHECK: @_ZL2g2 = internal constant [14 x i8] c"{DBase=^^?cd}\00"
+const char g2[] = @encode(DBase);
+
+// CHECK: @_ZL2g3 = internal constant [26 x i8] c"{Sub_with_virt=^^?q^^?cd}\00"
+const char g3[] = @encode(Sub_with_virt);
+
+// CHECK: @_ZL2g4 = internal constant [19 x i8] c"{Sub2=^^?qcf^^?cd}\00"
+const char g4[] = @encode(Sub2);





More information about the cfe-commits mailing list