From: Fariborz Jahanian Date: Fri, 19 Dec 2008 23:34:38 +0000 (+0000) Subject: More encoding support. This time for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=43822eaeddeaa419b90f23c68af6b23c46788a58;p=clang More encoding support. This time for @encode of classes and bitfields. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@61268 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 2c7b6fdf41..4a1992a914 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -299,7 +299,7 @@ public: /// given type into \arg S. If \arg NameFields is specified then /// record field names are also encoded. void getObjCEncodingForType(QualType t, std::string &S, - bool NameFields=false) const; + FieldDecl *Field=NULL) const; // Put the string version of type qualifiers into S. void getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, @@ -542,7 +542,7 @@ private: void getObjCEncodingForTypeImpl(QualType t, std::string &S, bool ExpandPointedToStructures, bool ExpandStructures, - bool NameFields) const; + FieldDecl *Field) const; }; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a91679e594..c50a021028 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1734,48 +1734,58 @@ void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, } void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - bool NameFields) const { + FieldDecl *Field) const { // We follow the behavior of gcc, expanding structures which are // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. - getObjCEncodingForTypeImpl(T, S, true, true, NameFields); + getObjCEncodingForTypeImpl(T, S, true, true, Field); } void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool ExpandPointedToStructures, bool ExpandStructures, - bool NameFields) const { + FieldDecl *FD) const { if (const BuiltinType *BT = T->getAsBuiltinType()) { - char encoding; - switch (BT->getKind()) { - default: assert(0 && "Unhandled builtin type kind"); - case BuiltinType::Void: encoding = 'v'; break; - case BuiltinType::Bool: encoding = 'B'; break; - case BuiltinType::Char_U: - case BuiltinType::UChar: encoding = 'C'; break; - case BuiltinType::UShort: encoding = 'S'; break; - case BuiltinType::UInt: encoding = 'I'; break; - case BuiltinType::ULong: encoding = 'L'; break; - case BuiltinType::ULongLong: encoding = 'Q'; break; - case BuiltinType::Char_S: - case BuiltinType::SChar: encoding = 'c'; break; - case BuiltinType::Short: encoding = 's'; break; - case BuiltinType::Int: encoding = 'i'; break; - case BuiltinType::Long: encoding = 'l'; break; - case BuiltinType::LongLong: encoding = 'q'; break; - case BuiltinType::Float: encoding = 'f'; break; - case BuiltinType::Double: encoding = 'd'; break; - case BuiltinType::LongDouble: encoding = 'd'; break; + if (FD && FD->isBitField()) { + const Expr *E = FD->getBitWidth(); + assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); + ASTContext *Ctx = const_cast(this); + unsigned N = E->getIntegerConstantExprValue(*Ctx).getZExtValue(); + S += 'b'; + S += llvm::utostr(N); } + else { + char encoding; + switch (BT->getKind()) { + default: assert(0 && "Unhandled builtin type kind"); + case BuiltinType::Void: encoding = 'v'; break; + case BuiltinType::Bool: encoding = 'B'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: encoding = 'C'; break; + case BuiltinType::UShort: encoding = 'S'; break; + case BuiltinType::UInt: encoding = 'I'; break; + case BuiltinType::ULong: encoding = 'L'; break; + case BuiltinType::ULongLong: encoding = 'Q'; break; + case BuiltinType::Char_S: + case BuiltinType::SChar: encoding = 'c'; break; + case BuiltinType::Short: encoding = 's'; break; + case BuiltinType::Int: encoding = 'i'; break; + case BuiltinType::Long: encoding = 'l'; break; + case BuiltinType::LongLong: encoding = 'q'; break; + case BuiltinType::Float: encoding = 'f'; break; + case BuiltinType::Double: encoding = 'd'; break; + case BuiltinType::LongDouble: encoding = 'd'; break; + } - S += encoding; + S += encoding; + } } else if (T->isObjCQualifiedIdType()) { // Treat id same as 'id' for encoding purposes. return getObjCEncodingForTypeImpl(getObjCIdType(), S, ExpandPointedToStructures, - ExpandStructures, NameFields); + ExpandStructures, FD); } else if (const PointerType *PT = T->getAsPointerType()) { QualType PointeeTy = PT->getPointeeType(); @@ -1810,7 +1820,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += '^'; getObjCEncodingForTypeImpl(PT->getPointeeType(), S, false, ExpandPointedToStructures, - false); + NULL); } else if (const ArrayType *AT = // Ignore type qualifiers etc. dyn_cast(T->getCanonicalTypeInternal())) { @@ -1822,7 +1832,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, assert(0 && "Unhandled array type!"); getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, NameFields); + false, ExpandStructures, FD); S += ']'; } else if (T->getAsFunctionType()) { S += '?'; @@ -1840,24 +1850,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, for (RecordDecl::field_iterator Field = RDecl->field_begin(), FieldEnd = RDecl->field_end(); Field != FieldEnd; ++Field) { - if (NameFields) { + if (FD) { S += '"'; S += Field->getNameAsString(); S += '"'; } // Special case bit-fields. - if (const Expr *E = Field->getBitWidth()) { - // FIXME: Fix constness. - ASTContext *Ctx = const_cast(this); - unsigned N = E->getIntegerConstantExprValue(*Ctx).getZExtValue(); - // FIXME: Obj-C is losing information about the type size - // here. Investigate if this is a problem. - S += 'b'; - S += llvm::utostr(N); + if (Field->isBitField()) { + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + (*Field)); } else { getObjCEncodingForTypeImpl(Field->getType(), S, false, true, - NameFields); + FD); } } } @@ -1866,7 +1871,26 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, S += 'i'; } else if (T->isBlockPointerType()) { S += '^'; // This type string is the same as general pointers. - } else + } else if (T->isObjCInterfaceType()) { + // @encode(class_name) + ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl(); + S += '{'; + const IdentifierInfo *II = OI->getIdentifier(); + S += II->getName(); + S += '='; + std::vector RecFields; + CollectObjCIvars(OI, RecFields); + for (unsigned int i = 0; i != RecFields.size(); i++) { + if (RecFields[i]->isBitField()) + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + RecFields[i]); + else + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + FD); + } + S += '}'; + } + else assert(0 && "@encode for type not implemented!"); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 33dfff1030..dd722458aa 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -1336,7 +1336,7 @@ llvm::Constant *CGObjCMac::EmitIvarList(const ObjCImplementationDecl *ID, Layout->getElementOffset(CGM.getTypes().getLLVMFieldNo(Field)); std::string TypeStr; Ivar[0] = GetMethodVarName(V->getIdentifier()); - CGM.getContext().getObjCEncodingForType(V->getType(), TypeStr, true); + CGM.getContext().getObjCEncodingForType(V->getType(), TypeStr, Field); Ivar[1] = GetMethodVarType(TypeStr); Ivar[2] = llvm::ConstantInt::get(ObjCTypes.IntTy, Offset); Ivars.push_back(llvm::ConstantStruct::get(ObjCTypes.IvarTy, Ivar)); diff --git a/test/CodeGenObjC/encode-test.m b/test/CodeGenObjC/encode-test.m index f5b6b92071..982faf03ba 100644 --- a/test/CodeGenObjC/encode-test.m +++ b/test/CodeGenObjC/encode-test.m @@ -1,5 +1,6 @@ // RUN: clang -fnext-runtime -emit-llvm -o %t %s && -// RUN: grep -e "\^{Innermost=CC}" %t | count 1 +// RUN: grep -e "\^{Innermost=CC}" %t | count 1 && +// RUN: grep -e "{Derived=#ib32b8b3b8sb16b8b8b2b8ccb6}" %t | count 1 @class Int1; @@ -15,3 +16,40 @@ struct Innermost { @implementation Int1 @end + +@interface Base +{ + struct objc_class *isa; + int full; + int full2: 32; + int _refs: 8; + int field2: 3; + unsigned f3: 8; + short cc; + unsigned g: 16; + int r2: 8; + int r3: 8; + int r4: 2; + int r5: 8; + char c; +} +@end + +@interface Derived: Base +{ + char d; + int _field3: 6; +} +@end + +@implementation Base +@end + +@implementation Derived +@end + +int main() +{ + const char *en = @encode(Derived); +} +