From: Argyrios Kyrtzidis Date: Tue, 17 May 2011 00:46:38 +0000 (+0000) Subject: Reapply the commits that r131401 reverted and add a fix for PR9927. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2636197098e02fd7c90f9496056b8ab886dcbff0;p=clang Reapply the commits that r131401 reverted and add a fix for PR9927. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@131446 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 55aca03fe5..2e84c5b08d 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1568,7 +1568,13 @@ private: 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, diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 379c13a934..b0303797e4 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -31,6 +31,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "CXXABI.h" +#include using namespace clang; @@ -4152,7 +4153,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandStructures, const FieldDecl *FD, bool OutermostType, - bool EncodingProperty) const { + bool EncodingProperty, + bool StructField) const { if (T->getAs()) { if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); @@ -4237,7 +4239,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast(T->getCanonicalTypeInternal())) { - if (isa(AT)) { + if (isa(AT) && !StructField) { // Incomplete arrays are encoded as a pointer to the array element. S += '^'; @@ -4246,11 +4248,15 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } else { S += '['; - if (const ConstantArrayType *CAT = dyn_cast(AT)) - S += llvm::utostr(CAT->getSize().getZExtValue()); - else { + if (const ConstantArrayType *CAT = dyn_cast(AT)) { + if (getTypeSize(CAT->getElementType()) == 0) + S += '0'; + else + S += llvm::utostr(CAT->getSize().getZExtValue()); + } else { //Variable length arrays are encoded as a regular array with 0 elements. - assert(isa(AT) && "Unknown array type!"); + assert((isa(AT) || isa(AT)) && + "Unknown array type!"); S += '0'; } @@ -4288,24 +4294,30 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } 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 +4438,135 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, 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(RDecl); + std::multimap FieldOrBaseOffsets; + const ASTRecordLayout &layout = getASTRecordLayout(RDecl); + + 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(); + uint64_t offs = layout.getBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + } + + unsigned i = 0; + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field, ++i) { + uint64_t offs = layout.getFieldOffset(i); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, *Field)); + } + + if (CXXRec && includeVBases) { + for (CXXRecordDecl::base_class_iterator + BI = CXXRec->vbases_begin(), + BE = CXXRec->vbases_end(); BI != BE; ++BI) { + CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + uint64_t offs = layout.getVBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + + CharUnits size; + if (CXXRec) { + size = includeVBases ? layout.getSize() : layout.getNonVirtualSize(); + } else { + size = layout.getSize(); + } + + uint64_t CurOffs = 0; + std::multimap::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. + uint64_t offs = toBits(size); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, (NamedDecl*)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(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); + if (!base->isEmpty()) + CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); + } else { + FieldDecl *field = cast(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) diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m index 24a90a0b4b..ade0c61822 100644 --- a/test/CodeGenObjC/encode-test.m +++ b/test/CodeGenObjC/encode-test.m @@ -144,3 +144,20 @@ struct s8 { 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); + +struct f +{ + int i; + struct{} g[4]; + int tt; +}; + +// CHECK: @g10 = constant [14 x i8] c"{f=i[0{?=}]i}\00" +const char g10[] = @encode(struct f); diff --git a/test/CodeGenObjCXX/PR9927.mm b/test/CodeGenObjCXX/PR9927.mm deleted file mode 100644 index ed503bd8be..0000000000 --- a/test/CodeGenObjCXX/PR9927.mm +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clang_cc1 -emit-llvm-only %s - -// Test that we don't crash. - -class allocator { -}; -class basic_string { -struct _Alloc_hider : allocator { -char* _M_p; -}; -_Alloc_hider _M_dataplus; -}; -@implementation -CrashReporterUI -(void)awakeFromNib { -} --(void)showCrashUI:(const basic_string&)dumpfile { -} -@end diff --git a/test/CodeGenObjCXX/encode.mm b/test/CodeGenObjCXX/encode.mm index 5a49feb706..dce3d70665 100644 --- a/test/CodeGenObjCXX/encode.mm +++ b/test/CodeGenObjCXX/encode.mm @@ -62,3 +62,73 @@ typedef float HGVec4f __attribute__ ((vector_size(16))); @implementation RedBalloonHGXFormWrapper @end +// rdar://9357400 +namespace rdar9357400 { + template struct fixed { + template struct rebind { typedef fixed other; }; + }; + + template + class fixed_1D + { + public: + typedef Element value_type; + typedef value_type array_impl[Size]; + protected: + array_impl m_data; + }; + + template + class vector; + + template + class vector< Element, fixed > + : public fixed_1D { }; + + typedef vector< float, fixed<4> > vector4f; + + // CHECK: @_ZN11rdar9357400L2ggE = internal constant [49 x i8] c"{vector >=[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); + +// http://llvm.org/PR9927 +class allocator { +}; +class basic_string { +struct _Alloc_hider : allocator { +char* _M_p; +}; +_Alloc_hider _M_dataplus; +}; + +// CHECK: @_ZL2g5 = internal constant [32 x i8] c"{basic_string={_Alloc_hider=*}}\00" +const char g5[] = @encode(basic_string);