From d849982e843e5295489409caaf4e95093b019fca Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Mon, 29 Oct 2007 05:01:08 +0000 Subject: [PATCH] Add (partial) support for @encode. llvm-svn: 43439 --- clang/AST/ASTContext.cpp | 100 +++++++++++++++++++++++++++ clang/CodeGen/CGExprScalar.cpp | 19 +++++ clang/Driver/RewriteTest.cpp | 5 +- clang/include/clang/AST/ASTContext.h | 3 + 4 files changed, 126 insertions(+), 1 deletion(-) diff --git a/clang/AST/ASTContext.cpp b/clang/AST/ASTContext.cpp index cf617d190eeb..61e2dbea069e 100644 --- a/clang/AST/ASTContext.cpp +++ b/clang/AST/ASTContext.cpp @@ -16,6 +16,8 @@ #include "clang/AST/DeclObjC.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" + using namespace clang; enum FloatingRank { @@ -835,6 +837,104 @@ QualType ASTContext::getCFConstantStringType() { return getTagDeclType(CFConstantStringTypeDecl); } +static bool isTypeTypedefedAsBOOL(QualType T) +{ + if (const PointerType *NCPT = T->getAsPointerType()) + if (const TypedefType *TT = dyn_cast(NCPT->getPointeeType())) + if (!strcmp(TT->getDecl()->getName(), "BOOL")) + return true; + + return false; +} + +void ASTContext::getObjcEncodingForType(QualType T, std::string& S) const +{ + QualType Ty = T.getCanonicalType(); + + if (const BuiltinType *BT = Ty->getAsBuiltinType()) { + char encoding; + switch (BT->getKind()) { + 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; + default: + assert(0 && "Unhandled builtin type kind"); + } + + S += encoding; + } else if (const PointerType *PT = Ty->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + + if (PointeeTy->isCharType()) { + // char pointer types should be encoded as '*' unless it is a + // type that has been typedef'd to 'BOOL'. + if (isTypeTypedefedAsBOOL(T)) { + S += '*'; + return; + } + } + + S += '^'; + getObjcEncodingForType(PT->getPointeeType(), S); + } else if (const ArrayType *AT = Ty->getAsArrayType()) { + S += '['; + + if (const ConstantArrayType *CAT = dyn_cast(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else + assert(0 && "Unhandled array type!"); + + getObjcEncodingForType(AT->getElementType(), S); + S += ']'; + } else + fprintf(stderr, "@encode for type %s not implemented!\n", + Ty.getAsString().c_str()); +} + void ASTContext::setBuiltinVaListType(QualType T) { assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); diff --git a/clang/CodeGen/CGExprScalar.cpp b/clang/CodeGen/CGExprScalar.cpp index 9bfd82ec0a09..e443a2636abb 100644 --- a/clang/CodeGen/CGExprScalar.cpp +++ b/clang/CodeGen/CGExprScalar.cpp @@ -16,6 +16,7 @@ #include "clang/AST/AST.h" #include "llvm/Constants.h" #include "llvm/Function.h" +#include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" #include "llvm/Support/Compiler.h" using namespace clang; @@ -262,6 +263,7 @@ public: Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } + Value *VisitObjCEncodeExpr(const ObjCEncodeExpr *E); }; } // end anonymous namespace. @@ -917,6 +919,23 @@ Value *ScalarExprEmitter::VisitVAArgExpr(VAArgExpr *VE) return V; } +Value *ScalarExprEmitter::VisitObjCEncodeExpr(const ObjCEncodeExpr *E) +{ + std::string str; + + CGF.getContext().getObjcEncodingForType(E->getEncodedType(), str); + + llvm::Constant *C = llvm::ConstantArray::get(str); + C = new llvm::GlobalVariable(C->getType(), true, + llvm::GlobalValue::InternalLinkage, + C, ".str", &CGF.CGM.getModule()); + llvm::Constant *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty); + llvm::Constant *Zeros[] = { Zero, Zero }; + C = llvm::ConstantExpr::getGetElementPtr(C, Zeros, 2); + + return C; +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// diff --git a/clang/Driver/RewriteTest.cpp b/clang/Driver/RewriteTest.cpp index db2c1ee70b86..0c303daddf2f 100644 --- a/clang/Driver/RewriteTest.cpp +++ b/clang/Driver/RewriteTest.cpp @@ -329,7 +329,10 @@ Stmt *RewriteTest::RewriteFunctionBody(Stmt *S) { Stmt *RewriteTest::RewriteAtEncode(ObjCEncodeExpr *Exp) { // Create a new string expression. QualType StrType = Context->getPointerType(Context->CharTy); - Expr *Replacement = new StringLiteral("foo", 3, false, StrType, + std::string StrEncoding; + Context->getObjcEncodingForType(Exp->getEncodedType(), StrEncoding); + Expr *Replacement = new StringLiteral(StrEncoding.c_str(), + StrEncoding.length(), false, StrType, SourceLocation(), SourceLocation()); Rewrite.ReplaceStmt(Exp, Replacement); delete Exp; diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 3881b6316b47..9ac7b846dfd3 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -171,6 +171,9 @@ public: return ObjcConstantStringType; } + // Return the ObjC type encoding for a given type. + void getObjcEncodingForType(QualType t, std::string &S) const; + // This setter/getter repreents the ObjC 'id' type. It is setup lazily, by // Sema. void setObjcIdType(TypedefDecl *Decl);