diff options
Diffstat (limited to 'clang/lib/AST')
-rw-r--r-- | clang/lib/AST/ASTConsumer.cpp | 28 | ||||
-rw-r--r-- | clang/lib/AST/ASTContext.cpp | 1853 | ||||
-rw-r--r-- | clang/lib/AST/Builtins.cpp | 195 | ||||
-rw-r--r-- | clang/lib/AST/CFG.cpp | 1509 | ||||
-rw-r--r-- | clang/lib/AST/Decl.cpp | 652 | ||||
-rw-r--r-- | clang/lib/AST/DeclSerialization.cpp | 463 | ||||
-rw-r--r-- | clang/lib/AST/Expr.cpp | 1391 | ||||
-rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 47 | ||||
-rw-r--r-- | clang/lib/AST/Makefile | 22 | ||||
-rw-r--r-- | clang/lib/AST/Stmt.cpp | 293 | ||||
-rw-r--r-- | clang/lib/AST/StmtDumper.cpp | 486 | ||||
-rw-r--r-- | clang/lib/AST/StmtIterator.cpp | 118 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 854 | ||||
-rw-r--r-- | clang/lib/AST/StmtSerialization.cpp | 1001 | ||||
-rw-r--r-- | clang/lib/AST/StmtViz.cpp | 59 | ||||
-rw-r--r-- | clang/lib/AST/TranslationUnit.cpp | 225 | ||||
-rw-r--r-- | clang/lib/AST/Type.cpp | 978 | ||||
-rw-r--r-- | clang/lib/AST/TypeSerialization.cpp | 293 |
18 files changed, 10467 insertions, 0 deletions
diff --git a/clang/lib/AST/ASTConsumer.cpp b/clang/lib/AST/ASTConsumer.cpp new file mode 100644 index 00000000000..b3d12710927 --- /dev/null +++ b/clang/lib/AST/ASTConsumer.cpp @@ -0,0 +1,28 @@ +//===--- ASTConsumer.cpp - Abstract interface for reading ASTs --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the ASTConsumer class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/Decl.h" +using namespace clang; + +ASTConsumer::~ASTConsumer() {} + +void ASTConsumer::HandleTopLevelDeclaration(Decl* d) { + if (ScopedDecl* sd = dyn_cast<ScopedDecl>(d)) + while (sd) { + HandleTopLevelDecl(sd); + sd = sd->getNextDeclarator(); + } + else + HandleTopLevelDecl(d); +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp new file mode 100644 index 00000000000..db4d53aa481 --- /dev/null +++ b/clang/lib/AST/ASTContext.cpp @@ -0,0 +1,1853 @@ +//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the ASTContext interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; + +enum FloatingRank { + FloatRank, DoubleRank, LongDoubleRank +}; + +ASTContext::~ASTContext() { + // Deallocate all the types. + while (!Types.empty()) { + if (FunctionTypeProto *FT = dyn_cast<FunctionTypeProto>(Types.back())) { + // Destroy the object, but don't call delete. These are malloc'd. + FT->~FunctionTypeProto(); + free(FT); + } else { + delete Types.back(); + } + Types.pop_back(); + } +} + +void ASTContext::PrintStats() const { + fprintf(stderr, "*** AST Context Stats:\n"); + fprintf(stderr, " %d types total.\n", (int)Types.size()); + unsigned NumBuiltin = 0, NumPointer = 0, NumArray = 0, NumFunctionP = 0; + unsigned NumVector = 0, NumComplex = 0; + unsigned NumFunctionNP = 0, NumTypeName = 0, NumTagged = 0, NumReference = 0; + + unsigned NumTagStruct = 0, NumTagUnion = 0, NumTagEnum = 0, NumTagClass = 0; + unsigned NumObjCInterfaces = 0, NumObjCQualifiedInterfaces = 0; + unsigned NumObjCQualifiedIds = 0; + + for (unsigned i = 0, e = Types.size(); i != e; ++i) { + Type *T = Types[i]; + if (isa<BuiltinType>(T)) + ++NumBuiltin; + else if (isa<PointerType>(T)) + ++NumPointer; + else if (isa<ReferenceType>(T)) + ++NumReference; + else if (isa<ComplexType>(T)) + ++NumComplex; + else if (isa<ArrayType>(T)) + ++NumArray; + else if (isa<VectorType>(T)) + ++NumVector; + else if (isa<FunctionTypeNoProto>(T)) + ++NumFunctionNP; + else if (isa<FunctionTypeProto>(T)) + ++NumFunctionP; + else if (isa<TypedefType>(T)) + ++NumTypeName; + else if (TagType *TT = dyn_cast<TagType>(T)) { + ++NumTagged; + switch (TT->getDecl()->getKind()) { + default: assert(0 && "Unknown tagged type!"); + case Decl::Struct: ++NumTagStruct; break; + case Decl::Union: ++NumTagUnion; break; + case Decl::Class: ++NumTagClass; break; + case Decl::Enum: ++NumTagEnum; break; + } + } else if (isa<ObjCInterfaceType>(T)) + ++NumObjCInterfaces; + else if (isa<ObjCQualifiedInterfaceType>(T)) + ++NumObjCQualifiedInterfaces; + else if (isa<ObjCQualifiedIdType>(T)) + ++NumObjCQualifiedIds; + else { + QualType(T, 0).dump(); + assert(0 && "Unknown type!"); + } + } + + fprintf(stderr, " %d builtin types\n", NumBuiltin); + fprintf(stderr, " %d pointer types\n", NumPointer); + fprintf(stderr, " %d reference types\n", NumReference); + fprintf(stderr, " %d complex types\n", NumComplex); + fprintf(stderr, " %d array types\n", NumArray); + fprintf(stderr, " %d vector types\n", NumVector); + fprintf(stderr, " %d function types with proto\n", NumFunctionP); + fprintf(stderr, " %d function types with no proto\n", NumFunctionNP); + fprintf(stderr, " %d typename (typedef) types\n", NumTypeName); + fprintf(stderr, " %d tagged types\n", NumTagged); + fprintf(stderr, " %d struct types\n", NumTagStruct); + fprintf(stderr, " %d union types\n", NumTagUnion); + fprintf(stderr, " %d class types\n", NumTagClass); + fprintf(stderr, " %d enum types\n", NumTagEnum); + fprintf(stderr, " %d interface types\n", NumObjCInterfaces); + fprintf(stderr, " %d protocol qualified interface types\n", + NumObjCQualifiedInterfaces); + fprintf(stderr, " %d protocol qualified id types\n", + NumObjCQualifiedIds); + fprintf(stderr, "Total bytes = %d\n", int(NumBuiltin*sizeof(BuiltinType)+ + NumPointer*sizeof(PointerType)+NumArray*sizeof(ArrayType)+ + NumComplex*sizeof(ComplexType)+NumVector*sizeof(VectorType)+ + NumFunctionP*sizeof(FunctionTypeProto)+ + NumFunctionNP*sizeof(FunctionTypeNoProto)+ + NumTypeName*sizeof(TypedefType)+NumTagged*sizeof(TagType))); +} + + +void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { + Types.push_back((R = QualType(new BuiltinType(K),0)).getTypePtr()); +} + +void ASTContext::InitBuiltinTypes() { + assert(VoidTy.isNull() && "Context reinitialized?"); + + // C99 6.2.5p19. + InitBuiltinType(VoidTy, BuiltinType::Void); + + // C99 6.2.5p2. + InitBuiltinType(BoolTy, BuiltinType::Bool); + // C99 6.2.5p3. + if (Target.isCharSigned()) + InitBuiltinType(CharTy, BuiltinType::Char_S); + else + InitBuiltinType(CharTy, BuiltinType::Char_U); + // C99 6.2.5p4. + InitBuiltinType(SignedCharTy, BuiltinType::SChar); + InitBuiltinType(ShortTy, BuiltinType::Short); + InitBuiltinType(IntTy, BuiltinType::Int); + InitBuiltinType(LongTy, BuiltinType::Long); + InitBuiltinType(LongLongTy, BuiltinType::LongLong); + + // C99 6.2.5p6. + InitBuiltinType(UnsignedCharTy, BuiltinType::UChar); + InitBuiltinType(UnsignedShortTy, BuiltinType::UShort); + InitBuiltinType(UnsignedIntTy, BuiltinType::UInt); + InitBuiltinType(UnsignedLongTy, BuiltinType::ULong); + InitBuiltinType(UnsignedLongLongTy, BuiltinType::ULongLong); + + // C99 6.2.5p10. + InitBuiltinType(FloatTy, BuiltinType::Float); + InitBuiltinType(DoubleTy, BuiltinType::Double); + InitBuiltinType(LongDoubleTy, BuiltinType::LongDouble); + + // C99 6.2.5p11. + FloatComplexTy = getComplexType(FloatTy); + DoubleComplexTy = getComplexType(DoubleTy); + LongDoubleComplexTy = getComplexType(LongDoubleTy); + + BuiltinVaListType = QualType(); + ObjCIdType = QualType(); + IdStructType = 0; + ObjCClassType = QualType(); + ClassStructType = 0; + + ObjCConstantStringType = QualType(); + + // void * type + VoidPtrTy = getPointerType(VoidTy); +} + +//===----------------------------------------------------------------------===// +// Type Sizing and Analysis +//===----------------------------------------------------------------------===// + +/// getTypeSize - Return the size of the specified type, in bits. This method +/// does not work on incomplete types. +std::pair<uint64_t, unsigned> +ASTContext::getTypeInfo(QualType T) { + T = T.getCanonicalType(); + uint64_t Width; + unsigned Align; + switch (T->getTypeClass()) { + case Type::TypeName: assert(0 && "Not a canonical type!"); + case Type::FunctionNoProto: + case Type::FunctionProto: + default: + assert(0 && "Incomplete types have no size!"); + case Type::VariableArray: + assert(0 && "VLAs not implemented yet!"); + case Type::ConstantArray: { + ConstantArrayType *CAT = cast<ConstantArrayType>(T); + + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType()); + Width = EltInfo.first*CAT->getSize().getZExtValue(); + Align = EltInfo.second; + break; + } + case Type::OCUVector: + case Type::Vector: { + std::pair<uint64_t, unsigned> EltInfo = + getTypeInfo(cast<VectorType>(T)->getElementType()); + Width = EltInfo.first*cast<VectorType>(T)->getNumElements(); + // FIXME: Vector alignment is not the alignment of its elements. + Align = EltInfo.second; + break; + } + + case Type::Builtin: + // FIXME: need to use TargetInfo to derive the target specific sizes. This + // implementation will suffice for play with vector support. + switch (cast<BuiltinType>(T)->getKind()) { + default: assert(0 && "Unknown builtin type!"); + case BuiltinType::Void: + assert(0 && "Incomplete types have no size!"); + case BuiltinType::Bool: + Width = Target.getBoolWidth(); + Align = Target.getBoolAlign(); + break; + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::SChar: + Width = Target.getCharWidth(); + Align = Target.getCharAlign(); + break; + case BuiltinType::UShort: + case BuiltinType::Short: + Width = Target.getShortWidth(); + Align = Target.getShortAlign(); + break; + case BuiltinType::UInt: + case BuiltinType::Int: + Width = Target.getIntWidth(); + Align = Target.getIntAlign(); + break; + case BuiltinType::ULong: + case BuiltinType::Long: + Width = Target.getLongWidth(); + Align = Target.getLongAlign(); + break; + case BuiltinType::ULongLong: + case BuiltinType::LongLong: + Width = Target.getLongLongWidth(); + Align = Target.getLongLongAlign(); + break; + case BuiltinType::Float: + Width = Target.getFloatWidth(); + Align = Target.getFloatAlign(); + break; + case BuiltinType::Double: + Width = Target.getDoubleWidth(); + Align = Target.getDoubleAlign(); + break; + case BuiltinType::LongDouble: + Width = Target.getLongDoubleWidth(); + Align = Target.getLongDoubleAlign(); + break; + } + break; + case Type::ASQual: + // FIXME: Pointers into different addr spaces could have different sizes and + // alignment requirements: getPointerInfo should take an AddrSpace. + return getTypeInfo(QualType(cast<ASQualType>(T)->getBaseType(), 0)); + case Type::ObjCQualifiedId: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; + case Type::Pointer: { + unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::Reference: + // "When applied to a reference or a reference type, the result is the size + // of the referenced type." C++98 5.3.3p2: expr.sizeof. + // FIXME: This is wrong for struct layout: a reference in a struct has + // pointer size. + return getTypeInfo(cast<ReferenceType>(T)->getReferenceeType()); + + case Type::Complex: { + // Complex types have the same alignment as their elements, but twice the + // size. + std::pair<uint64_t, unsigned> EltInfo = + getTypeInfo(cast<ComplexType>(T)->getElementType()); + Width = EltInfo.first*2; + Align = EltInfo.second; + break; + } + case Type::Tagged: + TagType *TT = cast<TagType>(T); + if (RecordType *RT = dyn_cast<RecordType>(TT)) { + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); + Width = Layout.getSize(); + Align = Layout.getAlignment(); + } else if (EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) { + return getTypeInfo(ED->getIntegerType()); + } else { + assert(0 && "Unimplemented type sizes!"); + } + break; + } + + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); + return std::make_pair(Width, Align); +} + +/// getASTRecordLayout - Get or compute information about the layout of the +/// specified record (struct/union/class), which indicates its size and field +/// position information. +const ASTRecordLayout &ASTContext::getASTRecordLayout(const RecordDecl *D) { + assert(D->isDefinition() && "Cannot get layout of forward declarations!"); + + // Look up this layout, if already laid out, return what we have. + const ASTRecordLayout *&Entry = ASTRecordLayouts[D]; + if (Entry) return *Entry; + + // Allocate and assign into ASTRecordLayouts here. The "Entry" reference can + // be invalidated (dangle) if the ASTRecordLayouts hashtable is inserted into. + ASTRecordLayout *NewEntry = new ASTRecordLayout(); + Entry = NewEntry; + + uint64_t *FieldOffsets = new uint64_t[D->getNumMembers()]; + uint64_t RecordSize = 0; + unsigned RecordAlign = 8; // Default alignment = 1 byte = 8 bits. + + if (D->getKind() != Decl::Union) { + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + RecordAlign = std::max(RecordAlign, AA->getAlignment()); + + bool StructIsPacked = D->getAttr<PackedAttr>(); + + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + bool FieldIsPacked = StructIsPacked || FD->getAttr<PackedAttr>(); + uint64_t FieldSize; + unsigned FieldAlign; + + if (const Expr *BitWidthExpr = FD->getBitWidth()) { + llvm::APSInt I(32); + bool BitWidthIsICE = + BitWidthExpr->isIntegerConstantExpr(I, *this); + assert (BitWidthIsICE && "Invalid BitField size expression"); + FieldSize = I.getZExtValue(); + + std::pair<uint64_t, unsigned> TypeInfo = getTypeInfo(FD->getType()); + uint64_t TypeSize = TypeInfo.first; + + if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else { + // FIXME: This is X86 specific, use 32-bit alignment for long long. + if (FD->getType()->isIntegerType() && TypeInfo.second > 32) + FieldAlign = 32; + else + FieldAlign = TypeInfo.second; + } + + // Check if we need to add padding to give the field the correct + // alignment. + if (RecordSize % FieldAlign + FieldSize > TypeSize) + RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); + + } else { + if (FD->getType()->isIncompleteType()) { + // This must be a flexible array member; we can't directly + // query getTypeInfo about these, so we figure it out here. + // Flexible array members don't have any size, but they + // have to be aligned appropriately for their element type. + + if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else { + const ArrayType* ATy = FD->getType()->getAsArrayType(); + FieldAlign = getTypeAlign(ATy->getElementType()); + } + FieldSize = 0; + } else { + std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType()); + FieldSize = FieldInfo.first; + + if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) + FieldAlign = AA->getAlignment(); + else if (FieldIsPacked) + FieldAlign = 8; + else + FieldAlign = FieldInfo.second; + } + + // Round up the current record size to the field's alignment boundary. + RecordSize = (RecordSize+FieldAlign-1) & ~(FieldAlign-1); + } + + // Place this field at the current location. + FieldOffsets[i] = RecordSize; + + // Reserve space for this field. + RecordSize += FieldSize; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + RecordSize = (RecordSize+RecordAlign-1) & ~(RecordAlign-1); + } else { + // Union layout just puts each member at the start of the record. + for (unsigned i = 0, e = D->getNumMembers(); i != e; ++i) { + const FieldDecl *FD = D->getMember(i); + std::pair<uint64_t, unsigned> FieldInfo = getTypeInfo(FD->getType()); + uint64_t FieldSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + // FIXME: This is X86 specific, use 32-bit alignment for long long. + if (FD->getType()->isIntegerType() && FieldAlign > 32) + FieldAlign = 32; + + // Round up the current record size to the field's alignment boundary. + RecordSize = std::max(RecordSize, FieldSize); + + // Place this field at the start of the record. + FieldOffsets[i] = 0; + + // Remember max struct/class alignment. + RecordAlign = std::max(RecordAlign, FieldAlign); + } + } + + NewEntry->SetLayout(RecordSize, RecordAlign, FieldOffsets); + return *NewEntry; +} + +//===----------------------------------------------------------------------===// +// Type creation/memoization methods +//===----------------------------------------------------------------------===// + +QualType ASTContext::getASQualType(QualType T, unsigned AddressSpace) { + if (T.getCanonicalType().getAddressSpace() == AddressSpace) + return T; + + // Type's cannot have multiple ASQuals, therefore we know we only have to deal + // with CVR qualifiers from here on out. + assert(T.getCanonicalType().getAddressSpace() == 0 && + "Type is already address space qualified"); + + // Check if we've already instantiated an address space qual'd type of this + // type. + llvm::FoldingSetNodeID ID; + ASQualType::Profile(ID, T.getTypePtr(), AddressSpace); + void *InsertPos = 0; + if (ASQualType *ASQy = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ASQy, 0); + + // If the base type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getASQualType(T.getCanonicalType(), AddressSpace); + + // Get the new insert position for the node we care about. + ASQualType *NewIP = ASQualTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + ASQualType *New = new ASQualType(T.getTypePtr(), Canonical, AddressSpace); + ASQualTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, T.getCVRQualifiers()); +} + + +/// getComplexType - Return the uniqued reference to the type for a complex +/// number with the specified element type. +QualType ASTContext::getComplexType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ComplexType::Profile(ID, T); + + void *InsertPos = 0; + if (ComplexType *CT = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(CT, 0); + + // If the pointee type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getComplexType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + ComplexType *NewIP = ComplexTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + ComplexType *New = new ComplexType(T, Canonical); + Types.push_back(New); + ComplexTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + + +/// getPointerType - Return the uniqued reference to the type for a pointer to +/// the specified type. +QualType ASTContext::getPointerType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + PointerType::Profile(ID, T); + + void *InsertPos = 0; + if (PointerType *PT = PointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the pointee type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getPointerType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + PointerType *NewIP = PointerTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + PointerType *New = new PointerType(T, Canonical); + Types.push_back(New); + PointerTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getReferenceType - Return the uniqued reference to the type for a reference +/// to the specified type. +QualType ASTContext::getReferenceType(QualType T) { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ReferenceType::Profile(ID, T); + + void *InsertPos = 0; + if (ReferenceType *RT = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(RT, 0); + + // If the referencee type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getReferenceType(T.getCanonicalType()); + + // Get the new insert position for the node we care about. + ReferenceType *NewIP = ReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + ReferenceType *New = new ReferenceType(T, Canonical); + Types.push_back(New); + ReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getConstantArrayType - Return the unique reference to the type for an +/// array of the specified element type. +QualType ASTContext::getConstantArrayType(QualType EltTy, + const llvm::APInt &ArySize, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + llvm::FoldingSetNodeID ID; + ConstantArrayType::Profile(ID, EltTy, ArySize); + + void *InsertPos = 0; + if (ConstantArrayType *ATP = + ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!EltTy->isCanonical()) { + Canonical = getConstantArrayType(EltTy.getCanonicalType(), ArySize, + ASM, EltTypeQuals); + // Get the new insert position for the node we care about. + ConstantArrayType *NewIP = + ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + ConstantArrayType *New = new ConstantArrayType(EltTy, Canonical, ArySize, + ASM, EltTypeQuals); + ConstantArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getVariableArrayType - Returns a non-unique reference to the type for a +/// variable array of the specified element type. +QualType ASTContext::getVariableArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + + VariableArrayType *New = new VariableArrayType(EltTy, QualType(), NumElts, + ASM, EltTypeQuals); + + VariableArrayTypes.push_back(New); + Types.push_back(New); + return QualType(New, 0); +} + +QualType ASTContext::getIncompleteArrayType(QualType EltTy, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + llvm::FoldingSetNodeID ID; + IncompleteArrayType::Profile(ID, EltTy); + + void *InsertPos = 0; + if (IncompleteArrayType *ATP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. + QualType Canonical; + + if (!EltTy->isCanonical()) { + Canonical = getIncompleteArrayType(EltTy.getCanonicalType(), + ASM, EltTypeQuals); + + // Get the new insert position for the node we care about. + IncompleteArrayType *NewIP = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, InsertPos); + + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + IncompleteArrayType *New = new IncompleteArrayType(EltTy, Canonical, + ASM, EltTypeQuals); + + IncompleteArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getVectorType - Return the unique reference to a vector type of +/// the specified element type and size. VectorType must be a built-in type. +QualType ASTContext::getVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr()); + assert(baseType != 0 && "getVectorType(): Expecting a built-in type"); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::Vector); + void *InsertPos = 0; + if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(VTP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!vecType->isCanonical()) { + Canonical = getVectorType(vecType.getCanonicalType(), NumElts); + + // Get the new insert position for the node we care about. + VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + VectorType *New = new VectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getOCUVectorType - Return the unique reference to an OCU vector type of +/// the specified element type and size. VectorType must be a built-in type. +QualType ASTContext::getOCUVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast<BuiltinType>(vecType.getCanonicalType().getTypePtr()); + assert(baseType != 0 && "getOCUVectorType(): Expecting a built-in type"); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::OCUVector); + void *InsertPos = 0; + if (VectorType *VTP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(VTP, 0); + + // If the element type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + QualType Canonical; + if (!vecType->isCanonical()) { + Canonical = getOCUVectorType(vecType.getCanonicalType(), NumElts); + + // Get the new insert position for the node we care about. + VectorType *NewIP = VectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + OCUVectorType *New = new OCUVectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getFunctionTypeNoProto - Return a K&R style C function type like 'int()'. +/// +QualType ASTContext::getFunctionTypeNoProto(QualType ResultTy) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionTypeNoProto::Profile(ID, ResultTy); + + void *InsertPos = 0; + if (FunctionTypeNoProto *FT = + FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FT, 0); + + QualType Canonical; + if (!ResultTy->isCanonical()) { + Canonical = getFunctionTypeNoProto(ResultTy.getCanonicalType()); + + // Get the new insert position for the node we care about. + FunctionTypeNoProto *NewIP = + FunctionTypeNoProtos.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + FunctionTypeNoProto *New = new FunctionTypeNoProto(ResultTy, Canonical); + Types.push_back(New); + FunctionTypeNoProtos.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getFunctionType - Return a normal function type with a typed argument +/// list. isVariadic indicates whether the argument list includes '...'. +QualType ASTContext::getFunctionType(QualType ResultTy, QualType *ArgArray, + unsigned NumArgs, bool isVariadic) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionTypeProto::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic); + + void *InsertPos = 0; + if (FunctionTypeProto *FTP = + FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FTP, 0); + + // Determine whether the type being created is already canonical or not. + bool isCanonical = ResultTy->isCanonical(); + for (unsigned i = 0; i != NumArgs && isCanonical; ++i) + if (!ArgArray[i]->isCanonical()) + isCanonical = false; + + // If this type isn't canonical, get the canonical version of it. + QualType Canonical; + if (!isCanonical) { + llvm::SmallVector<QualType, 16> CanonicalArgs; + CanonicalArgs.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + CanonicalArgs.push_back(ArgArray[i].getCanonicalType()); + + Canonical = getFunctionType(ResultTy.getCanonicalType(), + &CanonicalArgs[0], NumArgs, + isVariadic); + + // Get the new insert position for the node we care about. + FunctionTypeProto *NewIP = + FunctionTypeProtos.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); + } + + // FunctionTypeProto objects are not allocated with new because they have a + // variable size array (for parameter types) at the end of them. + FunctionTypeProto *FTP = + (FunctionTypeProto*)malloc(sizeof(FunctionTypeProto) + + NumArgs*sizeof(QualType)); + new (FTP) FunctionTypeProto(ResultTy, ArgArray, NumArgs, isVariadic, + Canonical); + Types.push_back(FTP); + FunctionTypeProtos.InsertNode(FTP, InsertPos); + return QualType(FTP, 0); +} + +/// getTypedefType - Return the unique reference to the type for the +/// specified typename decl. +QualType ASTContext::getTypedefType(TypedefDecl *Decl) { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + QualType Canonical = Decl->getUnderlyingType().getCanonicalType(); + Decl->TypeForDecl = new TypedefType(Type::TypeName, Decl, Canonical); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// getObjCInterfaceType - Return the unique reference to the type for the +/// specified ObjC interface decl. +QualType ASTContext::getObjCInterfaceType(ObjCInterfaceDecl *Decl) { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + Decl->TypeForDecl = new ObjCInterfaceType(Type::ObjCInterface, Decl); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// getObjCQualifiedInterfaceType - Return a +/// ObjCQualifiedInterfaceType type for the given interface decl and +/// the conforming protocol list. +QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **Protocols, unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjCQualifiedInterfaceType::Profile(ID, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCQualifiedInterfaceType *QT = + ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + ObjCQualifiedInterfaceType *QType = + new ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); + Types.push_back(QType); + ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getObjCQualifiedIdType - Return a +/// getObjCQualifiedIdType type for the 'id' decl and +/// the conforming protocol list. +QualType ASTContext::getObjCQualifiedIdType(QualType idType, + ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + llvm::FoldingSetNodeID ID; + ObjCQualifiedIdType::Profile(ID, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCQualifiedIdType *QT = + ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + QualType Canonical; + if (!idType->isCanonical()) { + Canonical = getObjCQualifiedIdType(idType.getCanonicalType(), + Protocols, NumProtocols); + ObjCQualifiedIdType *NewQT = + ObjCQualifiedIdTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewQT == 0 && "Shouldn't be in the map!"); + } + + ObjCQualifiedIdType *QType = + new ObjCQualifiedIdType(Canonical, Protocols, NumProtocols); + Types.push_back(QType); + ObjCQualifiedIdTypes.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 +/// DeclRefExpr's. This doesn't effect the type checker, since it operates +/// on canonical type's (which are always unique). +QualType ASTContext::getTypeOfExpr(Expr *tofExpr) { + QualType Canonical = tofExpr->getType().getCanonicalType(); + TypeOfExpr *toe = new TypeOfExpr(tofExpr, Canonical); + Types.push_back(toe); + return QualType(toe, 0); +} + +/// getTypeOfType - Unlike many "get<Type>" functions, we don't unique +/// TypeOfType AST's. The only motivation to unique these nodes would be +/// memory savings. Since typeof(t) is fairly uncommon, space shouldn't be +/// an issue. This doesn't effect the type checker, since it operates +/// on canonical type's (which are always unique). +QualType ASTContext::getTypeOfType(QualType tofType) { + QualType Canonical = tofType.getCanonicalType(); + TypeOfType *tot = new TypeOfType(tofType, Canonical); + Types.push_back(tot); + return QualType(tot, 0); +} + +/// getTagDeclType - Return the unique reference to the type for the +/// specified TagDecl (struct/union/class/enum) decl. +QualType ASTContext::getTagDeclType(TagDecl *Decl) { + assert (Decl); + + // The decl stores the type cache. + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + TagType* T = new TagType(Decl, QualType()); + Types.push_back(T); + Decl->TypeForDecl = T; + + return QualType(T, 0); +} + +/// getSizeType - Return the unique type for "size_t" (C99 7.17), the result +/// of the sizeof operator (C99 6.5.3.4p4). The value is target dependent and +/// needs to agree with the definition in <stddef.h>. +QualType ASTContext::getSizeType() const { + // On Darwin, size_t is defined as a "long unsigned int". + // FIXME: should derive from "Target". + return UnsignedLongTy; +} + +/// getWcharType - Return the unique type for "wchar_t" (C99 7.17), the +/// width of characters in wide strings, The value is target dependent and +/// needs to agree with the definition in <stddef.h>. +QualType ASTContext::getWcharType() const { + // On Darwin, wchar_t is defined as a "int". + // FIXME: should derive from "Target". + return IntTy; +} + +/// getPointerDiffType - Return the unique type for "ptrdiff_t" (ref?) +/// defined in <stddef.h>. Pointer - pointer requires this (C99 6.5.6p9). +QualType ASTContext::getPointerDiffType() const { + // On Darwin, ptrdiff_t is defined as a "int". This seems like a bug... + // FIXME: should derive from "Target". + return IntTy; +} + +/// getIntegerRank - Return an integer conversion rank (C99 6.3.1.1p1). This +/// routine will assert if passed a built-in type that isn't an integer or enum. +static int getIntegerRank(QualType t) { + if (const TagType *TT = dyn_cast<TagType>(t.getCanonicalType())) { + assert(TT->getDecl()->getKind() == Decl::Enum && "not an int or enum"); + return 4; + } + + const BuiltinType *BT = t.getCanonicalType()->getAsBuiltinType(); + switch (BT->getKind()) { + default: + assert(0 && "getIntegerRank(): not a built-in integer"); + case BuiltinType::Bool: + return 1; + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + return 2; + case BuiltinType::Short: + case BuiltinType::UShort: + return 3; + case BuiltinType::Int: + case BuiltinType::UInt: + return 4; + case BuiltinType::Long: + case BuiltinType::ULong: + return 5; + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + return 6; + } +} + +/// getFloatingRank - Return a relative rank for floating point types. +/// This routine will assert if passed a built-in type that isn't a float. +static int getFloatingRank(QualType T) { + T = T.getCanonicalType(); + if (const ComplexType *CT = T->getAsComplexType()) + return getFloatingRank(CT->getElementType()); + + switch (T->getAsBuiltinType()->getKind()) { + default: assert(0 && "getFloatingRank(): not a floating type"); + case BuiltinType::Float: return FloatRank; + case BuiltinType::Double: return DoubleRank; + case BuiltinType::LongDouble: return LongDoubleRank; + } +} + +/// getFloatingTypeOfSizeWithinDomain - Returns a real floating +/// point or a complex type (based on typeDomain/typeSize). +/// 'typeDomain' is a real floating point or complex type. +/// 'typeSize' is a real floating point or complex type. +QualType ASTContext::getFloatingTypeOfSizeWithinDomain( + QualType typeSize, QualType typeDomain) const { + if (typeDomain->isComplexType()) { + switch (getFloatingRank(typeSize)) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatComplexTy; + case DoubleRank: return DoubleComplexTy; + case LongDoubleRank: return LongDoubleComplexTy; + } + } + if (typeDomain->isRealFloatingType()) { + switch (getFloatingRank(typeSize)) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatTy; + case DoubleRank: return DoubleTy; + case LongDoubleRank: return LongDoubleTy; + } + } + assert(0 && "getFloatingTypeOfSizeWithinDomain(): illegal domain"); + //an invalid return value, but the assert + //will ensure that this code is never reached. + return VoidTy; +} + +/// compareFloatingType - Handles 3 different combos: +/// float/float, float/complex, complex/complex. +/// If lt > rt, return 1. If lt == rt, return 0. If lt < rt, return -1. +int ASTContext::compareFloatingType(QualType lt, QualType rt) { + if (getFloatingRank(lt) == getFloatingRank(rt)) + return 0; + if (getFloatingRank(lt) > getFloatingRank(rt)) + return 1; + return -1; +} + +// maxIntegerType - Returns the highest ranked integer type. Handles 3 case: +// unsigned/unsigned, signed/signed, signed/unsigned. C99 6.3.1.8p1. +QualType ASTContext::maxIntegerType(QualType lhs, QualType rhs) { + if (lhs == rhs) return lhs; + + bool t1Unsigned = lhs->isUnsignedIntegerType(); + bool t2Unsigned = rhs->isUnsignedIntegerType(); + + if ((t1Unsigned && t2Unsigned) || (!t1Unsigned && !t2Unsigned)) + return getIntegerRank(lhs) >= getIntegerRank(rhs) ? lhs : rhs; + + // We have two integer types with differing signs + QualType unsignedType = t1Unsigned ? lhs : rhs; + QualType signedType = t1Unsigned ? rhs : lhs; + + if (getIntegerRank(unsignedType) >= getIntegerRank(signedType)) + return unsignedType; + else { + // FIXME: Need to check if the signed type can represent all values of the + // unsigned type. If it can, then the result is the signed type. + // If it can't, then the result is the unsigned version of the signed type. + // Should probably add a helper that returns a signed integer type from + // an unsigned (and vice versa). C99 6.3.1.8. + return signedType; + } +} + +// getCFConstantStringType - Return the type used for constant CFStrings. +QualType ASTContext::getCFConstantStringType() { + if (!CFConstantStringTypeDecl) { + CFConstantStringTypeDecl = + RecordDecl::Create(*this, Decl::Struct, SourceLocation(), + &Idents.get("NSConstantString"), 0); + QualType FieldTypes[4]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.getQualifiedType(QualType::Const)); + // int flags; + FieldTypes[1] = IntTy; + // const char *str; + FieldTypes[2] = getPointerType(CharTy.getQualifiedType(QualType::Const)); + // long length; + FieldTypes[3] = LongTy; + // Create fields + FieldDecl *FieldDecls[4]; + + for (unsigned i = 0; i < 4; ++i) + FieldDecls[i] = new FieldDecl(SourceLocation(), 0, FieldTypes[i]); + + CFConstantStringTypeDecl->defineBody(FieldDecls, 4); + } + + return getTagDeclType(CFConstantStringTypeDecl); +} + +// This returns true if a type has been typedefed to BOOL: +// typedef <type> BOOL; +static bool isTypeTypedefedAsBOOL(QualType T) { + if (const TypedefType *TT = dyn_cast<TypedefType>(T)) + return !strcmp(TT->getDecl()->getName(), "BOOL"); + + return false; +} + +/// getObjCEncodingTypeSize returns size of type for objective-c encoding +/// purpose. +int ASTContext::getObjCEncodingTypeSize(QualType type) { + uint64_t sz = getTypeSize(type); + + // Make all integer and enum types at least as large as an int + if (sz > 0 && type->isIntegralType()) + sz = std::max(sz, getTypeSize(IntTy)); + // Treat arrays as pointers, since that's how they're passed in. + else if (type->isArrayType()) + sz = getTypeSize(VoidPtrTy); + return sz / getTypeSize(CharTy); +} + +/// getObjCEncodingForMethodDecl - Return the encoded type for this method +/// declaration. +void ASTContext::getObjCEncodingForMethodDecl(ObjCMethodDecl *Decl, + std::string& S) +{ + // Encode type qualifer, 'in', 'inout', etc. for the return type. + getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); + // Encode result type. + getObjCEncodingForType(Decl->getResultType(), S, EncodingRecordTypes); + // Compute size of all parameters. + // Start with computing size of a pointer in number of bytes. + // FIXME: There might(should) be a better way of doing this computation! + SourceLocation Loc; + int PtrSize = getTypeSize(VoidPtrTy) / getTypeSize(CharTy); + // The first two arguments (self and _cmd) are pointers; account for + // their size. + int ParmOffset = 2 * PtrSize; + int NumOfParams = Decl->getNumParams(); + for (int i = 0; i < NumOfParams; i++) { + QualType PType = Decl->getParamDecl(i)->getType(); + int sz = getObjCEncodingTypeSize (PType); + assert (sz > 0 && "getObjCEncodingForMethodDecl - Incomplete param type"); + ParmOffset += sz; + } + S += llvm::utostr(ParmOffset); + S += "@0:"; + S += llvm::utostr(PtrSize); + + // Argument types. + ParmOffset = 2 * PtrSize; + for (int i = 0; i < NumOfParams; i++) { + QualType PType = Decl->getParamDecl(i)->getType(); + // Process argument qualifiers for user supplied arguments; such as, + // 'in', 'inout', etc. + getObjCEncodingForTypeQualifier( + Decl->getParamDecl(i)->getObjCDeclQualifier(), S); + getObjCEncodingForType(PType, S, EncodingRecordTypes); + S += llvm::utostr(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } +} + +void ASTContext::getObjCEncodingForType(QualType T, std::string& S, + llvm::SmallVector<const RecordType *, 8> &ERType) const +{ + // FIXME: This currently doesn't encode: + // @ An object (whether statically typed or typed id) + // # A class object (Class) + // : A method selector (SEL) + // {name=type...} A structure + // (name=type...) A union + // bnum A bit field of num bits + + if (const BuiltinType *BT = T->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 (T->isObjCQualifiedIdType()) { + // Treat id<P...> same as 'id' for encoding purposes. + return getObjCEncodingForType(getObjCIdType(), S, ERType); + + } + else if (const PointerType *PT = T->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isObjCInterfaceType()) { + S += '@'; + return; + } else if (isObjCClassType(PointeeTy)) { + S += '#'; + return; + } else if (isObjCSelType(PointeeTy)) { + S += ':'; + return; + } + + if (PointeeTy->isCharType()) { + // char pointer types should be encoded as '*' unless it is a + // type that has been typedef'd to 'BOOL'. + if (!isTypeTypedefedAsBOOL(PointeeTy)) { + S += '*'; + return; + } + } + + S += '^'; + getObjCEncodingForType(PT->getPointeeType(), S, ERType); + } else if (const ArrayType *AT = T->getAsArrayType()) { + S += '['; + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else + assert(0 && "Unhandled array type!"); + + getObjCEncodingForType(AT->getElementType(), S, ERType); + S += ']'; + } else if (T->getAsFunctionType()) { + S += '?'; + } else if (const RecordType *RTy = T->getAsRecordType()) { + RecordDecl *RDecl= RTy->getDecl(); + S += '{'; + S += RDecl->getName(); + bool found = false; + for (unsigned i = 0, e = ERType.size(); i != e; ++i) + if (ERType[i] == RTy) { + found = true; + break; + } + if (!found) { + ERType.push_back(RTy); + S += '='; + for (int i = 0; i < RDecl->getNumMembers(); i++) { + FieldDecl *field = RDecl->getMember(i); + getObjCEncodingForType(field->getType(), S, ERType); + } + assert(ERType.back() == RTy && "Record Type stack mismatch."); + ERType.pop_back(); + } + S += '}'; + } else if (T->isEnumeralType()) { + S += 'i'; + } else + assert(0 && "@encode for type not implemented!"); +} + +void ASTContext::getObjCEncodingForTypeQualifier(Decl::ObjCDeclQualifier QT, + std::string& S) const { + if (QT & Decl::OBJC_TQ_In) + S += 'n'; + if (QT & Decl::OBJC_TQ_Inout) + S += 'N'; + if (QT & Decl::OBJC_TQ_Out) + S += 'o'; + if (QT & Decl::OBJC_TQ_Bycopy) + S += 'O'; + if (QT & Decl::OBJC_TQ_Byref) + S += 'R'; + if (QT & Decl::OBJC_TQ_Oneway) + S += 'V'; +} + +void ASTContext::setBuiltinVaListType(QualType T) +{ + assert(BuiltinVaListType.isNull() && "__builtin_va_list type already set!"); + + BuiltinVaListType = T; +} + +void ASTContext::setObjCIdType(TypedefDecl *TD) +{ + assert(ObjCIdType.isNull() && "'id' type already set!"); + + ObjCIdType = getTypedefType(TD); + + // typedef struct objc_object *id; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'id' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'id' incorrectly typed"); + IdStructType = rec; +} + +void ASTContext::setObjCSelType(TypedefDecl *TD) +{ + assert(ObjCSelType.isNull() && "'SEL' type already set!"); + + ObjCSelType = getTypedefType(TD); + + // typedef struct objc_selector *SEL; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'SEL' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'SEL' incorrectly typed"); + SelStructType = rec; +} + +void ASTContext::setObjCProtoType(QualType QT) +{ + assert(ObjCProtoType.isNull() && "'Protocol' type already set!"); + ObjCProtoType = QT; +} + +void ASTContext::setObjCClassType(TypedefDecl *TD) +{ + assert(ObjCClassType.isNull() && "'Class' type already set!"); + + ObjCClassType = getTypedefType(TD); + + // typedef struct objc_class *Class; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + assert(ptr && "'Class' incorrectly typed"); + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + assert(rec && "'Class' incorrectly typed"); + ClassStructType = rec; +} + +void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { + assert(ObjCConstantStringType.isNull() && + "'NSConstantString' type already set!"); + + ObjCConstantStringType = getObjCInterfaceType(Decl); +} + +bool ASTContext::builtinTypesAreCompatible(QualType lhs, QualType rhs) { + const BuiltinType *lBuiltin = lhs->getAsBuiltinType(); + const BuiltinType *rBuiltin = rhs->getAsBuiltinType(); + + return lBuiltin->getKind() == rBuiltin->getKind(); +} + +/// objcTypesAreCompatible - This routine is called when two types +/// are of different class; one is interface type or is +/// a qualified interface type and the other type is of a different class. +/// Example, II or II<P>. +bool ASTContext::objcTypesAreCompatible(QualType lhs, QualType rhs) { + if (lhs->isObjCInterfaceType() && isObjCIdType(rhs)) + return true; + else if (isObjCIdType(lhs) && rhs->isObjCInterfaceType()) + return true; + if (ObjCInterfaceType *lhsIT = + dyn_cast<ObjCInterfaceType>(lhs.getCanonicalType().getTypePtr())) { + ObjCQualifiedInterfaceType *rhsQI = + dyn_cast<ObjCQualifiedInterfaceType>(rhs.getCanonicalType().getTypePtr()); + return rhsQI && (lhsIT->getDecl() == rhsQI->getDecl()); + } + else if (ObjCInterfaceType *rhsIT = + dyn_cast<ObjCInterfaceType>(rhs.getCanonicalType().getTypePtr())) { + ObjCQualifiedInterfaceType *lhsQI = + dyn_cast<ObjCQualifiedInterfaceType>(lhs.getCanonicalType().getTypePtr()); + return lhsQI && (rhsIT->getDecl() == lhsQI->getDecl()); + } + return false; +} + +/// Check that 'lhs' and 'rhs' are compatible interface types. Both types +/// must be canonical types. +bool ASTContext::interfaceTypesAreCompatible(QualType lhs, QualType rhs) { + assert (lhs->isCanonical() && + "interfaceTypesAreCompatible strip typedefs of lhs"); + assert (rhs->isCanonical() && + "interfaceTypesAreCompatible strip typedefs of rhs"); + if (lhs == rhs) + return true; + ObjCInterfaceType *lhsIT = cast<ObjCInterfaceType>(lhs.getTypePtr()); + ObjCInterfaceType *rhsIT = cast<ObjCInterfaceType>(rhs.getTypePtr()); + ObjCInterfaceDecl *rhsIDecl = rhsIT->getDecl(); + ObjCInterfaceDecl *lhsIDecl = lhsIT->getDecl(); + // rhs is derived from lhs it is OK; else it is not OK. + while (rhsIDecl != NULL) { + if (rhsIDecl == lhsIDecl) + return true; + rhsIDecl = rhsIDecl->getSuperClass(); + } + return false; +} + +bool ASTContext::QualifiedInterfaceTypesAreCompatible(QualType lhs, + QualType rhs) { + ObjCQualifiedInterfaceType *lhsQI = + dyn_cast<ObjCQualifiedInterfaceType>(lhs.getCanonicalType().getTypePtr()); + assert(lhsQI && "QualifiedInterfaceTypesAreCompatible - bad lhs type"); + ObjCQualifiedInterfaceType *rhsQI = + dyn_cast<ObjCQualifiedInterfaceType>(rhs.getCanonicalType().getTypePtr()); + assert(rhsQI && "QualifiedInterfaceTypesAreCompatible - bad rhs type"); + if (!interfaceTypesAreCompatible( + getObjCInterfaceType(lhsQI->getDecl()).getCanonicalType(), + getObjCInterfaceType(rhsQI->getDecl()).getCanonicalType())) + return false; + /* All protocols in lhs must have a presense in rhs. */ + for (unsigned i =0; i < lhsQI->getNumProtocols(); i++) { + bool match = false; + ObjCProtocolDecl *lhsProto = lhsQI->getProtocols(i); + for (unsigned j = 0; j < rhsQI->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQI->getProtocols(j); + if (lhsProto == rhsProto) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; +} + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) { + if (lProto == rProto) + return true; + ObjCProtocolDecl** RefPDecl = rProto->getReferencedProtocols(); + for (unsigned i = 0; i < rProto->getNumReferencedProtocols(); i++) + if (ProtocolCompatibleWithProtocol(lProto, RefPDecl[i])) + return true; + return false; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, + ObjCInterfaceDecl *IDecl, + bool lookupCategory) { + + // 1st, look up the class. + ObjCProtocolDecl **protoList = IDecl->getReferencedProtocols(); + for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) { + if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + protoList = CDecl->getReferencedProtocols(); + for (unsigned i = 0; i < CDecl->getNumReferencedProtocols(); i++) { + if (ProtocolCompatibleWithProtocol(lProto, protoList[i])) + return true; + } + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory); + + return false; +} + +/// ObjCQualifiedIdTypesAreCompatible - Compares two types, at least +/// one of which is a protocol qualified 'id' type. When 'compare' +/// is true it is for comparison; when false, for assignment/initialization. +bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, + QualType rhs, + bool compare) { + // match id<P..> with an 'id' type in all cases. + if (const PointerType *PT = lhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + + } + else if (const PointerType *PT = rhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + + } + + ObjCQualifiedInterfaceType *lhsQI = 0; + ObjCQualifiedInterfaceType *rhsQI = 0; + ObjCInterfaceDecl *lhsID = 0; + ObjCInterfaceDecl *rhsID = 0; + ObjCQualifiedIdType *lhsQID = dyn_cast<ObjCQualifiedIdType>(lhs); + ObjCQualifiedIdType *rhsQID = dyn_cast<ObjCQualifiedIdType>(rhs); + + if (lhsQID) { + if (!rhsQID && rhs->getTypeClass() == Type::Pointer) { + QualType rtype = + cast<PointerType>(rhs.getCanonicalType())->getPointeeType(); + rhsQI = + dyn_cast<ObjCQualifiedInterfaceType>( + rtype.getCanonicalType().getTypePtr()); + if (!rhsQI) { + ObjCInterfaceType *IT = dyn_cast<ObjCInterfaceType>( + rtype.getCanonicalType().getTypePtr()); + if (IT) + rhsID = IT->getDecl(); + } + } + if (!rhsQI && !rhsQID && !rhsID) + return false; + + unsigned numRhsProtocols = 0; + ObjCProtocolDecl **rhsProtoList = 0; + if (rhsQI) { + numRhsProtocols = rhsQI->getNumProtocols(); + rhsProtoList = rhsQI->getReferencedProtocols(); + } + else if (rhsQID) { + numRhsProtocols = rhsQID->getNumProtocols(); + rhsProtoList = rhsQID->getReferencedProtocols(); + } + + for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { + ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); + bool match = false; + + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (rhsID) { + if (ClassImplementsProtocol(lhsProto, rhsID, true)) + match = true; + } + else for (unsigned j = 0; j < numRhsProtocols; j++) { + ObjCProtocolDecl *rhsProto = rhsProtoList[j]; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + if (!match) + return false; + } + } + else if (rhsQID) { + if (!lhsQID && lhs->getTypeClass() == Type::Pointer) { + QualType ltype = + cast<PointerType>(lhs.getCanonicalType())->getPointeeType(); + lhsQI = + dyn_cast<ObjCQualifiedInterfaceType>( + ltype.getCanonicalType().getTypePtr()); + if (!lhsQI) { + ObjCInterfaceType *IT = dyn_cast<ObjCInterfaceType>( + ltype.getCanonicalType().getTypePtr()); + if (IT) + lhsID = IT->getDecl(); + } + } + if (!lhsQI && !lhsQID && !lhsID) + return false; + + unsigned numLhsProtocols = 0; + ObjCProtocolDecl **lhsProtoList = 0; + if (lhsQI) { + numLhsProtocols = lhsQI->getNumProtocols(); + lhsProtoList = lhsQI->getReferencedProtocols(); + } + else if (lhsQID) { + numLhsProtocols = lhsQID->getNumProtocols(); + lhsProtoList = lhsQID->getReferencedProtocols(); + } + bool match = false; + // for static type vs. qualified 'id' type, check that class implements + // one of 'id's protocols. + if (lhsID) { + for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); + if (ClassImplementsProtocol(rhsProto, lhsID, compare)) { + match = true; + break; + } + } + } + else for (unsigned i =0; i < numLhsProtocols; i++) { + match = false; + ObjCProtocolDecl *lhsProto = lhsProtoList[i]; + for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + return true; +} + +bool ASTContext::vectorTypesAreCompatible(QualType lhs, QualType rhs) { + const VectorType *lVector = lhs->getAsVectorType(); + const VectorType *rVector = rhs->getAsVectorType(); + + if ((lVector->getElementType().getCanonicalType() == + rVector->getElementType().getCanonicalType()) && + (lVector->getNumElements() == rVector->getNumElements())) + return true; + return false; +} + +// C99 6.2.7p1: If both are complete types, then the following additional +// requirements apply...FIXME (handle compatibility across source files). +bool ASTContext::tagTypesAreCompatible(QualType lhs, QualType rhs) { + // "Class" and "id" are compatible built-in structure types. + if (isObjCIdType(lhs) && isObjCClassType(rhs) || + isObjCClassType(lhs) && isObjCIdType(rhs)) + return true; + + // Within a translation unit a tag type is + // only compatible with itself. + return lhs.getCanonicalType() == rhs.getCanonicalType(); +} + +bool ASTContext::pointerTypesAreCompatible(QualType lhs, QualType rhs) { + // C99 6.7.5.1p2: For two pointer types to be compatible, both shall be + // identically qualified and both shall be pointers to compatible types. + if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || + lhs.getAddressSpace() != rhs.getAddressSpace()) + return false; + + QualType ltype = cast<PointerType>(lhs.getCanonicalType())->getPointeeType(); + QualType rtype = cast<PointerType>(rhs.getCanonicalType())->getPointeeType(); + + return typesAreCompatible(ltype, rtype); +} + +// C++ 5.17p6: When the left operand of an assignment operator denotes a +// reference to T, the operation assigns to the object of type T denoted by the +// reference. +bool ASTContext::referenceTypesAreCompatible(QualType lhs, QualType rhs) { + QualType ltype = lhs; + + if (lhs->isReferenceType()) + ltype = cast<ReferenceType>(lhs.getCanonicalType())->getReferenceeType(); + + QualType rtype = rhs; + + if (rhs->isReferenceType()) + rtype = cast<ReferenceType>(rhs.getCanonicalType())->getReferenceeType(); + + return typesAreCompatible(ltype, rtype); +} + +bool ASTContext::functionTypesAreCompatible(QualType lhs, QualType rhs) { + const FunctionType *lbase = cast<FunctionType>(lhs.getCanonicalType()); + const FunctionType *rbase = cast<FunctionType>(rhs.getCanonicalType()); + const FunctionTypeProto *lproto = dyn_cast<FunctionTypeProto>(lbase); + const FunctionTypeProto *rproto = dyn_cast<FunctionTypeProto>(rbase); + + // first check the return types (common between C99 and K&R). + if (!typesAreCompatible(lbase->getResultType(), rbase->getResultType())) + return false; + + if (lproto && rproto) { // two C99 style function prototypes + unsigned lproto_nargs = lproto->getNumArgs(); + unsigned rproto_nargs = rproto->getNumArgs(); + + if (lproto_nargs != rproto_nargs) + return false; + + // both prototypes have the same number of arguments. + if ((lproto->isVariadic() && !rproto->isVariadic()) || + (rproto->isVariadic() && !lproto->isVariadic())) + return false; + + // The use of ellipsis agree...now check the argument types. + for (unsigned i = 0; i < lproto_nargs; i++) + // C99 6.7.5.3p15: ...and each parameter declared with qualified type + // is taken as having the unqualified version of it's declared type. + if (!typesAreCompatible(lproto->getArgType(i).getUnqualifiedType(), + rproto->getArgType(i).getUnqualifiedType())) + return false; + return true; + } + if (!lproto && !rproto) // two K&R style function decls, nothing to do. + return true; + + // we have a mixture of K&R style with C99 prototypes + const FunctionTypeProto *proto = lproto ? lproto : rproto; + + if (proto->isVariadic()) + return false; + + // FIXME: Each parameter type T in the prototype must be compatible with the + // type resulting from applying the usual argument conversions to T. + return true; +} + +bool ASTContext::arrayTypesAreCompatible(QualType lhs, QualType rhs) { + // Compatible arrays must have compatible element types + QualType ltype = lhs->getAsArrayType()->getElementType(); + QualType rtype = rhs->getAsArrayType()->getElementType(); + + if (!typesAreCompatible(ltype, rtype)) + return false; + + // Compatible arrays must be the same size + if (const ConstantArrayType* LCAT = lhs->getAsConstantArrayType()) + if (const ConstantArrayType* RCAT = rhs->getAsConstantArrayType()) + return RCAT->getSize() == LCAT->getSize(); + + return true; +} + +/// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible, +/// both shall have the identically qualified version of a compatible type. +/// C99 6.2.7p1: Two types have compatible types if their types are the +/// same. See 6.7.[2,3,5] for additional rules. +bool ASTContext::typesAreCompatible(QualType lhs, QualType rhs) { + if (lhs.getCVRQualifiers() != rhs.getCVRQualifiers() || + lhs.getAddressSpace() != rhs.getAddressSpace()) + return false; + + QualType lcanon = lhs.getCanonicalType(); + QualType rcanon = rhs.getCanonicalType(); + + // If two types are identical, they are are compatible + if (lcanon == rcanon) + return true; + + // C++ [expr]: If an expression initially has the type "reference to T", the + // type is adjusted to "T" prior to any further analysis, the expression + // designates the object or function denoted by the reference, and the + // expression is an lvalue. + if (ReferenceType *RT = dyn_cast<ReferenceType>(lcanon)) + lcanon = RT->getReferenceeType(); + if (ReferenceType *RT = dyn_cast<ReferenceType>(rcanon)) + rcanon = RT->getReferenceeType(); + + Type::TypeClass LHSClass = lcanon->getTypeClass(); + Type::TypeClass RHSClass = rcanon->getTypeClass(); + + // We want to consider the two function types to be the same for these + // comparisons, just force one to the other. + if (LHSClass == Type::FunctionProto) LHSClass = Type::FunctionNoProto; + if (RHSClass == Type::FunctionProto) RHSClass = Type::FunctionNoProto; + + // Same as above for arrays + if (LHSClass == Type::VariableArray) LHSClass = Type::ConstantArray; + if (RHSClass == Type::VariableArray) RHSClass = Type::ConstantArray; + if (LHSClass == Type::IncompleteArray) LHSClass = Type::ConstantArray; + if (RHSClass == Type::IncompleteArray) RHSClass = Type::ConstantArray; + + // If the canonical type classes don't match... + if (LHSClass != RHSClass) { + // For Objective-C, it is possible for two types to be compatible + // when their classes don't match (when dealing with "id"). If either type + // is an interface, we defer to objcTypesAreCompatible(). + if (lcanon->isObjCInterfaceType() || rcanon->isObjCInterfaceType()) + return objcTypesAreCompatible(lcanon, rcanon); + + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + if (lcanon->isEnumeralType() && rcanon->isIntegralType()) { + EnumDecl* EDecl = cast<EnumDecl>(cast<TagType>(lcanon)->getDecl()); + return EDecl->getIntegerType() == rcanon; + } + if (rcanon->isEnumeralType() && lcanon->isIntegralType()) { + EnumDecl* EDecl = cast<EnumDecl>(cast<TagType>(rcanon)->getDecl()); + return EDecl->getIntegerType() == lcanon; + } + + return false; + } + // The canonical type classes match. + switch (LHSClass) { + case Type::FunctionProto: assert(0 && "Canonicalized away above"); + case Type::Pointer: + return pointerTypesAreCompatible(lcanon, rcanon); + case Type::ConstantArray: + case Type::VariableArray: + case Type::IncompleteArray: + return arrayTypesAreCompatible(lcanon, rcanon); + case Type::FunctionNoProto: + return functionTypesAreCompatible(lcanon, rcanon); + case Type::Tagged: // handle structures, unions + return tagTypesAreCompatible(lcanon, rcanon); + case Type::Builtin: + return builtinTypesAreCompatible(lcanon, rcanon); + case Type::ObjCInterface: + return interfaceTypesAreCompatible(lcanon, rcanon); + case Type::Vector: + case Type::OCUVector: + return vectorTypesAreCompatible(lcanon, rcanon); + case Type::ObjCQualifiedInterface: + return QualifiedInterfaceTypesAreCompatible(lcanon, rcanon); + default: + assert(0 && "unexpected type"); + } + return true; // should never get here... +} + +/// Emit - Serialize an ASTContext object to Bitcode. +void ASTContext::Emit(llvm::Serializer& S) const { + S.EmitRef(SourceMgr); + S.EmitRef(Target); + S.EmitRef(Idents); + S.EmitRef(Selectors); + + // Emit the size of the type vector so that we can reserve that size + // when we reconstitute the ASTContext object. + S.EmitInt(Types.size()); + + for (std::vector<Type*>::const_iterator I=Types.begin(), E=Types.end(); + I!=E;++I) + (*I)->Emit(S); + + // FIXME: S.EmitOwnedPtr(CFConstantStringTypeDecl); +} + +ASTContext* ASTContext::Create(llvm::Deserializer& D) { + SourceManager &SM = D.ReadRef<SourceManager>(); + TargetInfo &t = D.ReadRef<TargetInfo>(); + IdentifierTable &idents = D.ReadRef<IdentifierTable>(); + SelectorTable &sels = D.ReadRef<SelectorTable>(); + + unsigned size_reserve = D.ReadInt(); + + ASTContext* A = new ASTContext(SM,t,idents,sels,size_reserve); + + for (unsigned i = 0; i < size_reserve; ++i) + Type::Create(*A,i,D); + + // FIXME: A->CFConstantStringTypeDecl = D.ReadOwnedPtr<RecordDecl>(); + + return A; +} diff --git a/clang/lib/AST/Builtins.cpp b/clang/lib/AST/Builtins.cpp new file mode 100644 index 00000000000..e2bf5ca007b --- /dev/null +++ b/clang/lib/AST/Builtins.cpp @@ -0,0 +1,195 @@ +//===--- Builtins.cpp - Builtin function implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements various things for builtin functions. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Builtins.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +static const Builtin::Info BuiltinInfo[] = { + { "not a builtin function", 0, 0 }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS }, +#include "clang/AST/Builtins.def" +}; + +const Builtin::Info &Builtin::Context::GetRecord(unsigned ID) const { + if (ID < Builtin::FirstTSBuiltin) + return BuiltinInfo[ID]; + assert(ID - Builtin::FirstTSBuiltin < NumTSRecords && "Invalid builtin ID!"); + return TSRecords[ID - Builtin::FirstTSBuiltin]; +} + + +/// InitializeBuiltins - Mark the identifiers for all the builtins with their +/// appropriate builtin ID # and mark any non-portable builtin identifiers as +/// such. +void Builtin::Context::InitializeBuiltins(IdentifierTable &Table, + const TargetInfo &Target) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Step #2: Get target builtins. + Target.getTargetBuiltins(TSRecords, NumTSRecords); + + // Step #3: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the +/// pointer over the consumed characters. This returns the resultant type. +static QualType DecodeTypeFromStr(const char *&Str, ASTContext &Context, + bool AllowTypeModifiers = true) { + // Modifiers. + bool Long = false, LongLong = false, Signed = false, Unsigned = false; + + // Read the modifiers first. + bool Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case 'S': + assert(!Unsigned && "Can't use both 'S' and 'U' modifiers!"); + assert(!Signed && "Can't use 'S' modifier multiple times!"); + Signed = true; + break; + case 'U': + assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); + assert(!Unsigned && "Can't use 'S' modifier multiple times!"); + Unsigned = true; + break; + case 'L': + assert(!LongLong && "Can't have LLL modifier"); + if (Long) + LongLong = true; + else + Long = true; + break; + } + } + + QualType Type; + + // Read the base type. + switch (*Str++) { + default: assert(0 && "Unknown builtin type letter!"); + case 'v': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'v'!"); + Type = Context.VoidTy; + break; + case 'f': + assert(!Long && !Signed && !Unsigned && "Bad modifiers used with 'f'!"); + Type = Context.FloatTy; + break; + case 'd': + assert(!LongLong && !Signed && !Unsigned && "Bad modifiers used with 'd'!"); + if (Long) + Type = Context.LongDoubleTy; + else + Type = Context.DoubleTy; + break; + case 's': + assert(!LongLong && "Bad modifiers used with 's'!"); + if (Unsigned) + Type = Context.UnsignedShortTy; + else + Type = Context.ShortTy; + break; + case 'i': + if (LongLong) + Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; + else if (Long) + Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; + else if (Unsigned) + Type = Context.UnsignedIntTy; + else + Type = Context.IntTy; // default is signed. + break; + case 'c': + assert(!Long && !LongLong && "Bad modifiers used with 'c'!"); + if (Signed) + Type = Context.SignedCharTy; + else if (Unsigned) + Type = Context.UnsignedCharTy; + else + Type = Context.CharTy; + break; + case 'z': // size_t. + assert(!Long && !Signed && !Unsigned && "Bad modifiers for 'z'!"); + Type = Context.getSizeType(); + break; + case 'F': + Type = Context.getCFConstantStringType(); + break; + case 'a': + Type = Context.getBuiltinVaListType(); + assert(!Type.isNull() && "builtin va list type not initialized!"); + break; + case 'V': { + char *End; + + unsigned NumElements = strtoul(Str, &End, 10); + assert(End != Str && "Missing vector size"); + + Str = End; + + QualType ElementType = DecodeTypeFromStr(Str, Context, false); + Type = Context.getVectorType(ElementType, NumElements); + break; + } + } + + if (!AllowTypeModifiers) + return Type; + + Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case '*': + Type = Context.getPointerType(Type); + break; + case '&': + Type = Context.getReferenceType(Type); + break; + case 'C': + Type = Type.getQualifiedType(QualType::Const); + break; + } + } + + return Type; +} + +/// GetBuiltinType - Return the type for the specified builtin. +QualType Builtin::Context::GetBuiltinType(unsigned id, + ASTContext &Context) const { + const char *TypeStr = GetRecord(id).Type; + + llvm::SmallVector<QualType, 8> ArgTypes; + + QualType ResType = DecodeTypeFromStr(TypeStr, Context); + while (TypeStr[0] && TypeStr[0] != '.') + ArgTypes.push_back(DecodeTypeFromStr(TypeStr, Context)); + + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && + "'.' should only occur at end of builtin type list!"); + + // handle untyped/variadic arguments "T c99Style();" or "T cppStyle(...);". + if (ArgTypes.size() == 0 && TypeStr[0] == '.') + return Context.getFunctionTypeNoProto(ResType); + return Context.getFunctionType(ResType, &ArgTypes[0], ArgTypes.size(), + TypeStr[0] == '.'); +} diff --git a/clang/lib/AST/CFG.cpp b/clang/lib/AST/CFG.cpp new file mode 100644 index 00000000000..e2aba6b3ff3 --- /dev/null +++ b/clang/lib/AST/CFG.cpp @@ -0,0 +1,1509 @@ +//===--- CFG.cpp - Classes for representing and building CFGs----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the CFG and CFGBuilder classes for representing and +// building Control-Flow Graphs (CFGs) from ASTs. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/CFG.h" +#include "clang/AST/Expr.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/Compiler.h" +#include <set> +#include <iomanip> +#include <algorithm> +#include <sstream> +#include <iostream> + +using namespace clang; + +namespace { + +// SaveAndRestore - A utility class that uses RIIA to save and restore +// the value of a variable. +template<typename T> +struct VISIBILITY_HIDDEN SaveAndRestore { + SaveAndRestore(T& x) : X(x), old_value(x) {} + ~SaveAndRestore() { X = old_value; } + T get() { return old_value; } + + T& X; + T old_value; +}; + +/// CFGBuilder - This class is implements CFG construction from an AST. +/// The builder is stateful: an instance of the builder should be used to only +/// construct a single CFG. +/// +/// Example usage: +/// +/// CFGBuilder builder; +/// CFG* cfg = builder.BuildAST(stmt1); +/// +/// CFG construction is done via a recursive walk of an AST. +/// We actually parse the AST in reverse order so that the successor +/// of a basic block is constructed prior to its predecessor. This +/// allows us to nicely capture implicit fall-throughs without extra +/// basic blocks. +/// +class VISIBILITY_HIDDEN CFGBuilder : public StmtVisitor<CFGBuilder,CFGBlock*> { + CFG* cfg; + CFGBlock* Block; + CFGBlock* Succ; + CFGBlock* ContinueTargetBlock; + CFGBlock* BreakTargetBlock; + CFGBlock* SwitchTerminatedBlock; + CFGBlock* DefaultCaseBlock; + + // LabelMap records the mapping from Label expressions to their blocks. + typedef llvm::DenseMap<LabelStmt*,CFGBlock*> LabelMapTy; + LabelMapTy LabelMap; + + // A list of blocks that end with a "goto" that must be backpatched to + // their resolved targets upon completion of CFG construction. + typedef std::vector<CFGBlock*> BackpatchBlocksTy; + BackpatchBlocksTy BackpatchBlocks; + + // A list of labels whose address has been taken (for indirect gotos). + typedef llvm::SmallPtrSet<LabelStmt*,5> LabelSetTy; + LabelSetTy AddressTakenLabels; + +public: + explicit CFGBuilder() : cfg(NULL), Block(NULL), Succ(NULL), + ContinueTargetBlock(NULL), BreakTargetBlock(NULL), + SwitchTerminatedBlock(NULL), DefaultCaseBlock(NULL) { + // Create an empty CFG. + cfg = new CFG(); + } + + ~CFGBuilder() { delete cfg; } + + // buildCFG - Used by external clients to construct the CFG. + CFG* buildCFG(Stmt* Statement); + + // Visitors to walk an AST and construct the CFG. Called by + // buildCFG. Do not call directly! + + CFGBlock* VisitStmt(Stmt* Statement); + CFGBlock* VisitNullStmt(NullStmt* Statement); + CFGBlock* VisitCompoundStmt(CompoundStmt* C); + CFGBlock* VisitIfStmt(IfStmt* I); + CFGBlock* VisitReturnStmt(ReturnStmt* R); + CFGBlock* VisitLabelStmt(LabelStmt* L); + CFGBlock* VisitGotoStmt(GotoStmt* G); + CFGBlock* VisitForStmt(ForStmt* F); + CFGBlock* VisitWhileStmt(WhileStmt* W); + CFGBlock* VisitDoStmt(DoStmt* D); + CFGBlock* VisitContinueStmt(ContinueStmt* C); + CFGBlock* VisitBreakStmt(BreakStmt* B); + CFGBlock* VisitSwitchStmt(SwitchStmt* S); + CFGBlock* VisitCaseStmt(CaseStmt* S); + CFGBlock* VisitDefaultStmt(DefaultStmt* D); + CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I); + + // FIXME: Add support for ObjC-specific control-flow structures. + + CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + badCFG = true; + return Block; + } + + CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S) { + badCFG = true; + return Block; + } + +private: + CFGBlock* createBlock(bool add_successor = true); + CFGBlock* addStmt(Stmt* S); + CFGBlock* WalkAST(Stmt* S, bool AlwaysAddStmt); + CFGBlock* WalkAST_VisitChildren(Stmt* S); + CFGBlock* WalkAST_VisitDeclSubExprs(StmtIterator& I); + CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* S); + void FinishBlock(CFGBlock* B); + + bool badCFG; +}; + +/// BuildCFG - Constructs a CFG from an AST (a Stmt*). The AST can +/// represent an arbitrary statement. Examples include a single expression +/// or a function body (compound statement). The ownership of the returned +/// CFG is transferred to the caller. If CFG construction fails, this method +/// returns NULL. +CFG* CFGBuilder::buildCFG(Stmt* Statement) { + assert (cfg); + if (!Statement) return NULL; + + badCFG = false; + + // Create an empty block that will serve as the exit block for the CFG. + // Since this is the first block added to the CFG, it will be implicitly + // registered as the exit block. + Succ = createBlock(); + assert (Succ == &cfg->getExit()); + Block = NULL; // the EXIT block is empty. Create all other blocks lazily. + + // Visit the statements and create the CFG. + CFGBlock* B = Visit(Statement); + if (!B) B = Succ; + + if (B) { + // Finalize the last constructed block. This usually involves + // reversing the order of the statements in the block. + if (Block) FinishBlock(B); + + // Backpatch the gotos whose label -> block mappings we didn't know + // when we encountered them. + for (BackpatchBlocksTy::iterator I = BackpatchBlocks.begin(), + E = BackpatchBlocks.end(); I != E; ++I ) { + + CFGBlock* B = *I; + GotoStmt* G = cast<GotoStmt>(B->getTerminator()); + LabelMapTy::iterator LI = LabelMap.find(G->getLabel()); + + // If there is no target for the goto, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + B->addSuccessor(LI->second); + } + + // Add successors to the Indirect Goto Dispatch block (if we have one). + if (CFGBlock* B = cfg->getIndirectGotoBlock()) + for (LabelSetTy::iterator I = AddressTakenLabels.begin(), + E = AddressTakenLabels.end(); I != E; ++I ) { + + // Lookup the target block. + LabelMapTy::iterator LI = LabelMap.find(*I); + + // If there is no target block that contains label, then we are looking + // at an incomplete AST. Handle this by not registering a successor. + if (LI == LabelMap.end()) continue; + + B->addSuccessor(LI->second); + } + + Succ = B; + } + + // Create an empty entry block that has no predecessors. + cfg->setEntry(createBlock()); + + if (badCFG) { + delete cfg; + cfg = NULL; + return NULL; + } + + // NULL out cfg so that repeated calls to the builder will fail and that + // the ownership of the constructed CFG is passed to the caller. + CFG* t = cfg; + cfg = NULL; + return t; +} + +/// createBlock - Used to lazily create blocks that are connected +/// to the current (global) succcessor. +CFGBlock* CFGBuilder::createBlock(bool add_successor) { + CFGBlock* B = cfg->createBlock(); + if (add_successor && Succ) B->addSuccessor(Succ); + return B; +} + +/// FinishBlock - When the last statement has been added to the block, +/// we must reverse the statements because they have been inserted +/// in reverse order. +void CFGBuilder::FinishBlock(CFGBlock* B) { + assert (B); + B->reverseStmts(); +} + +/// addStmt - Used to add statements/expressions to the current CFGBlock +/// "Block". This method calls WalkAST on the passed statement to see if it +/// contains any short-circuit expressions. If so, it recursively creates +/// the necessary blocks for such expressions. It returns the "topmost" block +/// of the created blocks, or the original value of "Block" when this method +/// was called if no additional blocks are created. +CFGBlock* CFGBuilder::addStmt(Stmt* S) { + if (!Block) Block = createBlock(); + return WalkAST(S,true); +} + +/// WalkAST - Used by addStmt to walk the subtree of a statement and +/// add extra blocks for ternary operators, &&, and ||. We also +/// process "," and DeclStmts (which may contain nested control-flow). +CFGBlock* CFGBuilder::WalkAST(Stmt* S, bool AlwaysAddStmt = false) { + switch (S->getStmtClass()) { + case Stmt::ConditionalOperatorClass: { + ConditionalOperator* C = cast<ConditionalOperator>(S); + + // Create the confluence block that will "merge" the results + // of the ternary expression. + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + FinishBlock(ConfluenceBlock); + + // Create a block for the LHS expression if there is an LHS expression. + // A GCC extension allows LHS to be NULL, causing the condition to + // be the value that is returned instead. + // e.g: x ?: y is shorthand for: x ? x : y; + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = NULL; + if (C->getLHS()) { + LHSBlock = Visit(C->getLHS()); + FinishBlock(LHSBlock); + Block = NULL; + } + + // Create the block for the RHS expression. + Succ = ConfluenceBlock; + CFGBlock* RHSBlock = Visit(C->getRHS()); + FinishBlock(RHSBlock); + + // Create the block that will contain the condition. + Block = createBlock(false); + + if (LHSBlock) + Block->addSuccessor(LHSBlock); + else { + // If we have no LHS expression, add the ConfluenceBlock as a direct + // successor for the block containing the condition. Moreover, + // we need to reverse the order of the predecessors in the + // ConfluenceBlock because the RHSBlock will have been added to + // the succcessors already, and we want the first predecessor to the + // the block containing the expression for the case when the ternary + // expression evaluates to true. + Block->addSuccessor(ConfluenceBlock); + assert (ConfluenceBlock->pred_size() == 2); + std::reverse(ConfluenceBlock->pred_begin(), + ConfluenceBlock->pred_end()); + } + + Block->addSuccessor(RHSBlock); + + Block->setTerminator(C); + return addStmt(C->getCond()); + } + + case Stmt::ChooseExprClass: { + ChooseExpr* C = cast<ChooseExpr>(S); + + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + FinishBlock(ConfluenceBlock); + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = Visit(C->getLHS()); + FinishBlock(LHSBlock); + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = Visit(C->getRHS()); + FinishBlock(RHSBlock); + + Block = createBlock(false); + Block->addSuccessor(LHSBlock); + Block->addSuccessor(RHSBlock); + Block->setTerminator(C); + return addStmt(C->getCond()); + } + + case Stmt::DeclStmtClass: { + ScopedDecl* D = cast<DeclStmt>(S)->getDecl(); + Block->appendStmt(S); + + StmtIterator I(D); + return WalkAST_VisitDeclSubExprs(I); + } + + case Stmt::AddrLabelExprClass: { + AddrLabelExpr* A = cast<AddrLabelExpr>(S); + AddressTakenLabels.insert(A->getLabel()); + + if (AlwaysAddStmt) Block->appendStmt(S); + return Block; + } + + case Stmt::StmtExprClass: + return WalkAST_VisitStmtExpr(cast<StmtExpr>(S)); + + case Stmt::UnaryOperatorClass: { + UnaryOperator* U = cast<UnaryOperator>(S); + + // sizeof(expressions). For such expressions, + // the subexpression is not really evaluated, so + // we don't care about control-flow within the sizeof. + if (U->getOpcode() == UnaryOperator::SizeOf) { + Block->appendStmt(S); + return Block; + } + + break; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(S); + + if (B->isLogicalOp()) { // && or || + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(B); + FinishBlock(ConfluenceBlock); + + // create the block evaluating the LHS + CFGBlock* LHSBlock = createBlock(false); + LHSBlock->setTerminator(B); + + // create the block evaluating the RHS + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = Visit(B->getRHS()); + + // Now link the LHSBlock with RHSBlock. + if (B->getOpcode() == BinaryOperator::LOr) { + LHSBlock->addSuccessor(ConfluenceBlock); + LHSBlock->addSuccessor(RHSBlock); + } + else { + assert (B->getOpcode() == BinaryOperator::LAnd); + LHSBlock->addSuccessor(RHSBlock); + LHSBlock->addSuccessor(ConfluenceBlock); + } + + // Generate the blocks for evaluating the LHS. + Block = LHSBlock; + return addStmt(B->getLHS()); + } + else if (B->getOpcode() == BinaryOperator::Comma) { // , + Block->appendStmt(B); + addStmt(B->getRHS()); + return addStmt(B->getLHS()); + } + + break; + } + + case Stmt::ParenExprClass: + return WalkAST(cast<ParenExpr>(S)->getSubExpr(), AlwaysAddStmt); + + default: + break; + }; + + if (AlwaysAddStmt) Block->appendStmt(S); + return WalkAST_VisitChildren(S); +} + +/// WalkAST_VisitDeclSubExprs - Utility method to handle Decls contained in +/// DeclStmts. Because the initialization code (and sometimes the +/// the type declarations) for DeclStmts can contain arbitrary expressions, +/// we must linearize declarations to handle arbitrary control-flow induced by +/// those expressions. +CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExprs(StmtIterator& I) { + if (I == StmtIterator()) + return Block; + + Stmt* S = *I; + ++I; + WalkAST_VisitDeclSubExprs(I); + + // Optimization: Don't create separate block-level statements for literals. + + switch (S->getStmtClass()) { + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + break; + + // All other cases. + + default: + Block = addStmt(S); + } + + return Block; +} + +/// WalkAST_VisitChildren - Utility method to call WalkAST on the +/// children of a Stmt. +CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* S) { + CFGBlock* B = Block; + for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; + I != E; ++I) + if (*I) B = WalkAST(*I); + + return B; +} + +/// WalkAST_VisitStmtExpr - Utility method to handle (nested) statement +/// expressions (a GCC extension). +CFGBlock* CFGBuilder::WalkAST_VisitStmtExpr(StmtExpr* S) { + Block->appendStmt(S); + return VisitCompoundStmt(S->getSubStmt()); +} + +/// VisitStmt - Handle statements with no branching control flow. +CFGBlock* CFGBuilder::VisitStmt(Stmt* Statement) { + // We cannot assume that we are in the middle of a basic block, since + // the CFG might only be constructed for this single statement. If + // we have no current basic block, just create one lazily. + if (!Block) Block = createBlock(); + + // Simply add the statement to the current block. We actually + // insert statements in reverse order; this order is reversed later + // when processing the containing element in the AST. + addStmt(Statement); + + return Block; +} + +CFGBlock* CFGBuilder::VisitNullStmt(NullStmt* Statement) { + return Block; +} + +CFGBlock* CFGBuilder::VisitCompoundStmt(CompoundStmt* C) { + + for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); + I != E; ++I ) { + Visit(*I); + } + + return Block; +} + +CFGBlock* CFGBuilder::VisitIfStmt(IfStmt* I) { + // We may see an if statement in the middle of a basic block, or + // it may be the first statement we are processing. In either case, + // we create a new basic block. First, we create the blocks for + // the then...else statements, and then we create the block containing + // the if statement. If we were in the middle of a block, we + // stop processing that block and reverse its statements. That block + // is then the implicit successor for the "then" and "else" clauses. + + // The block we were proccessing is now finished. Make it the + // successor block. + if (Block) { + Succ = Block; + FinishBlock(Block); + } + + // Process the false branch. NULL out Block so that the recursive + // call to Visit will create a new basic block. + // Null out Block so that all successor + CFGBlock* ElseBlock = Succ; + + if (Stmt* Else = I->getElse()) { + SaveAndRestore<CFGBlock*> sv(Succ); + + // NULL out Block so that the recursive call to Visit will + // create a new basic block. + Block = NULL; + ElseBlock = Visit(Else); + + if (!ElseBlock) // Can occur when the Else body has all NullStmts. + ElseBlock = sv.get(); + else if (Block) + FinishBlock(ElseBlock); + } + + // Process the true branch. NULL out Block so that the recursive + // call to Visit will create a new basic block. + // Null out Block so that all successor + CFGBlock* ThenBlock; + { + Stmt* Then = I->getThen(); + assert (Then); + SaveAndRestore<CFGBlock*> sv(Succ); + Block = NULL; + ThenBlock = Visit(Then); + + if (!ThenBlock) // Can occur when the Then body has all NullStmts. + ThenBlock = sv.get(); + else if (Block) + FinishBlock(ThenBlock); + } + + // Now create a new block containing the if statement. + Block = createBlock(false); + + // Set the terminator of the new block to the If statement. + Block->setTerminator(I); + + // Now add the successors. + Block->addSuccessor(ThenBlock); + Block->addSuccessor(ElseBlock); + + // Add the condition as the last statement in the new block. This + // may create new blocks as the condition may contain control-flow. Any + // newly created blocks will be pointed to be "Block". + return addStmt(I->getCond()->IgnoreParens()); +} + + +CFGBlock* CFGBuilder::VisitReturnStmt(ReturnStmt* R) { + // If we were in the middle of a block we stop processing that block + // and reverse its statements. + // + // NOTE: If a "return" appears in the middle of a block, this means + // that the code afterwards is DEAD (unreachable). We still + // keep a basic block for that code; a simple "mark-and-sweep" + // from the entry block will be able to report such dead + // blocks. + if (Block) FinishBlock(Block); + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + Block->addSuccessor(&cfg->getExit()); + + // Add the return statement to the block. This may create new blocks + // if R contains control-flow (short-circuit operations). + return addStmt(R); +} + +CFGBlock* CFGBuilder::VisitLabelStmt(LabelStmt* L) { + // Get the block of the labeled statement. Add it to our map. + Visit(L->getSubStmt()); + CFGBlock* LabelBlock = Block; + + if (!LabelBlock) // This can happen when the body is empty, i.e. + LabelBlock=createBlock(); // scopes that only contains NullStmts. + + assert (LabelMap.find(L) == LabelMap.end() && "label already in map"); + LabelMap[ L ] = LabelBlock; + + // Labels partition blocks, so this is the end of the basic block + // we were processing (L is the block's label). Because this is + // label (and we have already processed the substatement) there is no + // extra control-flow to worry about. + LabelBlock->setLabel(L); + FinishBlock(LabelBlock); + + // We set Block to NULL to allow lazy creation of a new block + // (if necessary); + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = LabelBlock; + + return LabelBlock; +} + +CFGBlock* CFGBuilder::VisitGotoStmt(GotoStmt* G) { + // Goto is a control-flow statement. Thus we stop processing the + // current block and create a new one. + if (Block) FinishBlock(Block); + Block = createBlock(false); + Block->setTerminator(G); + + // If we already know the mapping to the label block add the + // successor now. + LabelMapTy::iterator I = LabelMap.find(G->getLabel()); + + if (I == LabelMap.end()) + // We will need to backpatch this block later. + BackpatchBlocks.push_back(Block); + else + Block->addSuccessor(I->second); + + return Block; +} + +CFGBlock* CFGBuilder::VisitForStmt(ForStmt* F) { + // "for" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(F); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + if (Stmt* C = F->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body as + // well as any code above the loop. + Succ = EntryConditionBlock; + + // Now create the loop body. + { + assert (F->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // Create a new block to contain the (bottom) of the loop body. + Block = NULL; + + // If we have increment code, insert it at the end of the body block. + if (Stmt* I = F->getInc()) Block = addStmt(I); + + // Now populate the body block, and in the process create new blocks + // as we walk the body of the loop. + CFGBlock* BodyBlock = Visit(F->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "for (...;...; ) ;" + else if (Block) + FinishBlock(BodyBlock); + + // This new body block is a successor to our "exit" condition block. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // If the loop contains initialization, create a new block for those + // statements. This block can also contain statements that precede + // the loop. + if (Stmt* I = F->getInit()) { + Block = createBlock(); + return addStmt(I); + } + else { + // There is no loop initialization. We are thus basically a while + // loop. NULL out Block to force lazy block construction. + Block = NULL; + Succ = EntryConditionBlock; + return EntryConditionBlock; + } +} + +CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { + // "while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(W); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + // Thus we update "Succ" after adding the condition. + if (Stmt* C = W->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + assert (Block == EntryConditionBlock); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body as + // well as any code above the loop. + Succ = EntryConditionBlock; + + // Process the loop body. + { + assert (W->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + CFGBlock* BodyBlock = Visit(W->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "while(...) ;" + else if (Block) + FinishBlock(BodyBlock); + + // Add the loop body entry as a successor to the condition. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // There can be no more statements in the condition block + // since we loop back to this block. NULL out Block to force + // lazy creation of another block. + Block = NULL; + + // Return the condition block, which is the dominating block for the loop. + Succ = EntryConditionBlock; + return EntryConditionBlock; +} + +CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) { + // "do...while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + LoopSuccessor = Block; + } + else LoopSuccessor = Succ; + + // Because of short-circuit evaluation, the condition of the loop + // can span multiple basic blocks. Thus we need the "Entry" and "Exit" + // blocks that evaluate the condition. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(D); + + // Now add the actual condition to the condition block. Because the + // condition itself may contain control-flow, new blocks may be created. + if (Stmt* C = D->getCond()) { + Block = ExitConditionBlock; + EntryConditionBlock = addStmt(C); + if (Block) FinishBlock(EntryConditionBlock); + } + + // The condition block is the implicit successor for the loop body. + Succ = EntryConditionBlock; + + // Process the loop body. + CFGBlock* BodyBlock = NULL; + { + assert (D->getBody()); + + // Save the current values for Block, Succ, and continue and break targets + SaveAndRestore<CFGBlock*> save_Block(Block), save_Succ(Succ), + save_continue(ContinueTargetBlock), + save_break(BreakTargetBlock); + + // All continues within this loop should go to the condition block + ContinueTargetBlock = EntryConditionBlock; + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // NULL out Block to force lazy instantiation of blocks for the body. + Block = NULL; + + // Create the body. The returned block is the entry to the loop body. + BodyBlock = Visit(D->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "do ; while(...)" + else if (Block) + FinishBlock(BodyBlock); + + // Add the loop body entry as a successor to the condition. + ExitConditionBlock->addSuccessor(BodyBlock); + } + + // Link up the condition block with the code that follows the loop. + // (the false branch). + ExitConditionBlock->addSuccessor(LoopSuccessor); + + // There can be no more statements in the body block(s) + // since we loop back to the body. NULL out Block to force + // lazy creation of another block. + Block = NULL; + + // Return the loop body, which is the dominating block for the loop. + Succ = BodyBlock; + return BodyBlock; +} + +CFGBlock* CFGBuilder::VisitContinueStmt(ContinueStmt* C) { + // "continue" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) FinishBlock(Block); + + // Now create a new block that ends with the continue statement. + Block = createBlock(false); + Block->setTerminator(C); + + // If there is no target for the continue, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (ContinueTargetBlock) Block->addSuccessor(ContinueTargetBlock); + + return Block; +} + +CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) { + // "break" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) FinishBlock(Block); + + // Now create a new block that ends with the continue statement. + Block = createBlock(false); + Block->setTerminator(B); + + // If there is no target for the break, then we are looking at an + // incomplete AST. Handle this by not registering a successor. + if (BreakTargetBlock) Block->addSuccessor(BreakTargetBlock); + + return Block; +} + +CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* S) { + // "switch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock* SwitchSuccessor = NULL; + + if (Block) { + FinishBlock(Block); + SwitchSuccessor = Block; + } + else SwitchSuccessor = Succ; + + // Save the current "switch" context. + SaveAndRestore<CFGBlock*> save_switch(SwitchTerminatedBlock), + save_break(BreakTargetBlock), + save_default(DefaultCaseBlock); + + // Set the "default" case to be the block after the switch statement. + // If the switch statement contains a "default:", this value will + // be overwritten with the block for that code. + DefaultCaseBlock = SwitchSuccessor; + + // Create a new block that will contain the switch statement. + SwitchTerminatedBlock = createBlock(false); + + // Now process the switch body. The code after the switch is the implicit + // successor. + Succ = SwitchSuccessor; + BreakTargetBlock = SwitchSuccessor; + + // When visiting the body, the case statements should automatically get + // linked up to the switch. We also don't keep a pointer to the body, + // since all control-flow from the switch goes to case/default statements. + assert (S->getBody() && "switch must contain a non-NULL body"); + Block = NULL; + CFGBlock *BodyBlock = Visit(S->getBody()); + if (Block) FinishBlock(BodyBlock); + + // If we have no "default:" case, the default transition is to the + // code following the switch body. + SwitchTerminatedBlock->addSuccessor(DefaultCaseBlock); + + // Add the terminator and condition in the switch block. + SwitchTerminatedBlock->setTerminator(S); + assert (S->getCond() && "switch condition must be non-NULL"); + Block = SwitchTerminatedBlock; + + return addStmt(S->getCond()); +} + +CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* S) { + // CaseStmts are essentially labels, so they are the + // first statement in a block. + + if (S->getSubStmt()) Visit(S->getSubStmt()); + CFGBlock* CaseBlock = Block; + if (!CaseBlock) CaseBlock = createBlock(); + + // Cases statements partition blocks, so this is the top of + // the basic block we were processing (the "case XXX:" is the label). + CaseBlock->setLabel(S); + FinishBlock(CaseBlock); + + // Add this block to the list of successors for the block with the + // switch statement. + assert (SwitchTerminatedBlock); + SwitchTerminatedBlock->addSuccessor(CaseBlock); + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = CaseBlock; + + return CaseBlock; +} + +CFGBlock* CFGBuilder::VisitDefaultStmt(DefaultStmt* S) { + if (S->getSubStmt()) Visit(S->getSubStmt()); + DefaultCaseBlock = Block; + if (!DefaultCaseBlock) DefaultCaseBlock = createBlock(); + + // Default statements partition blocks, so this is the top of + // the basic block we were processing (the "default:" is the label). + DefaultCaseBlock->setLabel(S); + FinishBlock(DefaultCaseBlock); + + // Unlike case statements, we don't add the default block to the + // successors for the switch statement immediately. This is done + // when we finish processing the switch statement. This allows for + // the default case (including a fall-through to the code after the + // switch statement) to always be the last successor of a switch-terminated + // block. + + // We set Block to NULL to allow lazy creation of a new block (if necessary) + Block = NULL; + + // This block is now the implicit successor of other blocks. + Succ = DefaultCaseBlock; + + return DefaultCaseBlock; +} + +CFGBlock* CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt* I) { + // Lazily create the indirect-goto dispatch block if there isn't one + // already. + CFGBlock* IBlock = cfg->getIndirectGotoBlock(); + + if (!IBlock) { + IBlock = createBlock(false); + cfg->setIndirectGotoBlock(IBlock); + } + + // IndirectGoto is a control-flow statement. Thus we stop processing the + // current block and create a new one. + if (Block) FinishBlock(Block); + Block = createBlock(false); + Block->setTerminator(I); + Block->addSuccessor(IBlock); + return addStmt(I->getTarget()); +} + + +} // end anonymous namespace + +/// createBlock - Constructs and adds a new CFGBlock to the CFG. The +/// block has no successors or predecessors. If this is the first block +/// created in the CFG, it is automatically set to be the Entry and Exit +/// of the CFG. +CFGBlock* CFG::createBlock() { + bool first_block = begin() == end(); + + // Create the block. + Blocks.push_front(CFGBlock(NumBlockIDs++)); + + // If this is the first block, set it as the Entry and Exit. + if (first_block) Entry = Exit = &front(); + + // Return the block. + return &front(); +} + +/// buildCFG - Constructs a CFG from an AST. Ownership of the returned +/// CFG is returned to the caller. +CFG* CFG::buildCFG(Stmt* Statement) { + CFGBuilder Builder; + return Builder.buildCFG(Statement); +} + +/// reverseStmts - Reverses the orders of statements within a CFGBlock. +void CFGBlock::reverseStmts() { std::reverse(Stmts.begin(),Stmts.end()); } + +//===----------------------------------------------------------------------===// +// CFG: Queries for BlkExprs. +//===----------------------------------------------------------------------===// + +namespace { + typedef llvm::DenseMap<const Stmt*,unsigned> BlkExprMapTy; +} + +static void FindSubExprAssignments(Stmt* S, llvm::SmallPtrSet<Expr*,50>& Set) { + if (!S) + return; + + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) { + if (!*I) continue; + + if (BinaryOperator* B = dyn_cast<BinaryOperator>(*I)) + if (B->isAssignmentOp()) Set.insert(B); + + FindSubExprAssignments(*I, Set); + } +} + +static BlkExprMapTy* PopulateBlkExprMap(CFG& cfg) { + BlkExprMapTy* M = new BlkExprMapTy(); + + // Look for assignments that are used as subexpressions. These are the + // only assignments that we want to register as a block-level expression. + llvm::SmallPtrSet<Expr*,50> SubExprAssignments; + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) + for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) + FindSubExprAssignments(*BI, SubExprAssignments); + + // Iterate over the statements again on identify the Expr* and Stmt* at + // the block-level that are block-level expressions. + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) + for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) + if (Expr* E = dyn_cast<Expr>(*BI)) { + + if (BinaryOperator* B = dyn_cast<BinaryOperator>(E)) { + // Assignment expressions that are not nested within another + // expression are really "statements" whose value is never + // used by another expression. + if (B->isAssignmentOp() && !SubExprAssignments.count(E)) + continue; + } + else if (const StmtExpr* S = dyn_cast<StmtExpr>(E)) { + // Special handling for statement expressions. The last statement + // in the statement expression is also a block-level expr. + const CompoundStmt* C = S->getSubStmt(); + if (!C->body_empty()) { + unsigned x = M->size(); + (*M)[C->body_back()] = x; + } + } + + unsigned x = M->size(); + (*M)[E] = x; + } + + return M; +} + +CFG::BlkExprNumTy CFG::getBlkExprNum(const Stmt* S) { + assert(S != NULL); + if (!BlkExprMap) { BlkExprMap = (void*) PopulateBlkExprMap(*this); } + + BlkExprMapTy* M = reinterpret_cast<BlkExprMapTy*>(BlkExprMap); + BlkExprMapTy::iterator I = M->find(S); + + if (I == M->end()) return CFG::BlkExprNumTy(); + else return CFG::BlkExprNumTy(I->second); +} + +unsigned CFG::getNumBlkExprs() { + if (const BlkExprMapTy* M = reinterpret_cast<const BlkExprMapTy*>(BlkExprMap)) + return M->size(); + else { + // We assume callers interested in the number of BlkExprs will want + // the map constructed if it doesn't already exist. + BlkExprMap = (void*) PopulateBlkExprMap(*this); + return reinterpret_cast<BlkExprMapTy*>(BlkExprMap)->size(); + } +} + +typedef std::set<std::pair<CFGBlock*,CFGBlock*> > BlkEdgeSetTy; + +const std::pair<CFGBlock*,CFGBlock*>* +CFG::getBlockEdgeImpl(const CFGBlock* B1, const CFGBlock* B2) { + + BlkEdgeSetTy*& p = reinterpret_cast<BlkEdgeSetTy*&>(BlkEdgeSet); + if (!p) p = new BlkEdgeSetTy(); + + return &*(p->insert(std::make_pair(const_cast<CFGBlock*>(B1), + const_cast<CFGBlock*>(B2))).first); +} + +CFG::~CFG() { + delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap); + delete reinterpret_cast<BlkEdgeSetTy*>(BlkEdgeSet); +} + +//===----------------------------------------------------------------------===// +// CFG pretty printing +//===----------------------------------------------------------------------===// + +namespace { + +class VISIBILITY_HIDDEN StmtPrinterHelper : public PrinterHelper { + + typedef llvm::DenseMap<Stmt*,std::pair<unsigned,unsigned> > StmtMapTy; + StmtMapTy StmtMap; + signed CurrentBlock; + unsigned CurrentStmt; + +public: + + StmtPrinterHelper(const CFG* cfg) : CurrentBlock(0), CurrentStmt(0) { + for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { + unsigned j = 1; + for (CFGBlock::const_iterator BI = I->begin(), BEnd = I->end() ; + BI != BEnd; ++BI, ++j ) + StmtMap[*BI] = std::make_pair(I->getBlockID(),j); + } + } + + virtual ~StmtPrinterHelper() {} + + void setBlockID(signed i) { CurrentBlock = i; } + void setStmtID(unsigned i) { CurrentStmt = i; } + + virtual bool handledStmt(Stmt* S, std::ostream& OS) { + + StmtMapTy::iterator I = StmtMap.find(S); + + if (I == StmtMap.end()) + return false; + + if (CurrentBlock >= 0 && I->second.first == (unsigned) CurrentBlock + && I->second.second == CurrentStmt) + return false; + + OS << "[B" << I->second.first << "." << I->second.second << "]"; + return true; + } +}; + +class VISIBILITY_HIDDEN CFGBlockTerminatorPrint + : public StmtVisitor<CFGBlockTerminatorPrint,void> { + + std::ostream& OS; + StmtPrinterHelper* Helper; +public: + CFGBlockTerminatorPrint(std::ostream& os, StmtPrinterHelper* helper) + : OS(os), Helper(helper) {} + + void VisitIfStmt(IfStmt* I) { + OS << "if "; + I->getCond()->printPretty(OS,Helper); + } + + // Default case. + void VisitStmt(Stmt* S) { S->printPretty(OS); } + + void VisitForStmt(ForStmt* F) { + OS << "for (" ; + if (F->getInit()) OS << "..."; + OS << "; "; + if (Stmt* C = F->getCond()) C->printPretty(OS,Helper); + OS << "; "; + if (F->getInc()) OS << "..."; + OS << ")"; + } + + void VisitWhileStmt(WhileStmt* W) { + OS << "while " ; + if (Stmt* C = W->getCond()) C->printPretty(OS,Helper); + } + + void VisitDoStmt(DoStmt* D) { + OS << "do ... while "; + if (Stmt* C = D->getCond()) C->printPretty(OS,Helper); + } + + void VisitSwitchStmt(SwitchStmt* S) { + OS << "switch "; + S->getCond()->printPretty(OS,Helper); + } + + void VisitConditionalOperator(ConditionalOperator* C) { + C->getCond()->printPretty(OS,Helper); + OS << " ? ... : ..."; + } + + void VisitChooseExpr(ChooseExpr* C) { + OS << "__builtin_choose_expr( "; + C->getCond()->printPretty(OS,Helper); + OS << " )"; + } + + void VisitIndirectGotoStmt(IndirectGotoStmt* I) { + OS << "goto *"; + I->getTarget()->printPretty(OS,Helper); + } + + void VisitBinaryOperator(BinaryOperator* B) { + if (!B->isLogicalOp()) { + VisitExpr(B); + return; + } + + B->getLHS()->printPretty(OS,Helper); + + switch (B->getOpcode()) { + case BinaryOperator::LOr: + OS << " || ..."; + return; + case BinaryOperator::LAnd: + OS << " && ..."; + return; + default: + assert(false && "Invalid logical operator."); + } + } + + void VisitExpr(Expr* E) { + E->printPretty(OS,Helper); + } +}; + + +void print_stmt(std::ostream&OS, StmtPrinterHelper* Helper, Stmt* S) { + if (Helper) { + // special printing for statement-expressions. + if (StmtExpr* SE = dyn_cast<StmtExpr>(S)) { + CompoundStmt* Sub = SE->getSubStmt(); + + if (Sub->child_begin() != Sub->child_end()) { + OS << "({ ... ; "; + Helper->handledStmt(*SE->getSubStmt()->body_rbegin(),OS); + OS << " })\n"; + return; + } + } + + // special printing for comma expressions. + if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) { + if (B->getOpcode() == BinaryOperator::Comma) { + OS << "... , "; + Helper->handledStmt(B->getRHS(),OS); + OS << '\n'; + return; + } + } + } + + S->printPretty(OS, Helper); + + // Expressions need a newline. + if (isa<Expr>(S)) OS << '\n'; +} + +void print_block(std::ostream& OS, const CFG* cfg, const CFGBlock& B, + StmtPrinterHelper* Helper, bool print_edges) { + + if (Helper) Helper->setBlockID(B.getBlockID()); + + // Print the header. + OS << "\n [ B" << B.getBlockID(); + + if (&B == &cfg->getEntry()) + OS << " (ENTRY) ]\n"; + else if (&B == &cfg->getExit()) + OS << " (EXIT) ]\n"; + else if (&B == cfg->getIndirectGotoBlock()) + OS << " (INDIRECT GOTO DISPATCH) ]\n"; + else + OS << " ]\n"; + + // Print the label of this block. + if (Stmt* S = const_cast<Stmt*>(B.getLabel())) { + + if (print_edges) + OS << " "; + + if (LabelStmt* L = dyn_cast<LabelStmt>(S)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast<CaseStmt>(S)) { + OS << "case "; + C->getLHS()->printPretty(OS); + if (C->getRHS()) { + OS << " ... "; + C->getRHS()->printPretty(OS); + } + } + else if (isa<DefaultStmt>(S)) + OS << "default"; + else + assert(false && "Invalid label statement in CFGBlock."); + + OS << ":\n"; + } + + // Iterate through the statements in the block and print them. + unsigned j = 1; + + for (CFGBlock::const_iterator I = B.begin(), E = B.end() ; + I != E ; ++I, ++j ) { + + // Print the statement # in the basic block and the statement itself. + if (print_edges) + OS << " "; + + OS << std::setw(3) << j << ": "; + + if (Helper) + Helper->setStmtID(j); + + print_stmt(OS,Helper,*I); + } + + // Print the terminator of this block. + if (B.getTerminator()) { + if (print_edges) + OS << " "; + + OS << " T: "; + + if (Helper) Helper->setBlockID(-1); + + CFGBlockTerminatorPrint TPrinter(OS,Helper); + TPrinter.Visit(const_cast<Stmt*>(B.getTerminator())); + OS << '\n'; + } + + if (print_edges) { + // Print the predecessors of this block. + OS << " Predecessors (" << B.pred_size() << "):"; + unsigned i = 0; + + for (CFGBlock::const_pred_iterator I = B.pred_begin(), E = B.pred_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) == 0) + OS << "\n "; + + OS << " B" << (*I)->getBlockID(); + } + + OS << '\n'; + + // Print the successors of this block. + OS << " Successors (" << B.succ_size() << "):"; + i = 0; + + for (CFGBlock::const_succ_iterator I = B.succ_begin(), E = B.succ_end(); + I != E; ++I, ++i) { + + if (i == 8 || (i-8) % 10 == 0) + OS << "\n "; + + OS << " B" << (*I)->getBlockID(); + } + + OS << '\n'; + } +} + +} // end anonymous namespace + +/// dump - A simple pretty printer of a CFG that outputs to stderr. +void CFG::dump() const { print(*llvm::cerr.stream()); } + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(std::ostream& OS) const { + + StmtPrinterHelper Helper(this); + + // Print the entry block. + print_block(OS, this, getEntry(), &Helper, true); + + // Iterate through the CFGBlocks and print them one by one. + for (const_iterator I = Blocks.begin(), E = Blocks.end() ; I != E ; ++I) { + // Skip the entry block, because we already printed it. + if (&(*I) == &getEntry() || &(*I) == &getExit()) + continue; + + print_block(OS, this, *I, &Helper, true); + } + + // Print the exit block. + print_block(OS, this, getExit(), &Helper, true); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +void CFGBlock::dump(const CFG* cfg) const { print(*llvm::cerr.stream(), cfg); } + +/// print - A simple pretty printer of a CFGBlock that outputs to an ostream. +/// Generally this will only be called from CFG::print. +void CFGBlock::print(std::ostream& OS, const CFG* cfg) const { + StmtPrinterHelper Helper(cfg); + print_block(OS, cfg, *this, &Helper, true); +} + +/// printTerminator - A simple pretty printer of the terminator of a CFGBlock. +void CFGBlock::printTerminator(std::ostream& OS) const { + CFGBlockTerminatorPrint TPrinter(OS,NULL); + TPrinter.Visit(const_cast<Stmt*>(getTerminator())); +} + + +//===----------------------------------------------------------------------===// +// CFG Graphviz Visualization +//===----------------------------------------------------------------------===// + + +#ifndef NDEBUG +static StmtPrinterHelper* GraphHelper; +#endif + +void CFG::viewCFG() const { +#ifndef NDEBUG + StmtPrinterHelper H(this); + GraphHelper = &H; + llvm::ViewGraph(this,"CFG"); + GraphHelper = NULL; +#else + std::cerr << "CFG::viewCFG is only available in debug builds on " + << "systems with Graphviz or gv!\n"; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { + +#ifndef NDEBUG + std::ostringstream Out; + print_block(Out,Graph, *Node, GraphHelper, false); + std::string OutStr = Out.str(); + + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + + return OutStr; +#else + return ""; +#endif + } +}; +} // end namespace llvm diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp new file mode 100644 index 00000000000..7fa679cbc08 --- /dev/null +++ b/clang/lib/AST/Decl.cpp @@ -0,0 +1,652 @@ +//===--- Decl.cpp - Declaration AST Node Implementation -------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Decl class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/DenseMap.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Statistics +//===----------------------------------------------------------------------===// + +// temporary statistics gathering +static unsigned nFuncs = 0; +static unsigned nBlockVars = 0; +static unsigned nFileVars = 0; +static unsigned nParmVars = 0; +static unsigned nSUC = 0; +static unsigned nEnumConst = 0; +static unsigned nEnumDecls = 0; +static unsigned nTypedef = 0; +static unsigned nFieldDecls = 0; +static unsigned nInterfaceDecls = 0; +static unsigned nClassDecls = 0; +static unsigned nMethodDecls = 0; +static unsigned nProtocolDecls = 0; +static unsigned nForwardProtocolDecls = 0; +static unsigned nCategoryDecls = 0; +static unsigned nIvarDecls = 0; +static unsigned nObjCImplementationDecls = 0; +static unsigned nObjCCategoryImpl = 0; +static unsigned nObjCCompatibleAlias = 0; +static unsigned nObjCPropertyDecl = 0; +static unsigned nLinkageSpecDecl = 0; +static unsigned nFileScopeAsmDecl = 0; + +static bool StatSwitch = false; + +// This keeps track of all decl attributes. Since so few decls have attrs, we +// keep them in a hash map instead of wasting space in the Decl class. +typedef llvm::DenseMap<const Decl*, Attr*> DeclAttrMapTy; + +static DeclAttrMapTy *DeclAttrs = 0; + +const char *Decl::getDeclKindName() const { + switch (DeclKind) { + default: assert(0 && "Unknown decl kind!"); + case Typedef: return "Typedef"; + case Function: return "Function"; + case BlockVar: return "BlockVar"; + case FileVar: return "FileVar"; + case ParmVar: return "ParmVar"; + case EnumConstant: return "EnumConstant"; + case ObjCInterface: return "ObjCInterface"; + case ObjCClass: return "ObjCClass"; + case ObjCMethod: return "ObjCMethod"; + case ObjCProtocol: return "ObjCProtocol"; + case ObjCForwardProtocol: return "ObjCForwardProtocol"; + case Struct: return "Struct"; + case Union: return "Union"; + case Class: return "Class"; + case Enum: return "Enum"; + } +} + +bool Decl::CollectingStats(bool Enable) { + if (Enable) + StatSwitch = true; + return StatSwitch; +} + +void Decl::PrintStats() { + fprintf(stderr, "*** Decl Stats:\n"); + fprintf(stderr, " %d decls total.\n", + int(nFuncs+nBlockVars+nFileVars+nParmVars+nFieldDecls+nSUC+ + nEnumDecls+nEnumConst+nTypedef+nInterfaceDecls+nClassDecls+ + nMethodDecls+nProtocolDecls+nCategoryDecls+nIvarDecls)); + fprintf(stderr, " %d function decls, %d each (%d bytes)\n", + nFuncs, (int)sizeof(FunctionDecl), int(nFuncs*sizeof(FunctionDecl))); + fprintf(stderr, " %d block variable decls, %d each (%d bytes)\n", + nBlockVars, (int)sizeof(BlockVarDecl), + int(nBlockVars*sizeof(BlockVarDecl))); + fprintf(stderr, " %d file variable decls, %d each (%d bytes)\n", + nFileVars, (int)sizeof(FileVarDecl), + int(nFileVars*sizeof(FileVarDecl))); + fprintf(stderr, " %d parameter variable decls, %d each (%d bytes)\n", + nParmVars, (int)sizeof(ParmVarDecl), + int(nParmVars*sizeof(ParmVarDecl))); + fprintf(stderr, " %d field decls, %d each (%d bytes)\n", + nFieldDecls, (int)sizeof(FieldDecl), + int(nFieldDecls*sizeof(FieldDecl))); + fprintf(stderr, " %d struct/union/class decls, %d each (%d bytes)\n", + nSUC, (int)sizeof(RecordDecl), + int(nSUC*sizeof(RecordDecl))); + fprintf(stderr, " %d enum decls, %d each (%d bytes)\n", + nEnumDecls, (int)sizeof(EnumDecl), + int(nEnumDecls*sizeof(EnumDecl))); + fprintf(stderr, " %d enum constant decls, %d each (%d bytes)\n", + nEnumConst, (int)sizeof(EnumConstantDecl), + int(nEnumConst*sizeof(EnumConstantDecl))); + fprintf(stderr, " %d typedef decls, %d each (%d bytes)\n", + nTypedef, (int)sizeof(TypedefDecl),int(nTypedef*sizeof(TypedefDecl))); + // Objective-C decls... + fprintf(stderr, " %d interface decls, %d each (%d bytes)\n", + nInterfaceDecls, (int)sizeof(ObjCInterfaceDecl), + int(nInterfaceDecls*sizeof(ObjCInterfaceDecl))); + fprintf(stderr, " %d instance variable decls, %d each (%d bytes)\n", + nIvarDecls, (int)sizeof(ObjCIvarDecl), + int(nIvarDecls*sizeof(ObjCIvarDecl))); + fprintf(stderr, " %d class decls, %d each (%d bytes)\n", + nClassDecls, (int)sizeof(ObjCClassDecl), + int(nClassDecls*sizeof(ObjCClassDecl))); + fprintf(stderr, " %d method decls, %d each (%d bytes)\n", + nMethodDecls, (int)sizeof(ObjCMethodDecl), + int(nMethodDecls*sizeof(ObjCMethodDecl))); + fprintf(stderr, " %d protocol decls, %d each (%d bytes)\n", + nProtocolDecls, (int)sizeof(ObjCProtocolDecl), + int(nProtocolDecls*sizeof(ObjCProtocolDecl))); + fprintf(stderr, " %d forward protocol decls, %d each (%d bytes)\n", + nForwardProtocolDecls, (int)sizeof(ObjCForwardProtocolDecl), + int(nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl))); + fprintf(stderr, " %d category decls, %d each (%d bytes)\n", + nCategoryDecls, (int)sizeof(ObjCCategoryDecl), + int(nCategoryDecls*sizeof(ObjCCategoryDecl))); + + fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", + nObjCImplementationDecls, (int)sizeof(ObjCImplementationDecl), + int(nObjCImplementationDecls*sizeof(ObjCImplementationDecl))); + + fprintf(stderr, " %d class implementation decls, %d each (%d bytes)\n", + nObjCCategoryImpl, (int)sizeof(ObjCCategoryImplDecl), + int(nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl))); + + fprintf(stderr, " %d compatibility alias decls, %d each (%d bytes)\n", + nObjCCompatibleAlias, (int)sizeof(ObjCCompatibleAliasDecl), + int(nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl))); + + fprintf(stderr, " %d property decls, %d each (%d bytes)\n", + nObjCPropertyDecl, (int)sizeof(ObjCPropertyDecl), + int(nObjCPropertyDecl*sizeof(ObjCPropertyDecl))); + + fprintf(stderr, "Total bytes = %d\n", + int(nFuncs*sizeof(FunctionDecl)+nBlockVars*sizeof(BlockVarDecl)+ + nFileVars*sizeof(FileVarDecl)+nParmVars*sizeof(ParmVarDecl)+ + nFieldDecls*sizeof(FieldDecl)+nSUC*sizeof(RecordDecl)+ + nEnumDecls*sizeof(EnumDecl)+nEnumConst*sizeof(EnumConstantDecl)+ + nTypedef*sizeof(TypedefDecl)+ + nInterfaceDecls*sizeof(ObjCInterfaceDecl)+ + nIvarDecls*sizeof(ObjCIvarDecl)+ + nClassDecls*sizeof(ObjCClassDecl)+ + nMethodDecls*sizeof(ObjCMethodDecl)+ + nProtocolDecls*sizeof(ObjCProtocolDecl)+ + nForwardProtocolDecls*sizeof(ObjCForwardProtocolDecl)+ + nCategoryDecls*sizeof(ObjCCategoryDecl)+ + nObjCImplementationDecls*sizeof(ObjCImplementationDecl)+ + nObjCCategoryImpl*sizeof(ObjCCategoryImplDecl)+ + nObjCCompatibleAlias*sizeof(ObjCCompatibleAliasDecl)+ + nObjCPropertyDecl*sizeof(ObjCPropertyDecl)+ + nLinkageSpecDecl*sizeof(LinkageSpecDecl)+ + nFileScopeAsmDecl*sizeof(FileScopeAsmDecl))); + +} + +void Decl::addDeclKind(Kind k) { + switch (k) { + case Typedef: nTypedef++; break; + case Function: nFuncs++; break; + case BlockVar: nBlockVars++; break; + case FileVar: nFileVars++; break; + case ParmVar: nParmVars++; break; + case EnumConstant: nEnumConst++; break; + case Field: nFieldDecls++; break; + case Struct: case Union: case Class: nSUC++; break; + case Enum: nEnumDecls++; break; + case ObjCInterface: nInterfaceDecls++; break; + case ObjCClass: nClassDecls++; break; + case ObjCMethod: nMethodDecls++; break; + case ObjCProtocol: nProtocolDecls++; break; + case ObjCForwardProtocol: nForwardProtocolDecls++; break; + case ObjCCategory: nCategoryDecls++; break; + case ObjCIvar: nIvarDecls++; break; + case ObjCImplementation: nObjCImplementationDecls++; break; + case ObjCCategoryImpl: nObjCCategoryImpl++; break; + case CompatibleAlias: nObjCCompatibleAlias++; break; + case PropertyDecl: nObjCPropertyDecl++; break; + case LinkageSpec: nLinkageSpecDecl++; break; + case FileScopeAsm: nFileScopeAsmDecl++; break; + } +} + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +BlockVarDecl *BlockVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + StorageClass S, ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<BlockVarDecl>(); + return new (Mem) BlockVarDecl(L, Id, T, S, PrevDecl); +} + + +FileVarDecl *FileVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<FileVarDecl>(); + return new (Mem) FileVarDecl(L, Id, T, S, PrevDecl); +} + +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<ParmVarDecl>(); + return new (Mem) ParmVarDecl(L, Id, T, S, PrevDecl); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + StorageClass S, bool isInline, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<FunctionDecl>(); + return new (Mem) FunctionDecl(L, Id, T, S, isInline, PrevDecl); +} + + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V, + ScopedDecl *PrevDecl){ + void *Mem = C.getAllocator().Allocate<EnumConstantDecl>(); + return new (Mem) EnumConstantDecl(L, Id, T, E, V, PrevDecl); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, SourceLocation L, + IdentifierInfo *Id, QualType T, + ScopedDecl *PD) { + void *Mem = C.getAllocator().Allocate<TypedefDecl>(); + return new (Mem) TypedefDecl(L, Id, T, PD); +} + +EnumDecl *EnumDecl::Create(ASTContext &C, SourceLocation L, IdentifierInfo *Id, + ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<EnumDecl>(); + return new (Mem) EnumDecl(L, Id, PrevDecl); +} + +RecordDecl *RecordDecl::Create(ASTContext &C, Kind DK, SourceLocation L, + IdentifierInfo *Id, ScopedDecl *PrevDecl) { + void *Mem = C.getAllocator().Allocate<RecordDecl>(); + return new (Mem) RecordDecl(DK, L, Id, PrevDecl); +} + + +//===----------------------------------------------------------------------===// +// Decl Implementation +//===----------------------------------------------------------------------===// + +// Out-of-line virtual method providing a home for Decl. +Decl::~Decl() { + if (!HasAttrs) + return; + + DeclAttrMapTy::iterator it = DeclAttrs->find(this); + assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); + + delete it->second; + DeclAttrs->erase(it); + if (DeclAttrs->empty()) { + delete DeclAttrs; + DeclAttrs = 0; + } +} + +void Decl::addAttr(Attr *NewAttr) { + if (!DeclAttrs) + DeclAttrs = new llvm::DenseMap<const Decl*, Attr*>(); + + Attr *&ExistingAttr = (*DeclAttrs)[this]; + + NewAttr->setNext(ExistingAttr); + ExistingAttr = NewAttr; + + HasAttrs = true; +} + +const Attr *Decl::getAttrs() const { + if (!HasAttrs) + return 0; + + return (*DeclAttrs)[this]; +} + +const char *NamedDecl::getName() const { + if (const IdentifierInfo *II = getIdentifier()) + return II->getName(); + return ""; +} + +FunctionDecl::~FunctionDecl() { + delete[] ParamInfo; +} + +unsigned FunctionDecl::getNumParams() const { + if (isa<FunctionTypeNoProto>(getCanonicalType())) + return 0; + return cast<FunctionTypeProto>(getCanonicalType())->getNumArgs(); +} + +void FunctionDecl::setParams(ParmVarDecl **NewParamInfo, unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + assert(NumParams == getNumParams() && "Parameter count mismatch!"); + + // Zero params -> null pointer. + if (NumParams) { + ParamInfo = new ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + + +/// defineBody - When created, RecordDecl's correspond to a forward declared +/// record. This method is used to mark the decl as being defined, with the +/// specified contents. +void RecordDecl::defineBody(FieldDecl **members, unsigned numMembers) { + assert(!isDefinition() && "Cannot redefine record!"); + setDefinition(true); + NumMembers = numMembers; + if (numMembers) { + Members = new FieldDecl*[numMembers]; + memcpy(Members, members, numMembers*sizeof(Decl*)); + } +} + +FieldDecl* RecordDecl::getMember(IdentifierInfo *name) { + if (Members == 0 || NumMembers < 0) + return 0; + + // linear search. When C++ classes come along, will likely need to revisit. + for (int i = 0; i < NumMembers; ++i) { + if (Members[i]->getIdentifier() == name) + return Members[i]; + } + return 0; +} + +//===----------------------------------------------------------------------===// +// Objective-C Decl Implementation +//===----------------------------------------------------------------------===// + +void ObjCMethodDecl::setMethodParams(ParmVarDecl **NewParamInfo, + unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + + // Zero params -> null pointer. + if (NumParams) { + ParamInfo = new ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + NumMethodParams = NumParams; + } +} + +ObjCMethodDecl::~ObjCMethodDecl() { + delete[] ParamInfo; +} + +/// ObjCAddInstanceVariablesToClass - Inserts instance variables +/// into ObjCInterfaceDecl's fields. +/// +void ObjCInterfaceDecl::addInstanceVariablesToClass(ObjCIvarDecl **ivars, + unsigned numIvars, + SourceLocation RBrac) { + NumIvars = numIvars; + if (numIvars) { + Ivars = new ObjCIvarDecl*[numIvars]; + memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); + } + setLocEnd(RBrac); +} + +/// ObjCAddInstanceVariablesToClassImpl - Checks for correctness of Instance +/// Variables (Ivars) relative to what declared in @implementation;s class. +/// Ivars into ObjCImplementationDecl's fields. +/// +void ObjCImplementationDecl::ObjCAddInstanceVariablesToClassImpl( + ObjCIvarDecl **ivars, unsigned numIvars) { + NumIvars = numIvars; + if (numIvars) { + Ivars = new ObjCIvarDecl*[numIvars]; + memcpy(Ivars, ivars, numIvars*sizeof(ObjCIvarDecl*)); + } +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCInterfaceDecl's InsMethods and ClsMethods fields. +/// +void ObjCInterfaceDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCProtocolDecl's ProtoInsMethods and ProtoClsMethods fields. +/// +void ObjCProtocolDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +/// addMethods - Insert instance and methods declarations into +/// ObjCCategoryDecl's CatInsMethods and CatClsMethods fields. +/// +void ObjCCategoryDecl::addMethods(ObjCMethodDecl **insMethods, + unsigned numInsMembers, + ObjCMethodDecl **clsMethods, + unsigned numClsMembers, + SourceLocation endLoc) { + NumInstanceMethods = numInsMembers; + if (numInsMembers) { + InstanceMethods = new ObjCMethodDecl*[numInsMembers]; + memcpy(InstanceMethods, insMethods, numInsMembers*sizeof(ObjCMethodDecl*)); + } + NumClassMethods = numClsMembers; + if (numClsMembers) { + ClassMethods = new ObjCMethodDecl*[numClsMembers]; + memcpy(ClassMethods, clsMethods, numClsMembers*sizeof(ObjCMethodDecl*)); + } + AtEndLoc = endLoc; +} + +ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( + IdentifierInfo *ID, ObjCInterfaceDecl *&clsDeclared) { + ObjCInterfaceDecl* ClassDecl = this; + while (ClassDecl != NULL) { + for (ivar_iterator I = ClassDecl->ivar_begin(), E = ClassDecl->ivar_end(); + I != E; ++I) { + if ((*I)->getIdentifier() == ID) { + clsDeclared = ClassDecl; + return *I; + } + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +/// lookupInstanceMethod - This method returns an instance method by looking in +/// the class, its categories, and its super classes (using a linear search). +ObjCMethodDecl *ObjCInterfaceDecl::lookupInstanceMethod(Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getInstanceMethod(Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); + int numProtocols = ClassDecl->getNumIntfRefProtocols(); + for (int pIdx = 0; pIdx < numProtocols; pIdx++) { + if ((MethodDecl = protocols[pIdx]->getInstanceMethod(Sel))) + return MethodDecl; + } + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getInstanceMethod(Sel))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +// lookupClassMethod - This method returns a class method by looking in the +// class, its categories, and its super classes (using a linear search). +ObjCMethodDecl *ObjCInterfaceDecl::lookupClassMethod(Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getClassMethod(Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + ObjCProtocolDecl **protocols = ClassDecl->getReferencedProtocols(); + int numProtocols = ClassDecl->getNumIntfRefProtocols(); + for (int pIdx = 0; pIdx < numProtocols; pIdx++) { + if ((MethodDecl = protocols[pIdx]->getClassMethod(Sel))) + return MethodDecl; + } + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getClassMethod(Sel))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +/// lookupInstanceMethod - This method returns an instance method by looking in +/// the class implementation. Unlike interfaces, we don't look outside the +/// implementation. +ObjCMethodDecl *ObjCImplementationDecl::getInstanceMethod(Selector Sel) { + for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +/// lookupClassMethod - This method returns a class method by looking in +/// the class implementation. Unlike interfaces, we don't look outside the +/// implementation. +ObjCMethodDecl *ObjCImplementationDecl::getClassMethod(Selector Sel) { + for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); + I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupInstanceMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCCategoryImplDecl::getInstanceMethod(Selector Sel) { + for (instmeth_iterator I = instmeth_begin(), E = instmeth_end(); I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupClassMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCCategoryImplDecl::getClassMethod(Selector Sel) { + for (classmeth_iterator I = classmeth_begin(), E = classmeth_end(); + I != E; ++I) + if ((*I)->getSelector() == Sel) + return *I; + return NULL; +} + +// lookupInstanceMethod - Lookup a instance method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getInstanceMethod(Sel))) + return MethodDecl; + + if (getNumReferencedProtocols() > 0) { + ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); + + for (unsigned i = 0; i < getNumReferencedProtocols(); i++) { + if ((MethodDecl = RefPDecl[i]->getInstanceMethod(Sel))) + return MethodDecl; + } + } + return NULL; +} + +// lookupInstanceMethod - Lookup a class method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getClassMethod(Sel))) + return MethodDecl; + + if (getNumReferencedProtocols() > 0) { + ObjCProtocolDecl **RefPDecl = getReferencedProtocols(); + + for(unsigned i = 0; i < getNumReferencedProtocols(); i++) { + if ((MethodDecl = RefPDecl[i]->getClassMethod(Sel))) + return MethodDecl; + } + } + return NULL; +} + +/// getSynthesizedMethodSize - Compute size of synthesized method name +/// as done be the rewrite. +/// +unsigned ObjCMethodDecl::getSynthesizedMethodSize() const { + // syntesized method name is a concatenation of -/+[class-name selector] + // Get length of this name. + unsigned length = 3; // _I_ or _C_ + length += strlen(getClassInterface()->getName()) +1; // extra for _ + NamedDecl *MethodContext = getMethodContext(); + if (ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(MethodContext)) + length += strlen(CID->getName()) +1; + length += getSelector().getName().size(); // selector name + return length; +} + +ObjCInterfaceDecl *const ObjCMethodDecl::getClassInterface() const { + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(MethodContext)) + return ID; + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(MethodContext)) + return CD->getClassInterface(); + if (ObjCImplementationDecl *IMD = + dyn_cast<ObjCImplementationDecl>(MethodContext)) + return IMD->getClassInterface(); + if (ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(MethodContext)) + return CID->getClassInterface(); + assert(false && "unknown method context"); + return 0; +} diff --git a/clang/lib/AST/DeclSerialization.cpp b/clang/lib/AST/DeclSerialization.cpp new file mode 100644 index 00000000000..a7eaed5b2ef --- /dev/null +++ b/clang/lib/AST/DeclSerialization.cpp @@ -0,0 +1,463 @@ +//===--- DeclSerialization.cpp - Serialization of Decls ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines methods that implement bitcode serialization for Decls. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using llvm::Serializer; +using llvm::Deserializer; +using llvm::SerializedPtrID; + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Serialization: Dispatch code to handle specialized decl types. +//===----------------------------------------------------------------------===// + +void Decl::Emit(Serializer& S) const { + S.EmitInt(getKind()); + EmitImpl(S); +} + +Decl* Decl::Create(Deserializer& D) { + + Kind k = static_cast<Kind>(D.ReadInt()); + + switch (k) { + default: + assert (false && "Not implemented."); + break; + + case BlockVar: + return BlockVarDecl::CreateImpl(D); + + case Enum: + return EnumDecl::CreateImpl(D); + + case EnumConstant: + return EnumConstantDecl::CreateImpl(D); + + case Field: + return FieldDecl::CreateImpl(D); + + case FileVar: + return FileVarDecl::CreateImpl(D); + + case ParmVar: + return ParmVarDecl::CreateImpl(D); + + case Function: + return FunctionDecl::CreateImpl(D); + + case Union: + case Struct: + return RecordDecl::CreateImpl(k,D); + + case Typedef: + return TypedefDecl::CreateImpl(D); + + case FileScopeAsm: + return FileScopeAsmDecl::CreateImpl(D); + } +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of Decl. +//===----------------------------------------------------------------------===// + +void Decl::EmitInRec(Serializer& S) const { + S.Emit(getLocation()); // From Decl. +} + +void Decl::ReadInRec(Deserializer& D) { + Loc = SourceLocation::ReadVal(D); // From Decl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of NamedDecl. +//===----------------------------------------------------------------------===// + +void NamedDecl::EmitInRec(Serializer& S) const { + Decl::EmitInRec(S); + S.EmitPtr(getIdentifier()); // From NamedDecl. +} + +void NamedDecl::ReadInRec(Deserializer& D) { + Decl::ReadInRec(D); + D.ReadPtr(Identifier); // From NamedDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of ScopedDecl. +//===----------------------------------------------------------------------===// + +void ScopedDecl::EmitInRec(Serializer& S) const { + NamedDecl::EmitInRec(S); + S.EmitPtr(getNext()); // From ScopedDecl. +} + +void ScopedDecl::ReadInRec(Deserializer& D) { + NamedDecl::ReadInRec(D); + D.ReadPtr(Next); // From ScopedDecl. +} + + //===------------------------------------------------------------===// + // NOTE: Not all subclasses of ScopedDecl will use the "OutRec" // + // methods. This is because owned pointers are usually "batched" // + // together for efficiency. // + //===------------------------------------------------------------===// + +void ScopedDecl::EmitOutRec(Serializer& S) const { + S.EmitOwnedPtr(getNextDeclarator()); // From ScopedDecl. +} + +void ScopedDecl::ReadOutRec(Deserializer& D) { + NextDeclarator = + cast_or_null<ScopedDecl>(D.ReadOwnedPtr<Decl>()); // From ScopedDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of ValueDecl. +//===----------------------------------------------------------------------===// + +void ValueDecl::EmitInRec(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.Emit(getType()); // From ValueDecl. +} + +void ValueDecl::ReadInRec(Deserializer& D) { + ScopedDecl::ReadInRec(D); + DeclType = QualType::ReadVal(D); // From ValueDecl. +} + +//===----------------------------------------------------------------------===// +// Common serialization logic for subclasses of VarDecl. +//===----------------------------------------------------------------------===// + +void VarDecl::EmitInRec(Serializer& S) const { + ValueDecl::EmitInRec(S); + S.EmitInt(getStorageClass()); // From VarDecl. +} + +void VarDecl::ReadInRec(Deserializer& D) { + ValueDecl::ReadInRec(D); + SClass = static_cast<StorageClass>(D.ReadInt()); // From VarDecl. +} + + //===------------------------------------------------------------===// + // NOTE: VarDecl has its own "OutRec" methods that doesn't use // + // the one define in ScopedDecl. This is to batch emit the // + // owned pointers, which results in a smaller output. + //===------------------------------------------------------------===// + +void VarDecl::EmitOutRec(Serializer& S) const { + // Emit these last because they will create records of their own. + S.BatchEmitOwnedPtrs(getInit(), // From VarDecl. + getNextDeclarator()); // From ScopedDecl. +} + +void VarDecl::ReadOutRec(Deserializer& D) { + Decl* next_declarator; + + D.BatchReadOwnedPtrs(Init, // From VarDecl. + next_declarator); // From ScopedDecl. + + setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator)); +} + + +void VarDecl::EmitImpl(Serializer& S) const { + VarDecl::EmitInRec(S); + VarDecl::EmitOutRec(S); +} + +void VarDecl::ReadImpl(Deserializer& D) { + ReadInRec(D); + ReadOutRec(D); +} + +//===----------------------------------------------------------------------===// +// BlockVarDecl Serialization. +//===----------------------------------------------------------------------===// + +BlockVarDecl* BlockVarDecl::CreateImpl(Deserializer& D) { + BlockVarDecl* decl = + new BlockVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// FileVarDecl Serialization. +//===----------------------------------------------------------------------===// + +FileVarDecl* FileVarDecl::CreateImpl(Deserializer& D) { + FileVarDecl* decl = + new FileVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// ParmDecl Serialization. +//===----------------------------------------------------------------------===// + +void ParmVarDecl::EmitImpl(llvm::Serializer& S) const { + VarDecl::EmitImpl(S); + S.EmitInt(getObjCDeclQualifier()); // From ParmVarDecl. +} + +ParmVarDecl* ParmVarDecl::CreateImpl(Deserializer& D) { + ParmVarDecl* decl = + new ParmVarDecl(SourceLocation(),NULL,QualType(),None,NULL); + + decl->VarDecl::ReadImpl(D); + decl->objcDeclQualifier = static_cast<ObjCDeclQualifier>(D.ReadInt()); + + return decl; +} + +//===----------------------------------------------------------------------===// +// EnumDecl Serialization. +//===----------------------------------------------------------------------===// + +void EnumDecl::EmitImpl(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.EmitBool(isDefinition()); + S.Emit(IntegerType); + S.BatchEmitOwnedPtrs(ElementList,getNextDeclarator()); +} + +EnumDecl* EnumDecl::CreateImpl(Deserializer& D) { + EnumDecl* decl = new EnumDecl(SourceLocation(),NULL,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->setDefinition(D.ReadBool()); + decl->IntegerType = QualType::ReadVal(D); + + Decl* next_declarator; + Decl* Elist; + + D.BatchReadOwnedPtrs(Elist,next_declarator); + + decl->ElementList = cast_or_null<EnumConstantDecl>(Elist); + decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// EnumConstantDecl Serialization. +//===----------------------------------------------------------------------===// + +void EnumConstantDecl::EmitImpl(Serializer& S) const { + S.Emit(Val); + ValueDecl::EmitInRec(S); + S.BatchEmitOwnedPtrs(getNextDeclarator(),Init); +} + +EnumConstantDecl* EnumConstantDecl::CreateImpl(Deserializer& D) { + llvm::APSInt val(1); + D.Read(val); + + EnumConstantDecl* decl = + new EnumConstantDecl(SourceLocation(),NULL,QualType(),NULL, + val,NULL); + + decl->ValueDecl::ReadInRec(D); + + Decl* next_declarator; + + D.BatchReadOwnedPtrs(next_declarator,decl->Init); + + decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// FieldDecl Serialization. +//===----------------------------------------------------------------------===// + +void FieldDecl::EmitImpl(Serializer& S) const { + S.Emit(getType()); + NamedDecl::EmitInRec(S); + S.EmitOwnedPtr(BitWidth); +} + +FieldDecl* FieldDecl::CreateImpl(Deserializer& D) { + FieldDecl* decl = new FieldDecl(SourceLocation(),NULL,QualType()); + decl->DeclType.ReadBackpatch(D); + decl->ReadInRec(D); + decl->BitWidth = D.ReadOwnedPtr<Expr>(); + return decl; +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Serialization. +//===----------------------------------------------------------------------===// + +void FunctionDecl::EmitImpl(Serializer& S) const { + S.EmitInt(SClass); // From FunctionDecl. + S.EmitBool(IsInline); // From FunctionDecl. + ValueDecl::EmitInRec(S); + S.EmitPtr(DeclChain); + + // NOTE: We do not need to serialize out the number of parameters, because + // that is encoded in the type (accessed via getNumParams()). + + if (ParamInfo != NULL) { + S.EmitBool(true); + S.BatchEmitOwnedPtrs(getNumParams(),&ParamInfo[0], Body, + getNextDeclarator()); + } + else { + S.EmitBool(false); + S.BatchEmitOwnedPtrs(Body,getNextDeclarator()); + } +} + +FunctionDecl* FunctionDecl::CreateImpl(Deserializer& D) { + StorageClass SClass = static_cast<StorageClass>(D.ReadInt()); + bool IsInline = D.ReadBool(); + + FunctionDecl* decl = + new FunctionDecl(SourceLocation(),NULL,QualType(),SClass, IsInline, 0); + + decl->ValueDecl::ReadInRec(D); + D.ReadPtr(decl->DeclChain); + + Decl* next_declarator; + + bool hasParamDecls = D.ReadBool(); + + decl->ParamInfo = hasParamDecls + ? new ParmVarDecl*[decl->getNumParams()] + : NULL; + + if (hasParamDecls) + D.BatchReadOwnedPtrs(decl->getNumParams(), + reinterpret_cast<Decl**>(&decl->ParamInfo[0]), + decl->Body, next_declarator); + else + D.BatchReadOwnedPtrs(decl->Body, next_declarator); + + decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator)); + + return decl; +} + +//===----------------------------------------------------------------------===// +// RecordDecl Serialization. +//===----------------------------------------------------------------------===// + +void RecordDecl::EmitImpl(Serializer& S) const { + ScopedDecl::EmitInRec(S); + S.EmitBool(isDefinition()); + S.EmitBool(hasFlexibleArrayMember()); + S.EmitSInt(getNumMembers()); + if (getNumMembers() > 0) { + assert (Members); + S.BatchEmitOwnedPtrs((unsigned) getNumMembers(), + (Decl**) &Members[0],getNextDeclarator()); + } + else + ScopedDecl::EmitOutRec(S); +} + +RecordDecl* RecordDecl::CreateImpl(Decl::Kind DK, Deserializer& D) { + RecordDecl* decl = new RecordDecl(DK,SourceLocation(),NULL,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->setDefinition(D.ReadBool()); + decl->setHasFlexibleArrayMember(D.ReadBool()); + decl->NumMembers = D.ReadSInt(); + + if (decl->getNumMembers() > 0) { + Decl* next_declarator; + decl->Members = new FieldDecl*[(unsigned) decl->getNumMembers()]; + + D.BatchReadOwnedPtrs((unsigned) decl->getNumMembers(), + (Decl**) &decl->Members[0], + next_declarator); + + decl->setNextDeclarator(cast_or_null<ScopedDecl>(next_declarator)); + } + else + decl->ScopedDecl::ReadOutRec(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// TypedefDecl Serialization. +//===----------------------------------------------------------------------===// + +void TypedefDecl::EmitImpl(Serializer& S) const { + S.Emit(UnderlyingType); + ScopedDecl::EmitInRec(S); + ScopedDecl::EmitOutRec(S); +} + +TypedefDecl* TypedefDecl::CreateImpl(Deserializer& D) { + QualType T = QualType::ReadVal(D); + + TypedefDecl* decl = new TypedefDecl(SourceLocation(),NULL,T,NULL); + + decl->ScopedDecl::ReadInRec(D); + decl->ScopedDecl::ReadOutRec(D); + + return decl; +} + +//===----------------------------------------------------------------------===// +// LinkageSpec Serialization. +//===----------------------------------------------------------------------===// + +void LinkageSpecDecl::EmitInRec(Serializer& S) const { + Decl::EmitInRec(S); + S.EmitInt(getLanguage()); + S.EmitPtr(D); +} + +void LinkageSpecDecl::ReadInRec(Deserializer& D) { + Decl::ReadInRec(D); + Language = static_cast<LanguageIDs>(D.ReadInt()); + D.ReadPtr(this->D); +} + +//===----------------------------------------------------------------------===// +// FileScopeAsm Serialization. +//===----------------------------------------------------------------------===// + +void FileScopeAsmDecl::EmitImpl(llvm::Serializer& S) const +{ + Decl::EmitInRec(S); + S.EmitOwnedPtr(AsmString); +} + +FileScopeAsmDecl* FileScopeAsmDecl::CreateImpl(Deserializer& D) { + FileScopeAsmDecl* decl = new FileScopeAsmDecl(SourceLocation(), 0); + + decl->Decl::ReadInRec(D); + decl->AsmString = cast<StringLiteral>(D.ReadOwnedPtr<Expr>()); +// D.ReadOwnedPtr(D.ReadOwnedPtr<StringLiteral>())<#T * * Ptr#>, <#bool AutoRegister#>)(decl->AsmString); + + return decl; +} diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp new file mode 100644 index 00000000000..11fcc419a51 --- /dev/null +++ b/clang/lib/AST/Expr.cpp @@ -0,0 +1,1391 @@ +//===--- Expr.cpp - Expression AST Node Implementation --------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Expr class and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +StringLiteral::StringLiteral(const char *strData, unsigned byteLength, + bool Wide, QualType t, SourceLocation firstLoc, + SourceLocation lastLoc) : + Expr(StringLiteralClass, t) { + // OPTIMIZE: could allocate this appended to the StringLiteral. + char *AStrData = new char[byteLength]; + memcpy(AStrData, strData, byteLength); + StrData = AStrData; + ByteLength = byteLength; + IsWide = Wide; + firstTokLoc = firstLoc; + lastTokLoc = lastLoc; +} + +StringLiteral::~StringLiteral() { + delete[] StrData; +} + +bool UnaryOperator::isPostfix(Opcode Op) { + switch (Op) { + case PostInc: + case PostDec: + return true; + default: + return false; + } +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "sizeof" or "[pre]++". +const char *UnaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown unary operator"); + case PostInc: return "++"; + case PostDec: return "--"; + case PreInc: return "++"; + case PreDec: return "--"; + case AddrOf: return "&"; + case Deref: return "*"; + case Plus: return "+"; + case Minus: return "-"; + case Not: return "~"; + case LNot: return "!"; + case Real: return "__real"; + case Imag: return "__imag"; + case SizeOf: return "sizeof"; + case AlignOf: return "alignof"; + case Extension: return "__extension__"; + case OffsetOf: return "__builtin_offsetof"; + } +} + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + + +CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t, + SourceLocation rparenloc) + : Expr(CallExprClass, t), NumArgs(numargs) { + SubExprs = new Expr*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + RParenLoc = rparenloc; +} + +/// setNumArgs - This changes the number of arguments present in this call. +/// Any orphaned expressions are deleted by this, and any new operands are set +/// to null. +void CallExpr::setNumArgs(unsigned NumArgs) { + // No change, just return. + if (NumArgs == getNumArgs()) return; + + // If shrinking # arguments, just delete the extras and forgot them. + if (NumArgs < getNumArgs()) { + for (unsigned i = NumArgs, e = getNumArgs(); i != e; ++i) + delete getArg(i); + this->NumArgs = NumArgs; + return; + } + + // Otherwise, we are growing the # arguments. New an bigger argument array. + Expr **NewSubExprs = new Expr*[NumArgs+1]; + // Copy over args. + for (unsigned i = 0; i != getNumArgs()+ARGS_START; ++i) + NewSubExprs[i] = SubExprs[i]; + // Null out new args. + for (unsigned i = getNumArgs()+ARGS_START; i != NumArgs+ARGS_START; ++i) + NewSubExprs[i] = 0; + + delete[] SubExprs; + SubExprs = NewSubExprs; + this->NumArgs = NumArgs; +} + +bool CallExpr::isBuiltinConstantExpr() const { + // All simple function calls (e.g. func()) are implicitly cast to pointer to + // function. As a result, we try and obtain the DeclRefExpr from the + // ImplicitCastExpr. + const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return false; + + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); + if (!DRE) + return false; + + const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (!FDecl) + return false; + + unsigned builtinID = FDecl->getIdentifier()->getBuiltinID(); + if (!builtinID) + return false; + + // We have a builtin that is a constant expression + if (builtinID == Builtin::BI__builtin___CFStringMakeConstantString) + return true; + return false; +} + +bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const { + // The following enum mimics gcc's internal "typeclass.h" file. + enum gcc_type_class { + no_type_class = -1, + void_type_class, integer_type_class, char_type_class, + enumeral_type_class, boolean_type_class, + pointer_type_class, reference_type_class, offset_type_class, + real_type_class, complex_type_class, + function_type_class, method_type_class, + record_type_class, union_type_class, + array_type_class, string_type_class, + lang_type_class + }; + Result.setIsSigned(true); + + // All simple function calls (e.g. func()) are implicitly cast to pointer to + // function. As a result, we try and obtain the DeclRefExpr from the + // ImplicitCastExpr. + const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return false; + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); + if (!DRE) + return false; + + // We have a DeclRefExpr. + if (strcmp(DRE->getDecl()->getName(), "__builtin_classify_type") == 0) { + // If no argument was supplied, default to "no_type_class". This isn't + // ideal, however it's what gcc does. + Result = static_cast<uint64_t>(no_type_class); + if (NumArgs >= 1) { + QualType argType = getArg(0)->getType(); + + if (argType->isVoidType()) + Result = void_type_class; + else if (argType->isEnumeralType()) + Result = enumeral_type_class; + else if (argType->isBooleanType()) + Result = boolean_type_class; + else if (argType->isCharType()) + Result = string_type_class; // gcc doesn't appear to use char_type_class + else if (argType->isIntegerType()) + Result = integer_type_class; + else if (argType->isPointerType()) + Result = pointer_type_class; + else if (argType->isReferenceType()) + Result = reference_type_class; + else if (argType->isRealType()) + Result = real_type_class; + else if (argType->isComplexType()) + Result = complex_type_class; + else if (argType->isFunctionType()) + Result = function_type_class; + else if (argType->isStructureType()) + Result = record_type_class; + else if (argType->isUnionType()) + Result = union_type_class; + else if (argType->isArrayType()) + Result = array_type_class; + else if (argType->isUnionType()) + Result = union_type_class; + else // FIXME: offset_type_class, method_type_class, & lang_type_class? + assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); + } + return true; + } + return false; +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + default: assert(0 && "Unknown binary operator"); + case Mul: return "*"; + case Div: return "/"; + case Rem: return "%"; + case Add: return "+"; + case Sub: return "-"; + case Shl: return "<<"; + case Shr: return ">>"; + case LT: return "<"; + case GT: return ">"; + case LE: return "<="; + case GE: return ">="; + case EQ: return "=="; + case NE: return "!="; + case And: return "&"; + case Xor: return "^"; + case Or: return "|"; + case LAnd: return "&&"; + case LOr: return "||"; + case Assign: return "="; + case MulAssign: return "*="; + case DivAssign: return "/="; + case RemAssign: return "%="; + case AddAssign: return "+="; + case SubAssign: return "-="; + case ShlAssign: return "<<="; + case ShrAssign: return ">>="; + case AndAssign: return "&="; + case XorAssign: return "^="; + case OrAssign: return "|="; + case Comma: return ","; + } +} + +InitListExpr::InitListExpr(SourceLocation lbraceloc, + Expr **initexprs, unsigned numinits, + SourceLocation rbraceloc) + : Expr(InitListExprClass, QualType()) + , NumInits(numinits) + , LBraceLoc(lbraceloc) + , RBraceLoc(rbraceloc) +{ + InitExprs = new Expr*[numinits]; + for (unsigned i = 0; i != numinits; i++) + InitExprs[i] = initexprs[i]; +} + +//===----------------------------------------------------------------------===// +// Generic Expression Routines +//===----------------------------------------------------------------------===// + +/// hasLocalSideEffect - Return true if this immediate expression has side +/// effects, not counting any sub-expressions. +bool Expr::hasLocalSideEffect() const { + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->hasLocalSideEffect(); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(this); + + switch (UO->getOpcode()) { + default: return false; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + return true; // ++/-- + + case UnaryOperator::Deref: + // Dereferencing a volatile pointer is a side-effect. + return getType().isVolatileQualified(); + case UnaryOperator::Real: + case UnaryOperator::Imag: + // accessing a piece of a volatile complex is a side-effect. + return UO->getSubExpr()->getType().isVolatileQualified(); + + case UnaryOperator::Extension: + return UO->getSubExpr()->hasLocalSideEffect(); + } + } + case BinaryOperatorClass: { + const BinaryOperator *BinOp = cast<BinaryOperator>(this); + // Consider comma to have side effects if the LHS and RHS both do. + if (BinOp->getOpcode() == BinaryOperator::Comma) + return BinOp->getLHS()->hasLocalSideEffect() && + BinOp->getRHS()->hasLocalSideEffect(); + + return BinOp->isAssignmentOp(); + } + case CompoundAssignOperatorClass: + return true; + + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + return Exp->getCond()->hasLocalSideEffect() + || (Exp->getLHS() && Exp->getLHS()->hasLocalSideEffect()) + || (Exp->getRHS() && Exp->getRHS()->hasLocalSideEffect()); + } + + case MemberExprClass: + case ArraySubscriptExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // if is a side effect. + return getType().isVolatileQualified(); + + case CallExprClass: + // TODO: check attributes for pure/const. "void foo() { strlen("bar"); }" + // should warn. + return true; + case ObjCMessageExprClass: + return true; + + case CastExprClass: + // If this is a cast to void, check the operand. Otherwise, the result of + // the cast is unused. + if (getType()->isVoidType()) + return cast<CastExpr>(this)->getSubExpr()->hasLocalSideEffect(); + return false; + } +} + +/// isLvalue - C99 6.3.2.1: an lvalue is an expression with an object type or an +/// incomplete type other than void. Nonarray expressions that can be lvalues: +/// - name, where name must be a variable +/// - e[i] +/// - (e), where e must be an lvalue +/// - e.name, where e must be an lvalue +/// - e->name +/// - *e, the type of e cannot be a function type +/// - string-constant +/// - (__real__ e) and (__imag__ e) where e is an lvalue [GNU extension] +/// - reference type [C++ [expr]] +/// +Expr::isLvalueResult Expr::isLvalue() const { + // first, check the type (C99 6.3.2.1) + if (TR->isFunctionType()) // from isObjectType() + return LV_NotObjectType; + + // Allow qualified void which is an incomplete type other than void (yuck). + if (TR->isVoidType() && !TR.getCanonicalType().getCVRQualifiers()) + return LV_IncompleteVoidType; + + if (TR->isReferenceType()) // C++ [expr] + return LV_Valid; + + // the type looks fine, now check the expression + switch (getStmtClass()) { + case StringLiteralClass: // C99 6.5.1p4 + return LV_Valid; + case ArraySubscriptExprClass: // C99 6.5.3p4 (e1[e2] == (*((e1)+(e2)))) + // For vectors, make sure base is an lvalue (i.e. not a function call). + if (cast<ArraySubscriptExpr>(this)->getBase()->getType()->isVectorType()) + return cast<ArraySubscriptExpr>(this)->getBase()->isLvalue(); + return LV_Valid; + case DeclRefExprClass: // C99 6.5.1p2 + if (isa<VarDecl>(cast<DeclRefExpr>(this)->getDecl())) + return LV_Valid; + break; + case MemberExprClass: { // C99 6.5.2.3p4 + const MemberExpr *m = cast<MemberExpr>(this); + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(); + } + case UnaryOperatorClass: + if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Deref) + return LV_Valid; // C99 6.5.3p4 + + if (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Real || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Imag) + return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(); // GNU. + break; + case ParenExprClass: // C99 6.5.1p5 + return cast<ParenExpr>(this)->getSubExpr()->isLvalue(); + case CompoundLiteralExprClass: // C99 6.5.2.5p5 + return LV_Valid; + case OCUVectorElementExprClass: + if (cast<OCUVectorElementExpr>(this)->containsDuplicateElements()) + return LV_DuplicateVectorComponents; + return LV_Valid; + case ObjCIvarRefExprClass: // ObjC instance variables are lvalues. + return LV_Valid; + case PreDefinedExprClass: + return LV_Valid; + default: + break; + } + return LV_InvalidExpression; +} + +/// isModifiableLvalue - C99 6.3.2.1: an lvalue that does not have array type, +/// does not have an incomplete type, does not have a const-qualified type, and +/// if it is a structure or union, does not have any member (including, +/// recursively, any member or element of all contained aggregates or unions) +/// with a const-qualified type. +Expr::isModifiableLvalueResult Expr::isModifiableLvalue() const { + isLvalueResult lvalResult = isLvalue(); + + switch (lvalResult) { + case LV_Valid: break; + case LV_NotObjectType: return MLV_NotObjectType; + case LV_IncompleteVoidType: return MLV_IncompleteVoidType; + case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; + case LV_InvalidExpression: return MLV_InvalidExpression; + } + if (TR.isConstQualified()) + return MLV_ConstQualified; + if (TR->isArrayType()) + return MLV_ArrayType; + if (TR->isIncompleteType()) + return MLV_IncompleteType; + + if (const RecordType *r = dyn_cast<RecordType>(TR.getCanonicalType())) { + if (r->hasConstFields()) + return MLV_ConstQualified; + } + return MLV_Valid; +} + +/// hasGlobalStorage - Return true if this expression has static storage +/// duration. This means that the address of this expression is a link-time +/// constant. +bool Expr::hasGlobalStorage() const { + switch (getStmtClass()) { + default: + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->hasGlobalStorage(); + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->getSubExpr()->hasGlobalStorage(); + case CompoundLiteralExprClass: + return cast<CompoundLiteralExpr>(this)->isFileScope(); + case DeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->hasGlobalStorage(); + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(this); + return !M->isArrow() && M->getBase()->hasGlobalStorage(); + } + case ArraySubscriptExprClass: + return cast<ArraySubscriptExpr>(this)->getBase()->hasGlobalStorage(); + case PreDefinedExprClass: + return true; + } +} + +Expr* Expr::IgnoreParens() { + Expr* E = this; + while (ParenExpr* P = dyn_cast<ParenExpr>(E)) + E = P->getSubExpr(); + + return E; +} + +/// IgnoreParenCasts - Ignore parentheses and casts. Strip off any ParenExpr +/// or CastExprs or ImplicitCastExprs, returning their operand. +Expr *Expr::IgnoreParenCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) + E = P->getSubExpr(); + else if (CastExpr *P = dyn_cast<CastExpr>(E)) + E = P->getSubExpr(); + else if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) + E = P->getSubExpr(); + else + return E; + } +} + + +bool Expr::isConstantExpr(ASTContext &Ctx, SourceLocation *Loc) const { + switch (getStmtClass()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->isConstantExpr(Ctx, Loc); + case StringLiteralClass: + case ObjCStringLiteralClass: + case FloatingLiteralClass: + case IntegerLiteralClass: + case CharacterLiteralClass: + case ImaginaryLiteralClass: + case TypesCompatibleExprClass: + case CXXBoolLiteralExprClass: + return true; + case CallExprClass: { + const CallExpr *CE = cast<CallExpr>(this); + llvm::APSInt Result(32); + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + if (CE->isBuiltinClassifyType(Result)) + return true; + if (CE->isBuiltinConstantExpr()) + return true; + if (Loc) *Loc = getLocStart(); + return false; + } + case DeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + // Accept address of function. + if (isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D)) + return true; + if (Loc) *Loc = getLocStart(); + if (isa<VarDecl>(D)) + return TR->isArrayType(); + return false; + } + case CompoundLiteralExprClass: + if (Loc) *Loc = getLocStart(); + // Allow "(int []){2,4}", since the array will be converted to a pointer. + // Allow "(vector type){2,4}" since the elements are all constant. + return TR->isArrayType() || TR->isVectorType(); + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(this); + + // C99 6.6p9 + if (Exp->getOpcode() == UnaryOperator::AddrOf) { + if (!Exp->getSubExpr()->hasGlobalStorage()) { + if (Loc) *Loc = getLocStart(); + return false; + } + return true; + } + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (!Exp->isSizeOfAlignOfOp() && + Exp->getOpcode() != UnaryOperator::OffsetOf && + !Exp->getSubExpr()->isConstantExpr(Ctx, Loc)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + case UnaryOperator::Extension: + return true; // FIXME: this is wrong. + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + case UnaryOperator::OffsetOf: + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + return true; + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + return true; + } + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this); + // alignof always evaluates to a constant. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isVoidType() && + !Exp->getArgumentType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + return true; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->isConstantExpr(Ctx, Loc)) + return false; + + if (!Exp->getRHS()->isConstantExpr(Ctx, Loc)) + return false; + return true; + } + case ImplicitCastExprClass: + case CastExprClass: { + const Expr *SubExpr; + SourceLocation CastLoc; + if (const CastExpr *C = dyn_cast<CastExpr>(this)) { + SubExpr = C->getSubExpr(); + CastLoc = C->getLParenLoc(); + } else { + SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr(); + CastLoc = getLocStart(); + } + if (!SubExpr->isConstantExpr(Ctx, Loc)) { + if (Loc) *Loc = SubExpr->getLocStart(); + return false; + } + return true; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + if (!Exp->getCond()->isConstantExpr(Ctx, Loc) || + // Handle the GNU extension for missing LHS. + !(Exp->getLHS() && Exp->getLHS()->isConstantExpr(Ctx, Loc)) || + !Exp->getRHS()->isConstantExpr(Ctx, Loc)) + return false; + return true; + } + case InitListExprClass: { + const InitListExpr *Exp = cast<InitListExpr>(this); + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!Exp->getInit(i)->isConstantExpr(Ctx, Loc)) { + if (Loc) *Loc = Exp->getInit(i)->getLocStart(); + return false; + } + } + return true; + } + } +} + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. Note: With the introduction of VLA's in +/// C99 the result of the sizeof operator is no longer always a constant +/// expression. The generalization of the wording to include any subexpression +/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions +/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance, +/// "0 || f()" can be treated as a constant expression. In C90 this expression, +/// occurring in a context requiring a constant, would have been a constraint +/// violation. FIXME: This routine currently implements C90 semantics. +/// To properly implement C99 semantics this routine will need to evaluate +/// expressions involving operators previously mentioned. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not +/// permit this. This includes things like (int)1e1000 +/// +/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof +/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer +/// cast+dereference. +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc, bool isEvaluated) const { + switch (getStmtClass()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()-> + isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated); + case IntegerLiteralClass: + Result = cast<IntegerLiteral>(this)->getValue(); + break; + case CharacterLiteralClass: { + const CharacterLiteral *CL = cast<CharacterLiteral>(this); + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + Result = CL->getValue(); + Result.setIsUnsigned(!getType()->isSignedIntegerType()); + break; + } + case TypesCompatibleExprClass: { + const TypesCompatibleExpr *TCE = cast<TypesCompatibleExpr>(this); + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + Result = Ctx.typesAreCompatible(TCE->getArgType1(), TCE->getArgType2()); + break; + } + case CallExprClass: { + const CallExpr *CE = cast<CallExpr>(this); + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + if (CE->isBuiltinClassifyType(Result)) + break; + if (Loc) *Loc = getLocStart(); + return false; + } + case DeclRefExprClass: + if (const EnumConstantDecl *D = + dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) { + Result = D->getInitVal(); + break; + } + if (Loc) *Loc = getLocStart(); + return false; + case UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(this); + + // Get the operand value. If this is sizeof/alignof, do not evalute the + // operand. This affects C99 6.6p3. + if (!Exp->isSizeOfAlignOfOp() && !Exp->isOffsetOfOp() && + !Exp->getSubExpr()->isIntegerConstantExpr(Result, Ctx, Loc,isEvaluated)) + return false; + + switch (Exp->getOpcode()) { + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + default: + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + case UnaryOperator::Extension: + return true; // FIXME: this is wrong. + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + // Return the result in the right width. + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getSubExpr()->getType()->isVoidType()) { + Result = 1; + break; + } + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!Exp->getSubExpr()->getType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + + // Get information about the size or align. + if (Exp->getSubExpr()->getType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + Result = Exp->getOpcode() == UnaryOperator::AlignOf ? 4 : 1; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->getOpcode() == UnaryOperator::AlignOf) + Result = Ctx.getTypeAlign(Exp->getSubExpr()->getType()) / CharSize; + else + Result = Ctx.getTypeSize(Exp->getSubExpr()->getType()) / CharSize; + } + break; + case UnaryOperator::LNot: { + bool Val = Result == 0; + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + Result = Val; + break; + } + case UnaryOperator::Plus: + break; + case UnaryOperator::Minus: + Result = -Result; + break; + case UnaryOperator::Not: + Result = ~Result; + break; + case UnaryOperator::OffsetOf: + Result = Exp->evaluateOffsetOf(Ctx); + } + break; + } + case SizeOfAlignOfTypeExprClass: { + const SizeOfAlignOfTypeExpr *Exp = cast<SizeOfAlignOfTypeExpr>(this); + + // Return the result in the right width. + Result.zextOrTrunc(static_cast<uint32_t>(Ctx.getTypeSize(getType()))); + + // sizeof(void) and __alignof__(void) = 1 as a gcc extension. + if (Exp->getArgumentType()->isVoidType()) { + Result = 1; + break; + } + + // alignof always evaluates to a constant, sizeof does if arg is not VLA. + if (Exp->isSizeOf() && !Exp->getArgumentType()->isConstantSizeType()) { + if (Loc) *Loc = Exp->getOperatorLoc(); + return false; + } + + // Get information about the size or align. + if (Exp->getArgumentType()->isFunctionType()) { + // GCC extension: sizeof(function) = 1. + Result = Exp->isSizeOf() ? 1 : 4; + } else { + unsigned CharSize = Ctx.Target.getCharWidth(); + if (Exp->isSizeOf()) + Result = Ctx.getTypeSize(Exp->getArgumentType()) / CharSize; + else + Result = Ctx.getTypeAlign(Exp->getArgumentType()) / CharSize; + } + break; + } + case BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(this); + + // The LHS of a constant expr is always evaluated and needed. + if (!Exp->getLHS()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + llvm::APSInt RHS(Result); + + // The short-circuiting &&/|| operators don't necessarily evaluate their + // RHS. Make sure to pass isEvaluated down correctly. + if (Exp->isLogicalOp()) { + bool RHSEval; + if (Exp->getOpcode() == BinaryOperator::LAnd) + RHSEval = Result != 0; + else { + assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical"); + RHSEval = Result == 0; + } + + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, + isEvaluated & RHSEval)) + return false; + } else { + if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, isEvaluated)) + return false; + } + + switch (Exp->getOpcode()) { + default: + if (Loc) *Loc = getLocStart(); + return false; + case BinaryOperator::Mul: + Result *= RHS; + break; + case BinaryOperator::Div: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result /= RHS; + break; + case BinaryOperator::Rem: + if (RHS == 0) { + if (!isEvaluated) break; + if (Loc) *Loc = getLocStart(); + return false; + } + Result %= RHS; + break; + case BinaryOperator::Add: Result += RHS; break; + case BinaryOperator::Sub: Result -= RHS; break; + case BinaryOperator::Shl: + Result <<= + static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::Shr: + Result >>= + static_cast<uint32_t>(RHS.getLimitedValue(Result.getBitWidth()-1)); + break; + case BinaryOperator::LT: Result = Result < RHS; break; + case BinaryOperator::GT: Result = Result > RHS; break; + case BinaryOperator::LE: Result = Result <= RHS; break; + case BinaryOperator::GE: Result = Result >= RHS; break; + case BinaryOperator::EQ: Result = Result == RHS; break; + case BinaryOperator::NE: Result = Result != RHS; break; + case BinaryOperator::And: Result &= RHS; break; + case BinaryOperator::Xor: Result ^= RHS; break; + case BinaryOperator::Or: Result |= RHS; break; + case BinaryOperator::LAnd: + Result = Result != 0 && RHS != 0; + break; + case BinaryOperator::LOr: + Result = Result != 0 || RHS != 0; + break; + + case BinaryOperator::Comma: + // C99 6.6p3: "shall not contain assignment, ..., or comma operators, + // *except* when they are contained within a subexpression that is not + // evaluated". Note that Assignment can never happen due to constraints + // on the LHS subexpr, so we don't need to check it here. + if (isEvaluated) { + if (Loc) *Loc = getLocStart(); + return false; + } + + // The result of the constant expr is the RHS. + Result = RHS; + return true; + } + + assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!"); + break; + } + case ImplicitCastExprClass: + case CastExprClass: { + const Expr *SubExpr; + SourceLocation CastLoc; + if (const CastExpr *C = dyn_cast<CastExpr>(this)) { + SubExpr = C->getSubExpr(); + CastLoc = C->getLParenLoc(); + } else { + SubExpr = cast<ImplicitCastExpr>(this)->getSubExpr(); + CastLoc = getLocStart(); + } + + // C99 6.6p6: shall only convert arithmetic types to integer types. + if (!SubExpr->getType()->isArithmeticType() || + !getType()->isIntegerType()) { + if (Loc) *Loc = SubExpr->getLocStart(); + return false; + } + + uint32_t DestWidth = static_cast<uint32_t>(Ctx.getTypeSize(getType())); + + // Handle simple integer->integer casts. + if (SubExpr->getType()->isIntegerType()) { + if (!SubExpr->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + // Figure out if this is a truncate, extend or noop cast. + // If the input is signed, do a sign extend, noop, or truncate. + if (getType()->isBooleanType()) { + // Conversion to bool compares against zero. + Result = Result != 0; + Result.zextOrTrunc(DestWidth); + } else if (SubExpr->getType()->isSignedIntegerType()) + Result.sextOrTrunc(DestWidth); + else // If the input is unsigned, do a zero extend, noop, or truncate. + Result.zextOrTrunc(DestWidth); + break; + } + + // Allow floating constants that are the immediate operands of casts or that + // are parenthesized. + const Expr *Operand = SubExpr; + while (const ParenExpr *PE = dyn_cast<ParenExpr>(Operand)) + Operand = PE->getSubExpr(); + + // If this isn't a floating literal, we can't handle it. + const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand); + if (!FL) { + if (Loc) *Loc = Operand->getLocStart(); + return false; + } + + // If the destination is boolean, compare against zero. + if (getType()->isBooleanType()) { + Result = !FL->getValue().isZero(); + Result.zextOrTrunc(DestWidth); + break; + } + + // Determine whether we are converting to unsigned or signed. + bool DestSigned = getType()->isSignedIntegerType(); + + // TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can + // be called multiple times per AST. + uint64_t Space[4]; + (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned, + llvm::APFloat::rmTowardZero); + Result = llvm::APInt(DestWidth, 4, Space); + break; + } + case ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + + if (!Exp->getCond()->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + + const Expr *TrueExp = Exp->getLHS(); + const Expr *FalseExp = Exp->getRHS(); + if (Result == 0) std::swap(TrueExp, FalseExp); + + // Evaluate the false one first, discard the result. + if (FalseExp && !FalseExp->isIntegerConstantExpr(Result, Ctx, Loc, false)) + return false; + // Evalute the true one, capture the result. + if (TrueExp && + !TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated)) + return false; + break; + } + } + + // Cases that are valid constant exprs fall through to here. + Result.setIsUnsigned(getType()->isUnsignedIntegerType()); + return true; +} + +/// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an +/// integer constant expression with the value zero, or if this is one that is +/// cast to void*. +bool Expr::isNullPointerConstant(ASTContext &Ctx) const { + // Strip off a cast to void*, if it exists. + if (const CastExpr *CE = dyn_cast<CastExpr>(this)) { + // Check that it is a cast to void*. + if (const PointerType *PT = CE->getType()->getAsPointerType()) { + QualType Pointee = PT->getPointeeType(); + if (Pointee.getCVRQualifiers() == 0 && + Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. + return CE->getSubExpr()->isNullPointerConstant(Ctx); + } + } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) { + // Ignore the ImplicitCastExpr type entirely. + return ICE->getSubExpr()->isNullPointerConstant(Ctx); + } else if (const ParenExpr *PE = dyn_cast<ParenExpr>(this)) { + // Accept ((void*)0) as a null pointer constant, as many other + // implementations do. + return PE->getSubExpr()->isNullPointerConstant(Ctx); + } + + // This expression must be an integer type. + if (!getType()->isIntegerType()) + return false; + + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. + llvm::APSInt Val(32); + return isIntegerConstantExpr(Val, Ctx, 0, true) && Val == 0; +} + +unsigned OCUVectorElementExpr::getNumElements() const { + return strlen(Accessor.getName()); +} + + +/// getComponentType - Determine whether the components of this access are +/// "point" "color" or "texture" elements. +OCUVectorElementExpr::ElementType +OCUVectorElementExpr::getElementType() const { + // derive the component type, no need to waste space. + const char *compStr = Accessor.getName(); + + if (OCUVectorType::getPointAccessorIdx(*compStr) != -1) return Point; + if (OCUVectorType::getColorAccessorIdx(*compStr) != -1) return Color; + + assert(OCUVectorType::getTextureAccessorIdx(*compStr) != -1 && + "getComponentType(): Illegal accessor"); + return Texture; +} + +/// containsDuplicateElements - Return true if any element access is +/// repeated. +bool OCUVectorElementExpr::containsDuplicateElements() const { + const char *compStr = Accessor.getName(); + unsigned length = strlen(compStr); + + for (unsigned i = 0; i < length-1; i++) { + const char *s = compStr+i; + for (const char c = *s++; *s; s++) + if (c == *s) + return true; + } + return false; +} + +/// getEncodedElementAccess - We encode fields with two bits per component. +unsigned OCUVectorElementExpr::getEncodedElementAccess() const { + const char *compStr = Accessor.getName(); + unsigned length = getNumElements(); + + unsigned Result = 0; + + while (length--) { + Result <<= 2; + int Idx = OCUVectorType::getAccessorIdx(compStr[length]); + assert(Idx != -1 && "Invalid accessor letter"); + Result |= Idx; + } + return Result; +} + +// constructor for instance messages. +ObjCMessageExpr::ObjCMessageExpr(Expr *receiver, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto), ClassName(0) { + NumArgs = nargs; + SubExprs = new Expr*[NumArgs+1]; + SubExprs[RECEIVER] = receiver; + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +// constructor for class messages. +// FIXME: clsName should be typed to ObjCInterfaceType +ObjCMessageExpr::ObjCMessageExpr(IdentifierInfo *clsName, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) + : Expr(ObjCMessageExprClass, retType), SelName(selInfo), + MethodProto(mproto), ClassName(clsName) { + NumArgs = nargs; + SubExprs = new Expr*[NumArgs+1]; + SubExprs[RECEIVER] = 0; + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + + +bool ChooseExpr::isConditionTrue(ASTContext &C) const { + llvm::APSInt CondVal(32); + bool IsConst = getCond()->isIntegerConstantExpr(CondVal, C); + assert(IsConst && "Condition of choose expr must be i-c-e"); IsConst=IsConst; + return CondVal != 0; +} + +static int64_t evaluateOffsetOf(ASTContext& C, const Expr *E) +{ + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + QualType Ty = ME->getBase()->getType(); + + RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + const ASTRecordLayout &RL = C.getASTRecordLayout(RD); + FieldDecl *FD = ME->getMemberDecl(); + + // FIXME: This is linear time. + unsigned i = 0, e = 0; + for (i = 0, e = RD->getNumMembers(); i != e; i++) { + if (RD->getMember(i) == FD) + break; + } + + return RL.getFieldOffset(i) + evaluateOffsetOf(C, ME->getBase()); + } else if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) { + const Expr *Base = ASE->getBase(); + llvm::APSInt Idx(32); + bool ICE = ASE->getIdx()->isIntegerConstantExpr(Idx, C); + assert(ICE && "Array index is not a constant integer!"); + + int64_t size = C.getTypeSize(ASE->getType()); + size *= Idx.getSExtValue(); + + return size + evaluateOffsetOf(C, Base); + } else if (isa<CompoundLiteralExpr>(E)) + return 0; + + assert(0 && "Unknown offsetof subexpression!"); + return 0; +} + +int64_t UnaryOperator::evaluateOffsetOf(ASTContext& C) const +{ + assert(Opc == OffsetOf && "Unary operator not offsetof!"); + + unsigned CharSize = C.Target.getCharWidth(); + return ::evaluateOffsetOf(C, Val) / CharSize; +} + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// DeclRefExpr +Stmt::child_iterator DeclRefExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator DeclRefExpr::child_end() { return child_iterator(); } + +// ObjCIvarRefExpr +Stmt::child_iterator ObjCIvarRefExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCIvarRefExpr::child_end() { return child_iterator(); } + +// PreDefinedExpr +Stmt::child_iterator PreDefinedExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator PreDefinedExpr::child_end() { return child_iterator(); } + +// IntegerLiteral +Stmt::child_iterator IntegerLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator IntegerLiteral::child_end() { return child_iterator(); } + +// CharacterLiteral +Stmt::child_iterator CharacterLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator CharacterLiteral::child_end() { return child_iterator(); } + +// FloatingLiteral +Stmt::child_iterator FloatingLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator FloatingLiteral::child_end() { return child_iterator(); } + +// ImaginaryLiteral +Stmt::child_iterator ImaginaryLiteral::child_begin() { + return reinterpret_cast<Stmt**>(&Val); +} +Stmt::child_iterator ImaginaryLiteral::child_end() { + return reinterpret_cast<Stmt**>(&Val)+1; +} + +// StringLiteral +Stmt::child_iterator StringLiteral::child_begin() { return child_iterator(); } +Stmt::child_iterator StringLiteral::child_end() { return child_iterator(); } + +// ParenExpr +Stmt::child_iterator ParenExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Val); +} +Stmt::child_iterator ParenExpr::child_end() { + return reinterpret_cast<Stmt**>(&Val)+1; +} + +// UnaryOperator +Stmt::child_iterator UnaryOperator::child_begin() { + return reinterpret_cast<Stmt**>(&Val); +} +Stmt::child_iterator UnaryOperator::child_end() { + return reinterpret_cast<Stmt**>(&Val+1); +} + +// SizeOfAlignOfTypeExpr +Stmt::child_iterator SizeOfAlignOfTypeExpr::child_begin() { + // If the type is a VLA type (and not a typedef), the size expression of the + // VLA needs to be treated as an executable expression. + if (VariableArrayType* T = dyn_cast<VariableArrayType>(Ty.getTypePtr())) + return child_iterator(T); + else + return child_iterator(); +} +Stmt::child_iterator SizeOfAlignOfTypeExpr::child_end() { + return child_iterator(); +} + +// ArraySubscriptExpr +Stmt::child_iterator ArraySubscriptExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs); +} +Stmt::child_iterator ArraySubscriptExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR; +} + +// CallExpr +Stmt::child_iterator CallExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs[0]); +} +Stmt::child_iterator CallExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs[NumArgs+ARGS_START]); +} + +// MemberExpr +Stmt::child_iterator MemberExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Base); +} +Stmt::child_iterator MemberExpr::child_end() { + return reinterpret_cast<Stmt**>(&Base)+1; +} + +// OCUVectorElementExpr +Stmt::child_iterator OCUVectorElementExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Base); +} +Stmt::child_iterator OCUVectorElementExpr::child_end() { + return reinterpret_cast<Stmt**>(&Base)+1; +} + +// CompoundLiteralExpr +Stmt::child_iterator CompoundLiteralExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Init); +} +Stmt::child_iterator CompoundLiteralExpr::child_end() { + return reinterpret_cast<Stmt**>(&Init)+1; +} + +// ImplicitCastExpr +Stmt::child_iterator ImplicitCastExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Op); +} +Stmt::child_iterator ImplicitCastExpr::child_end() { + return reinterpret_cast<Stmt**>(&Op)+1; +} + +// CastExpr +Stmt::child_iterator CastExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Op); +} +Stmt::child_iterator CastExpr::child_end() { + return reinterpret_cast<Stmt**>(&Op)+1; +} + +// BinaryOperator +Stmt::child_iterator BinaryOperator::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs); +} +Stmt::child_iterator BinaryOperator::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR; +} + +// ConditionalOperator +Stmt::child_iterator ConditionalOperator::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs); +} +Stmt::child_iterator ConditionalOperator::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR; +} + +// AddrLabelExpr +Stmt::child_iterator AddrLabelExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator AddrLabelExpr::child_end() { return child_iterator(); } + +// StmtExpr +Stmt::child_iterator StmtExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubStmt); +} +Stmt::child_iterator StmtExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubStmt)+1; +} + +// TypesCompatibleExpr +Stmt::child_iterator TypesCompatibleExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator TypesCompatibleExpr::child_end() { + return child_iterator(); +} + +// ChooseExpr +Stmt::child_iterator ChooseExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs); +} + +Stmt::child_iterator ChooseExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs)+END_EXPR; +} + +// OverloadExpr +Stmt::child_iterator OverloadExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs[0]); +} +Stmt::child_iterator OverloadExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs[NumExprs]); +} + +// VAArgExpr +Stmt::child_iterator VAArgExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Val); +} + +Stmt::child_iterator VAArgExpr::child_end() { + return reinterpret_cast<Stmt**>(&Val)+1; +} + +// InitListExpr +Stmt::child_iterator InitListExpr::child_begin() { + return reinterpret_cast<Stmt**>(&InitExprs[0]); +} +Stmt::child_iterator InitListExpr::child_end() { + return reinterpret_cast<Stmt**>(&InitExprs[NumInits]); +} + +// ObjCStringLiteral +Stmt::child_iterator ObjCStringLiteral::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCStringLiteral::child_end() { + return child_iterator(); +} + +// ObjCEncodeExpr +Stmt::child_iterator ObjCEncodeExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCEncodeExpr::child_end() { return child_iterator(); } + +// ObjCSelectorExpr +Stmt::child_iterator ObjCSelectorExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCSelectorExpr::child_end() { + return child_iterator(); +} + +// ObjCProtocolExpr +Stmt::child_iterator ObjCProtocolExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator ObjCProtocolExpr::child_end() { + return child_iterator(); +} + +// ObjCMessageExpr +Stmt::child_iterator ObjCMessageExpr::child_begin() { + return reinterpret_cast<Stmt**>(&SubExprs[0]); +} +Stmt::child_iterator ObjCMessageExpr::child_end() { + return reinterpret_cast<Stmt**>(&SubExprs[getNumArgs()+ARGS_START]); +} + diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp new file mode 100644 index 00000000000..3bc32e75d87 --- /dev/null +++ b/clang/lib/AST/ExprCXX.cpp @@ -0,0 +1,47 @@ +//===--- ExprCXX.cpp - (C++) Expression AST Node Implementation -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the subclesses of Expr class declared in ExprCXX.h +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExprCXX.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + + +// CXXCastExpr +Stmt::child_iterator CXXCastExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Op); +} +Stmt::child_iterator CXXCastExpr::child_end() { + return reinterpret_cast<Stmt**>(&Op)+1; +} + +// CXXBoolLiteralExpr +Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXBoolLiteralExpr::child_end() { + return child_iterator(); +} + +// CXXThrowExpr +Stmt::child_iterator CXXThrowExpr::child_begin() { + return reinterpret_cast<Stmt**>(&Op); +} +Stmt::child_iterator CXXThrowExpr::child_end() { + // If Op is 0, we are processing throw; which has no children. + if (Op == 0) + return reinterpret_cast<Stmt**>(&Op)+0; + return reinterpret_cast<Stmt**>(&Op)+1; +} diff --git a/clang/lib/AST/Makefile b/clang/lib/AST/Makefile new file mode 100644 index 00000000000..cdfc64cacaf --- /dev/null +++ b/clang/lib/AST/Makefile @@ -0,0 +1,22 @@ +##===- clang/lib/AST/Makefile ------------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements the AST library for the C-Language front-end. +# +##===----------------------------------------------------------------------===## + +LEVEL = ../../../.. +LIBRARYNAME := clangAST +BUILD_ARCHIVE = 1 +CXXFLAGS = -fno-rtti + +CPPFLAGS += -I$(PROJ_SRC_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp new file mode 100644 index 00000000000..572280bc054 --- /dev/null +++ b/clang/lib/AST/Stmt.cpp @@ -0,0 +1,293 @@ +//===--- Stmt.cpp - Statement AST Node Implementation ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt class and statement subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Stmt.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/IdentifierTable.h" +using namespace clang; + +static struct StmtClassNameTable { + const char *Name; + unsigned Counter; + unsigned Size; +} StmtClassInfo[Stmt::lastExprConstant+1]; + +static StmtClassNameTable &getStmtInfoTableEntry(Stmt::StmtClass E) { + static bool Initialized = false; + if (Initialized) + return StmtClassInfo[E]; + + // Intialize the table on the first use. + Initialized = true; +#define STMT(N, CLASS, PARENT) \ + StmtClassInfo[N].Name = #CLASS; \ + StmtClassInfo[N].Size = sizeof(CLASS); +#include "clang/AST/StmtNodes.def" + + return StmtClassInfo[E]; +} + +const char *Stmt::getStmtClassName() const { + return getStmtInfoTableEntry(sClass).Name; +} + +void Stmt::PrintStats() { + // Ensure the table is primed. + getStmtInfoTableEntry(Stmt::NullStmtClass); + + unsigned sum = 0; + fprintf(stderr, "*** Stmt/Expr Stats:\n"); + for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + if (StmtClassInfo[i].Name == 0) continue; + sum += StmtClassInfo[i].Counter; + } + fprintf(stderr, " %d stmts/exprs total.\n", sum); + sum = 0; + for (int i = 0; i != Stmt::lastExprConstant+1; i++) { + if (StmtClassInfo[i].Name == 0) continue; + fprintf(stderr, " %d %s, %d each (%d bytes)\n", + StmtClassInfo[i].Counter, StmtClassInfo[i].Name, + StmtClassInfo[i].Size, + StmtClassInfo[i].Counter*StmtClassInfo[i].Size); + sum += StmtClassInfo[i].Counter*StmtClassInfo[i].Size; + } + fprintf(stderr, "Total bytes = %d\n", sum); +} + +void Stmt::addStmtClass(StmtClass s) { + ++getStmtInfoTableEntry(s).Counter; +} + +static bool StatSwitch = false; + +bool Stmt::CollectingStats(bool enable) { + if (enable) StatSwitch = true; + return StatSwitch; +} + + +const char *LabelStmt::getName() const { + return getID()->getName(); +} + +// This is defined here to avoid polluting Stmt.h with importing Expr.h +SourceRange ReturnStmt::getSourceRange() const { + if (RetExpr) + return SourceRange(RetLoc, RetExpr->getLocEnd()); + else + return SourceRange(RetLoc); +} + +bool Stmt::hasImplicitControlFlow() const { + switch (sClass) { + default: + return false; + + case CallExprClass: + case ConditionalOperatorClass: + case ChooseExprClass: + case StmtExprClass: + case DeclStmtClass: + return true; + + case Stmt::BinaryOperatorClass: { + const BinaryOperator* B = cast<BinaryOperator>(this); + if (B->isLogicalOp() || B->getOpcode() == BinaryOperator::Comma) + return true; + else + return false; + } + } +} + +//===----------------------------------------------------------------------===// +// Constructors +//===----------------------------------------------------------------------===// + +AsmStmt::AsmStmt(SourceLocation asmloc, bool issimple, bool isvolatile, + unsigned numoutputs, unsigned numinputs, + std::string *names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, + StringLiteral **clobbers, SourceLocation rparenloc) + : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) + , IsSimple(issimple), IsVolatile(isvolatile) + , NumOutputs(numoutputs), NumInputs(numinputs) { + for (unsigned i = 0, e = numinputs + numoutputs; i != e; i++) { + Names.push_back(names[i]); + Exprs.push_back(exprs[i]); + Constraints.push_back(constraints[i]); + } + + for (unsigned i = 0; i != numclobbers; i++) + Clobbers.push_back(clobbers[i]); +} + +ObjCForCollectionStmt::ObjCForCollectionStmt(Stmt *Elem, Expr *Collect, + Stmt *Body, SourceLocation FCL, + SourceLocation RPL) +: Stmt(ObjCForCollectionStmtClass) { + SubExprs[ELEM] = Elem; + SubExprs[COLLECTION] = reinterpret_cast<Stmt*>(Collect); + SubExprs[BODY] = Body; + ForLoc = FCL; + RParenLoc = RPL; +} + + +ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, + SourceLocation rparenloc, + Stmt *catchVarStmtDecl, Stmt *atCatchStmt, + Stmt *atCatchList) +: Stmt(ObjCAtCatchStmtClass) { + SubExprs[SELECTOR] = catchVarStmtDecl; + SubExprs[BODY] = atCatchStmt; + if (!atCatchList) + SubExprs[NEXT_CATCH] = NULL; + else { + ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList); + + while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) + AtCatchList = NextCatch; + + AtCatchList->SubExprs[NEXT_CATCH] = this; + } + AtCatchLoc = atCatchLoc; + RParenLoc = rparenloc; +} + + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// DeclStmt +Stmt::child_iterator DeclStmt::child_begin() { return getDecl(); } +Stmt::child_iterator DeclStmt::child_end() { return child_iterator(); } + +// NullStmt +Stmt::child_iterator NullStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator NullStmt::child_end() { return child_iterator(); } + +// CompoundStmt +Stmt::child_iterator CompoundStmt::child_begin() { return &Body[0]; } +Stmt::child_iterator CompoundStmt::child_end() { return &Body[0]+Body.size(); } + +// CaseStmt +Stmt::child_iterator CaseStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator CaseStmt::child_end() { return &SubExprs[END_EXPR]; } + +// DefaultStmt +Stmt::child_iterator DefaultStmt::child_begin() { return &SubStmt; } +Stmt::child_iterator DefaultStmt::child_end() { return &SubStmt+1; } + +// LabelStmt +Stmt::child_iterator LabelStmt::child_begin() { return &SubStmt; } +Stmt::child_iterator LabelStmt::child_end() { return &SubStmt+1; } + +// IfStmt +Stmt::child_iterator IfStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator IfStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// SwitchStmt +Stmt::child_iterator SwitchStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator SwitchStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// WhileStmt +Stmt::child_iterator WhileStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator WhileStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// DoStmt +Stmt::child_iterator DoStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator DoStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// ForStmt +Stmt::child_iterator ForStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator ForStmt::child_end() { return &SubExprs[0]+END_EXPR; } + +// ObjCForCollectionStmt +Stmt::child_iterator ObjCForCollectionStmt::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ObjCForCollectionStmt::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// GotoStmt +Stmt::child_iterator GotoStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator GotoStmt::child_end() { return child_iterator(); } + +// IndirectGotoStmt +Stmt::child_iterator IndirectGotoStmt::child_begin() { + return reinterpret_cast<Stmt**>(&Target); +} + +Stmt::child_iterator IndirectGotoStmt::child_end() { return ++child_begin(); } + +// ContinueStmt +Stmt::child_iterator ContinueStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator ContinueStmt::child_end() { return child_iterator(); } + +// BreakStmt +Stmt::child_iterator BreakStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator BreakStmt::child_end() { return child_iterator(); } + +// ReturnStmt +Stmt::child_iterator ReturnStmt::child_begin() { + if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr); + else return child_iterator(); +} + +Stmt::child_iterator ReturnStmt::child_end() { + if (RetExpr) return reinterpret_cast<Stmt**>(&RetExpr)+1; + else return child_iterator(); +} + +// AsmStmt +Stmt::child_iterator AsmStmt::child_begin() { return child_iterator(); } +Stmt::child_iterator AsmStmt::child_end() { return child_iterator(); } + +// ObjCAtCatchStmt +Stmt::child_iterator ObjCAtCatchStmt::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator ObjCAtCatchStmt::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// ObjCAtFinallyStmt +Stmt::child_iterator ObjCAtFinallyStmt::child_begin() { return &AtFinallyStmt; } +Stmt::child_iterator ObjCAtFinallyStmt::child_end() { return &AtFinallyStmt+1; } + +// ObjCAtTryStmt +Stmt::child_iterator ObjCAtTryStmt::child_begin() { return &SubStmts[0]; } +Stmt::child_iterator ObjCAtTryStmt::child_end() { + return &SubStmts[0]+END_EXPR; +} + +// ObjCAtThrowStmt +Stmt::child_iterator ObjCAtThrowStmt::child_begin() { + return &Throw; +} + +Stmt::child_iterator ObjCAtThrowStmt::child_end() { + return &Throw+1; +} + +// ObjCAtSynchronizedStmt +Stmt::child_iterator ObjCAtSynchronizedStmt::child_begin() { + return &SubStmts[0]; +} + +Stmt::child_iterator ObjCAtSynchronizedStmt::child_end() { + return &SubStmts[0]+END_EXPR; +} + diff --git a/clang/lib/AST/StmtDumper.cpp b/clang/lib/AST/StmtDumper.cpp new file mode 100644 index 00000000000..d813899b530 --- /dev/null +++ b/clang/lib/AST/StmtDumper.cpp @@ -0,0 +1,486 @@ +//===--- StmtDumper.cpp - Dumping implementation for Stmt ASTs ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// AST in a form that exposes type details and other fields. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/Compiler.h" +#include <cstdio> +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtDumper Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtDumper : public StmtVisitor<StmtDumper> { + SourceManager *SM; + FILE *F; + unsigned IndentLevel; + + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump + /// the first few levels of an AST. This keeps track of how many ast levels + /// are left. + unsigned MaxDepth; + + /// LastLocFilename/LastLocLine - Keep track of the last location we print + /// out so that we can print out deltas from then on out. + const char *LastLocFilename; + unsigned LastLocLine; + public: + StmtDumper(SourceManager *sm, FILE *f, unsigned maxDepth) + : SM(sm), F(f), IndentLevel(0-1), MaxDepth(maxDepth) { + LastLocFilename = ""; + LastLocLine = ~0U; + } + + void DumpSubTree(Stmt *S) { + // Prune the recursion if not using dump all. + if (MaxDepth == 0) return; + + ++IndentLevel; + if (S) { + if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) + VisitDeclStmt(DS); + else { + Visit(S); + + // Print out children. + Stmt::child_iterator CI = S->child_begin(), CE = S->child_end(); + if (CI != CE) { + while (CI != CE) { + fprintf(F, "\n"); + DumpSubTree(*CI++); + } + } + fprintf(F, ")"); + } + } else { + Indent(); + fprintf(F, "<<<NULL>>>"); + } + --IndentLevel; + } + + void DumpDeclarator(Decl *D); + + void Indent() const { + for (int i = 0, e = IndentLevel; i < e; ++i) + fprintf(F, " "); + } + + void DumpType(QualType T) { + fprintf(F, "'%s'", T.getAsString().c_str()); + + // If the type is directly a typedef, strip off typedefness to give at + // least one level of concreteness. + if (TypedefType *TDT = dyn_cast<TypedefType>(T)) + fprintf(F, ":'%s'", TDT->LookThroughTypedefs().getAsString().c_str()); + } + void DumpStmt(const Stmt *Node) { + Indent(); + fprintf(F, "(%s %p", Node->getStmtClassName(), (void*)Node); + DumpSourceRange(Node); + } + void DumpExpr(const Expr *Node) { + DumpStmt(Node); + fprintf(F, " "); + DumpType(Node->getType()); + } + void DumpSourceRange(const Stmt *Node); + void DumpLocation(SourceLocation Loc); + + // Stmts. + void VisitStmt(Stmt *Node); + void VisitDeclStmt(DeclStmt *Node); + void VisitLabelStmt(LabelStmt *Node); + void VisitGotoStmt(GotoStmt *Node); + + // Exprs + void VisitExpr(Expr *Node); + void VisitDeclRefExpr(DeclRefExpr *Node); + void VisitPreDefinedExpr(PreDefinedExpr *Node); + void VisitCharacterLiteral(CharacterLiteral *Node); + void VisitIntegerLiteral(IntegerLiteral *Node); + void VisitFloatingLiteral(FloatingLiteral *Node); + void VisitStringLiteral(StringLiteral *Str); + void VisitUnaryOperator(UnaryOperator *Node); + void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitOCUVectorElementExpr(OCUVectorElementExpr *Node); + void VisitBinaryOperator(BinaryOperator *Node); + void VisitCompoundAssignOperator(CompoundAssignOperator *Node); + void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); + + // C++ + void VisitCXXCastExpr(CXXCastExpr *Node); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); + + // ObjC + void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(ObjCMessageExpr* Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + }; +} + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +void StmtDumper::DumpLocation(SourceLocation Loc) { + SourceLocation PhysLoc = SM->getPhysicalLoc(Loc); + + // The general format we print out is filename:line:col, but we drop pieces + // that haven't changed since the last loc printed. + const char *Filename = SM->getSourceName(PhysLoc); + unsigned LineNo = SM->getLineNumber(PhysLoc); + if (strcmp(Filename, LastLocFilename) != 0) { + fprintf(stderr, "%s:%u:%u", Filename, LineNo, SM->getColumnNumber(PhysLoc)); + LastLocFilename = Filename; + LastLocLine = LineNo; + } else if (LineNo != LastLocLine) { + fprintf(stderr, "line:%u:%u", LineNo, SM->getColumnNumber(PhysLoc)); + LastLocLine = LineNo; + } else { + fprintf(stderr, "col:%u", SM->getColumnNumber(PhysLoc)); + } +} + +void StmtDumper::DumpSourceRange(const Stmt *Node) { + // Can't translate locations if a SourceManager isn't available. + if (SM == 0) return; + + // TODO: If the parent expression is available, we can print a delta vs its + // location. + SourceRange R = Node->getSourceRange(); + + fprintf(stderr, " <"); + DumpLocation(R.getBegin()); + if (R.getBegin() != R.getEnd()) { + fprintf(stderr, ", "); + DumpLocation(R.getEnd()); + } + fprintf(stderr, ">"); + + // <t2.c:123:421[blah], t2.c:412:321> + +} + + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitStmt(Stmt *Node) { + DumpStmt(Node); +} + +void StmtDumper::DumpDeclarator(Decl *D) { + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { + fprintf(F, "\"typedef %s %s\"", + localType->getUnderlyingType().getAsString().c_str(), + localType->getName()); + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + fprintf(F, "\""); + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: fprintf(F, "extern "); break; + case VarDecl::Static: fprintf(F, "static "); break; + case VarDecl::Auto: fprintf(F, "auto "); break; + case VarDecl::Register: fprintf(F, "register "); break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + fprintf(F, "%s", Name.c_str()); + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getInit()) { + fprintf(F, " =\n"); + DumpSubTree(V->getInit()); + } + } + fprintf(F, "\""); + } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + // print a free standing tag decl (e.g. "struct x;"). + const char *tagname; + if (const IdentifierInfo *II = TD->getIdentifier()) + tagname = II->getName(); + else + tagname = "<anonymous>"; + fprintf(F, "\"%s %s;\"", TD->getKindName(), tagname); + // FIXME: print tag bodies. + } else { + assert(0 && "Unexpected decl"); + } +} + +void StmtDumper::VisitDeclStmt(DeclStmt *Node) { + DumpStmt(Node); + fprintf(F,"\n"); + for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + ++IndentLevel; + Indent(); + fprintf(F, "%p ", (void*) D); + DumpDeclarator(D); + if (D->getNextDeclarator()) + fprintf(F,"\n"); + --IndentLevel; + } +} + +void StmtDumper::VisitLabelStmt(LabelStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s'\n", Node->getName()); +} + +void StmtDumper::VisitGotoStmt(GotoStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s':%p", Node->getLabel()->getName(), (void*)Node->getLabel()); +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitExpr(Expr *Node) { + DumpExpr(Node); +} + +void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + switch (Node->getDecl()->getKind()) { + case Decl::Function: fprintf(F,"FunctionDecl"); break; + case Decl::BlockVar: fprintf(F,"BlockVar"); break; + case Decl::FileVar: fprintf(F,"FileVar"); break; + case Decl::ParmVar: fprintf(F,"ParmVar"); break; + case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; + case Decl::Typedef: fprintf(F,"Typedef"); break; + case Decl::Struct: fprintf(F,"Struct"); break; + case Decl::Union: fprintf(F,"Union"); break; + case Decl::Class: fprintf(F,"Class"); break; + case Decl::Enum: fprintf(F,"Enum"); break; + case Decl::ObjCInterface: fprintf(F,"ObjCInterface"); break; + case Decl::ObjCClass: fprintf(F,"ObjCClass"); break; + default: fprintf(F,"Decl"); break; + } + + fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); +} + +void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + DumpExpr(Node->getBase()); + + fprintf(F, " ObjCIvarRefExpr"); + fprintf(F, "='%s' %p", Node->getDecl()->getName(), (void*)Node->getDecl()); +} + +void StmtDumper::VisitPreDefinedExpr(PreDefinedExpr *Node) { + DumpExpr(Node); + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PreDefinedExpr::Func: + fprintf(F, " __func__"); + break; + case PreDefinedExpr::Function: + fprintf(F, " __FUNCTION__"); + break; + case PreDefinedExpr::PrettyFunction: + fprintf(F, " __PRETTY_FUNCTION__"); + break; + } +} + +void StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { + DumpExpr(Node); + fprintf(F, " %d", Node->getValue()); +} + +void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { + DumpExpr(Node); + + bool isSigned = Node->getType()->isSignedIntegerType(); + fprintf(F, " %s", Node->getValue().toString(10, isSigned).c_str()); +} +void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { + DumpExpr(Node); + fprintf(F, " %f", Node->getValueAsDouble()); +} + +void StmtDumper::VisitStringLiteral(StringLiteral *Str) { + DumpExpr(Str); + // FIXME: this doesn't print wstrings right. + fprintf(F, " %s\"", Str->isWide() ? "L" : ""); + + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (char C = Str->getStrData()[i]) { + default: + if (isprint(C)) + fputc(C, F); + else + fprintf(F, "\\%03o", C); + break; + // Handle some common ones to make dumps prettier. + case '\\': fprintf(F, "\\\\"); break; + case '"': fprintf(F, "\\\""); break; + case '\n': fprintf(F, "\\n"); break; + case '\t': fprintf(F, "\\t"); break; + case '\a': fprintf(F, "\\a"); break; + case '\b': fprintf(F, "\\b"); break; + } + } + fprintf(F, "\""); +} + +void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { + DumpExpr(Node); + fprintf(F, " %s '%s'", Node->isPostfix() ? "postfix" : "prefix", + UnaryOperator::getOpcodeStr(Node->getOpcode())); +} +void StmtDumper::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); + DumpType(Node->getArgumentType()); +} + +void StmtDumper::VisitMemberExpr(MemberExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", + Node->getMemberDecl()->getName(), (void*)Node->getMemberDecl()); +} +void StmtDumper::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", Node->getAccessor().getName()); +} +void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { + DumpExpr(Node); + fprintf(F, " '%s'", BinaryOperator::getOpcodeStr(Node->getOpcode())); +} +void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + DumpExpr(Node); + fprintf(F, " '%s' ComputeTy=", + BinaryOperator::getOpcodeStr(Node->getOpcode())); + DumpType(Node->getComputationType()); +} + +// GNU extensions. + +void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s %p", Node->getLabel()->getName(), (void*)Node->getLabel()); +} + +void StmtDumper::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { + DumpExpr(Node); + fprintf(F, " "); + DumpType(Node->getArgType1()); + fprintf(F, " "); + DumpType(Node->getArgType2()); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitCXXCastExpr(CXXCastExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", CXXCastExpr::getOpcodeStr(Node->getOpcode())); +} + +void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", Node->getValue() ? "true" : "false"); +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { + DumpExpr(Node); + fprintf(F, " selector=%s", Node->getSelector().getName().c_str()); +} + +void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + DumpType(Node->getEncodedType()); +} + +void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + Selector &selector = Node->getSelector(); + fprintf(F, "%s", selector.getName().c_str()); +} + +void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + fprintf(F, "%s", Node->getProtocol()->getName()); +} +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +/// dump - This does a local dump of the specified AST fragment. It dumps the +/// specified node and a few nodes underneath it, but not the whole subtree. +/// This is useful in a debugger. +void Stmt::dump(SourceManager &SM) const { + StmtDumper P(&SM, stderr, 4); + P.DumpSubTree(const_cast<Stmt*>(this)); + fprintf(stderr, "\n"); +} + +/// dump - This does a local dump of the specified AST fragment. It dumps the +/// specified node and a few nodes underneath it, but not the whole subtree. +/// This is useful in a debugger. +void Stmt::dump() const { + StmtDumper P(0, stderr, 4); + P.DumpSubTree(const_cast<Stmt*>(this)); + fprintf(stderr, "\n"); +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll(SourceManager &SM) const { + StmtDumper P(&SM, stderr, ~0U); + P.DumpSubTree(const_cast<Stmt*>(this)); + fprintf(stderr, "\n"); +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll() const { + StmtDumper P(0, stderr, ~0U); + P.DumpSubTree(const_cast<Stmt*>(this)); + fprintf(stderr, "\n"); +} diff --git a/clang/lib/AST/StmtIterator.cpp b/clang/lib/AST/StmtIterator.cpp new file mode 100644 index 00000000000..14083e30a99 --- /dev/null +++ b/clang/lib/AST/StmtIterator.cpp @@ -0,0 +1,118 @@ +//===--- StmtIterator.cpp - Iterators for Statements ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines internal methods for StmtIterator. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtIterator.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" + +using namespace clang; + +static inline VariableArrayType* FindVA(Type* t) { + while (ArrayType* vt = dyn_cast<ArrayType>(t)) { + if (VariableArrayType* vat = dyn_cast<VariableArrayType>(vt)) + if (vat->getSizeExpr()) + return vat; + + t = vt->getElementType().getTypePtr(); + } + + return NULL; +} + +void StmtIteratorBase::NextVA() { + assert (getVAPtr()); + + VariableArrayType* p = getVAPtr(); + p = FindVA(p->getElementType().getTypePtr()); + setVAPtr(p); + + if (!p && decl) { + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) + if (VD->Init) + return; + + NextDecl(); + } + else { + RawVAPtr = 0; + } +} + +void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { + assert (inDecl()); + assert (getVAPtr() == NULL); + assert (decl); + + if (ImmediateAdvance) { + decl = decl->getNextDeclarator(); + + if (!decl) { + RawVAPtr = 0; + return; + } + } + + for ( ; decl ; decl = decl->getNextDeclarator()) { + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) { + if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { + setVAPtr(VAPtr); + return; + } + + if (VD->getInit()) + return; + } + else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(decl)) { + if (VariableArrayType* VAPtr = + FindVA(TD->getUnderlyingType().getTypePtr())) { + setVAPtr(VAPtr); + return; + } + } + else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(decl)) + if (ECD->getInitExpr()) + return; + } + + if (!decl) { + RawVAPtr = 0; + return; + } +} + +StmtIteratorBase::StmtIteratorBase(ScopedDecl* d) + : decl(d), RawVAPtr(DeclMode) { + assert (decl); + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) +: decl(NULL), RawVAPtr(SizeOfTypeVAMode) { + RawVAPtr |= reinterpret_cast<uintptr_t>(t); +} + + +Stmt*& StmtIteratorBase::GetDeclExpr() const { + if (VariableArrayType* VAPtr = getVAPtr()) { + assert (VAPtr->SizeExpr); + return reinterpret_cast<Stmt*&>(VAPtr->SizeExpr); + } + + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) { + assert (VD->Init); + return reinterpret_cast<Stmt*&>(VD->Init); + } + + EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl); + return reinterpret_cast<Stmt*&>(ECD->Init); +} diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp new file mode 100644 index 00000000000..ba82b7fcff7 --- /dev/null +++ b/clang/lib/AST/StmtPrinter.cpp @@ -0,0 +1,854 @@ +//===--- StmtPrinter.cpp - Printing implementation for Stmt ASTs ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the Stmt::dumpPretty/Stmt::printPretty methods, which +// pretty print the AST back out to C code. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" +#include <iomanip> +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtPrinter Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { + std::ostream &OS; + unsigned IndentLevel; + clang::PrinterHelper* Helper; + public: + StmtPrinter(std::ostream &os, PrinterHelper* helper) : + OS(os), IndentLevel(0), Helper(helper) {} + + void PrintStmt(Stmt *S, int SubIndent = 1) { + IndentLevel += SubIndent; + if (S && isa<Expr>(S)) { + // If this is an expr used in a stmt context, indent and newline it. + Indent(); + Visit(S); + OS << ";\n"; + } else if (S) { + Visit(S); + } else { + Indent() << "<<<NULL STATEMENT>>>\n"; + } + IndentLevel -= SubIndent; + } + + void PrintRawCompoundStmt(CompoundStmt *S); + void PrintRawDecl(Decl *D); + void PrintRawIfStmt(IfStmt *If); + + void PrintExpr(Expr *E) { + if (E) + Visit(E); + else + OS << "<null expr>"; + } + + std::ostream &Indent(int Delta = 0) const { + for (int i = 0, e = IndentLevel+Delta; i < e; ++i) + OS << " "; + return OS; + } + + bool PrintOffsetOfDesignator(Expr *E); + void VisitUnaryOffsetOf(UnaryOperator *Node); + + void Visit(Stmt* S) { + if (Helper && Helper->handledStmt(S,OS)) + return; + else StmtVisitor<StmtPrinter>::Visit(S); + } + + void VisitStmt(Stmt *Node); +#define STMT(N, CLASS, PARENT) \ + void Visit##CLASS(CLASS *Node); +#include "clang/AST/StmtNodes.def" + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitStmt(Stmt *Node) { + Indent() << "<<unknown stmt type>>\n"; +} + +/// PrintRawCompoundStmt - Print a compound stmt without indenting the {, and +/// with no newline after the }. +void StmtPrinter::PrintRawCompoundStmt(CompoundStmt *Node) { + OS << "{\n"; + for (CompoundStmt::body_iterator I = Node->body_begin(), E = Node->body_end(); + I != E; ++I) + PrintStmt(*I); + + Indent() << "}"; +} + +void StmtPrinter::PrintRawDecl(Decl *D) { + // FIXME: Need to complete/beautify this... this code simply shows the + // nodes are where they need to be. + if (TypedefDecl *localType = dyn_cast<TypedefDecl>(D)) { + OS << "typedef " << localType->getUnderlyingType().getAsString(); + OS << " " << localType->getName(); + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + switch (V->getStorageClass()) { + default: assert(0 && "Unknown storage class!"); + case VarDecl::None: break; + case VarDecl::Extern: OS << "extern "; break; + case VarDecl::Static: OS << "static "; break; + case VarDecl::Auto: OS << "auto "; break; + case VarDecl::Register: OS << "register "; break; + } + } + + std::string Name = VD->getName(); + VD->getType().getAsStringInternal(Name); + OS << Name; + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getInit()) { + OS << " = "; + PrintExpr(V->getInit()); + } + } + } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + // print a free standing tag decl (e.g. "struct x;"). + OS << TD->getKindName(); + OS << " "; + if (const IdentifierInfo *II = TD->getIdentifier()) + OS << II->getName(); + else + OS << "<anonymous>"; + // FIXME: print tag bodies. + } else { + assert(0 && "Unexpected decl"); + } +} + + +void StmtPrinter::VisitNullStmt(NullStmt *Node) { + Indent() << ";\n"; +} + +void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { + for (ScopedDecl *D = Node->getDecl(); D; D = D->getNextDeclarator()) { + Indent(); + PrintRawDecl(D); + OS << ";\n"; + } +} + +void StmtPrinter::VisitCompoundStmt(CompoundStmt *Node) { + Indent(); + PrintRawCompoundStmt(Node); + OS << "\n"; +} + +void StmtPrinter::VisitCaseStmt(CaseStmt *Node) { + Indent(-1) << "case "; + PrintExpr(Node->getLHS()); + if (Node->getRHS()) { + OS << " ... "; + PrintExpr(Node->getRHS()); + } + OS << ":\n"; + + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitDefaultStmt(DefaultStmt *Node) { + Indent(-1) << "default:\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { + Indent(-1) << Node->getName() << ":\n"; + PrintStmt(Node->getSubStmt(), 0); +} + +void StmtPrinter::PrintRawIfStmt(IfStmt *If) { + OS << "if "; + PrintExpr(If->getCond()); + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << (If->getElse() ? ' ' : '\n'); + } else { + OS << '\n'; + PrintStmt(If->getThen()); + if (If->getElse()) Indent(); + } + + if (Stmt *Else = If->getElse()) { + OS << "else"; + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Else)) { + OS << ' '; + PrintRawCompoundStmt(CS); + OS << '\n'; + } else if (IfStmt *ElseIf = dyn_cast<IfStmt>(Else)) { + OS << ' '; + PrintRawIfStmt(ElseIf); + } else { + OS << '\n'; + PrintStmt(If->getElse()); + } + } +} + +void StmtPrinter::VisitIfStmt(IfStmt *If) { + Indent(); + PrintRawIfStmt(If); +} + +void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { + Indent() << "switch ("; + PrintExpr(Node->getCond()); + OS << ")"; + + // Pretty print compoundstmt bodies (very common). + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + OS << " "; + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitSwitchCase(SwitchCase*) { + assert(0 && "SwitchCase is an abstract class"); +} + +void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { + Indent() << "while ("; + PrintExpr(Node->getCond()); + OS << ")\n"; + PrintStmt(Node->getBody()); +} + +void StmtPrinter::VisitDoStmt(DoStmt *Node) { + Indent() << "do "; + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << " "; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + Indent(); + } + + OS << "while "; + PrintExpr(Node->getCond()); + OS << ";\n"; +} + +void StmtPrinter::VisitForStmt(ForStmt *Node) { + Indent() << "for ("; + if (Node->getInit()) { + if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getInit())) + PrintRawDecl(DS->getDecl()); + else + PrintExpr(cast<Expr>(Node->getInit())); + } + OS << ";"; + if (Node->getCond()) { + OS << " "; + PrintExpr(Node->getCond()); + } + OS << ";"; + if (Node->getInc()) { + OS << " "; + PrintExpr(Node->getInc()); + } + OS << ") "; + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *Node) { + Indent() << "for ("; + if (DeclStmt *DS = dyn_cast<DeclStmt>(Node->getElement())) + PrintRawDecl(DS->getDecl()); + else + PrintExpr(cast<Expr>(Node->getElement())); + OS << " in "; + PrintExpr(Node->getCollection()); + OS << ") "; + + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Node->getBody())) { + PrintRawCompoundStmt(CS); + OS << "\n"; + } else { + OS << "\n"; + PrintStmt(Node->getBody()); + } +} + +void StmtPrinter::VisitGotoStmt(GotoStmt *Node) { + Indent() << "goto " << Node->getLabel()->getName() << ";\n"; +} + +void StmtPrinter::VisitIndirectGotoStmt(IndirectGotoStmt *Node) { + Indent() << "goto *"; + PrintExpr(Node->getTarget()); + OS << ";\n"; +} + +void StmtPrinter::VisitContinueStmt(ContinueStmt *Node) { + Indent() << "continue;\n"; +} + +void StmtPrinter::VisitBreakStmt(BreakStmt *Node) { + Indent() << "break;\n"; +} + + +void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { + Indent() << "return"; + if (Node->getRetValue()) { + OS << " "; + PrintExpr(Node->getRetValue()); + } + OS << ";\n"; +} + + +void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { + Indent() << "asm "; + + if (Node->isVolatile()) + OS << "volatile "; + + OS << "("; + VisitStringLiteral(Node->getAsmString()); + + // Outputs + if (Node->getNumOutputs() != 0 || Node->getNumInputs() != 0 || + Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumOutputs(); i != e; ++i) { + if (i != 0) + OS << ", "; + + if (!Node->getOutputName(i).empty()) { + OS << '['; + OS << Node->getOutputName(i); + OS << "] "; + } + + VisitStringLiteral(Node->getOutputConstraint(i)); + OS << " "; + Visit(Node->getOutputExpr(i)); + } + + // Inputs + if (Node->getNumInputs() != 0 || Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumInputs(); i != e; ++i) { + if (i != 0) + OS << ", "; + + if (!Node->getInputName(i).empty()) { + OS << '['; + OS << Node->getInputName(i); + OS << "] "; + } + + VisitStringLiteral(Node->getInputConstraint(i)); + OS << " "; + Visit(Node->getInputExpr(i)); + } + + // Clobbers + if (Node->getNumClobbers() != 0) + OS << " : "; + + for (unsigned i = 0, e = Node->getNumClobbers(); i != e; ++i) { + if (i != 0) + OS << ", "; + + VisitStringLiteral(Node->getClobber(i)); + } + + OS << ");\n"; +} + +void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { + Indent() << "@try"; + if (CompoundStmt *TS = dyn_cast<CompoundStmt>(Node->getTryBody())) { + PrintRawCompoundStmt(TS); + OS << "\n"; + } + + for (ObjCAtCatchStmt *catchStmt = + static_cast<ObjCAtCatchStmt *>(Node->getCatchStmts()); + catchStmt; + catchStmt = + static_cast<ObjCAtCatchStmt *>(catchStmt->getNextCatchStmt())) { + Indent() << "@catch("; + if (catchStmt->getCatchParamStmt()) { + if (DeclStmt *DS = dyn_cast<DeclStmt>(catchStmt->getCatchParamStmt())) + PrintRawDecl(DS->getDecl()); + } + OS << ")"; + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(catchStmt->getCatchBody())) + { + PrintRawCompoundStmt(CS); + OS << "\n"; + } + } + + if (ObjCAtFinallyStmt *FS =static_cast<ObjCAtFinallyStmt *>( + Node->getFinallyStmt())) { + Indent() << "@finally"; + PrintRawCompoundStmt(dyn_cast<CompoundStmt>(FS->getFinallyBody())); + OS << "\n"; + } +} + +void StmtPrinter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *Node) { +} + +void StmtPrinter::VisitObjCAtCatchStmt (ObjCAtCatchStmt *Node) { + Indent() << "@catch (...) { /* todo */ } \n"; +} + +void StmtPrinter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *Node) { + Indent() << "@throw"; + if (Node->getThrowExpr()) { + OS << " "; + PrintExpr(Node->getThrowExpr()); + } + OS << ";\n"; +} + +void StmtPrinter::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *Node) { + Indent() << "@synchronized ("; + PrintExpr(Node->getSynchExpr()); + OS << ")"; + PrintRawCompoundStmt(Node->getSynchBody()); + OS << "\n"; +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitExpr(Expr *Node) { + OS << "<<unknown expr type>>"; +} + +void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + OS << Node->getDecl()->getName(); +} + +void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + OS << Node->getDecl()->getName(); +} + +void StmtPrinter::VisitPreDefinedExpr(PreDefinedExpr *Node) { + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PreDefinedExpr::Func: + OS << "__func__"; + break; + case PreDefinedExpr::Function: + OS << "__FUNCTION__"; + break; + case PreDefinedExpr::PrettyFunction: + OS << "__PRETTY_FUNCTION__"; + break; + } +} + +void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { + // FIXME should print an L for wchar_t constants + unsigned value = Node->getValue(); + switch (value) { + case '\\': + OS << "'\\\\'"; + break; + case '\'': + OS << "'\\''"; + break; + case '\a': + // TODO: K&R: the meaning of '\\a' is different in traditional C + OS << "'\\a'"; + break; + case '\b': + OS << "'\\b'"; + break; + // Nonstandard escape sequence. + /*case '\e': + OS << "'\\e'"; + break;*/ + case '\f': + OS << "'\\f'"; + break; + case '\n': + OS << "'\\n'"; + break; + case '\r': + OS << "'\\r'"; + break; + case '\t': + OS << "'\\t'"; + break; + case '\v': + OS << "'\\v'"; + break; + default: + if (value < 256 && isprint(value)) { + OS << "'" << (char)value << "'"; + } else if (value < 256) { + OS << "'\\x" << std::hex << value << std::dec << "'"; + } else { + // FIXME what to really do here? + OS << value; + } + } +} + +void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { + bool isSigned = Node->getType()->isSignedIntegerType(); + OS << Node->getValue().toString(10, isSigned); + + // Emit suffixes. Integer literals are always a builtin integer type. + switch (cast<BuiltinType>(Node->getType().getCanonicalType())->getKind()) { + default: assert(0 && "Unexpected type for integer literal!"); + case BuiltinType::Int: break; // no suffix. + case BuiltinType::UInt: OS << 'U'; break; + case BuiltinType::Long: OS << 'L'; break; + case BuiltinType::ULong: OS << "UL"; break; + case BuiltinType::LongLong: OS << "LL"; break; + case BuiltinType::ULongLong: OS << "ULL"; break; + } +} +void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + // FIXME: print value more precisely. + OS << Node->getValueAsDouble(); +} + +void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { + PrintExpr(Node->getSubExpr()); + OS << "i"; +} + +void StmtPrinter::VisitStringLiteral(StringLiteral *Str) { + if (Str->isWide()) OS << 'L'; + OS << '"'; + + // FIXME: this doesn't print wstrings right. + for (unsigned i = 0, e = Str->getByteLength(); i != e; ++i) { + switch (Str->getStrData()[i]) { + default: OS << Str->getStrData()[i]; break; + // Handle some common ones to make dumps prettier. + case '\\': OS << "\\\\"; break; + case '"': OS << "\\\""; break; + case '\n': OS << "\\n"; break; + case '\t': OS << "\\t"; break; + case '\a': OS << "\\a"; break; + case '\b': OS << "\\b"; break; + } + } + OS << '"'; +} +void StmtPrinter::VisitParenExpr(ParenExpr *Node) { + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} +void StmtPrinter::VisitUnaryOperator(UnaryOperator *Node) { + if (!Node->isPostfix()) { + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); + + // Print a space if this is an "identifier operator" like sizeof or __real. + switch (Node->getOpcode()) { + default: break; + case UnaryOperator::SizeOf: + case UnaryOperator::AlignOf: + case UnaryOperator::Real: + case UnaryOperator::Imag: + case UnaryOperator::Extension: + OS << ' '; + break; + } + } + PrintExpr(Node->getSubExpr()); + + if (Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); +} + +bool StmtPrinter::PrintOffsetOfDesignator(Expr *E) { + if (isa<CompoundLiteralExpr>(E)) { + // Base case, print the type and comma. + OS << E->getType().getAsString() << ", "; + return true; + } else if (ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) { + PrintOffsetOfDesignator(ASE->getLHS()); + OS << "["; + PrintExpr(ASE->getRHS()); + OS << "]"; + return false; + } else { + MemberExpr *ME = cast<MemberExpr>(E); + bool IsFirst = PrintOffsetOfDesignator(ME->getBase()); + OS << (IsFirst ? "" : ".") << ME->getMemberDecl()->getName(); + return false; + } +} + +void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { + OS << "__builtin_offsetof("; + PrintOffsetOfDesignator(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr *Node) { + OS << (Node->isSizeOf() ? "sizeof(" : "__alignof("); + OS << Node->getArgumentType().getAsString() << ")"; +} +void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { + PrintExpr(Node->getLHS()); + OS << "["; + PrintExpr(Node->getRHS()); + OS << "]"; +} + +void StmtPrinter::VisitCallExpr(CallExpr *Call) { + PrintExpr(Call->getCallee()); + OS << "("; + for (unsigned i = 0, e = Call->getNumArgs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Call->getArg(i)); + } + OS << ")"; +} +void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + + FieldDecl *Field = Node->getMemberDecl(); + assert(Field && "MemberExpr should alway reference a field!"); + OS << Field->getName(); +} +void StmtPrinter::VisitOCUVectorElementExpr(OCUVectorElementExpr *Node) { + PrintExpr(Node->getBase()); + OS << "."; + OS << Node->getAccessor().getName(); +} +void StmtPrinter::VisitCastExpr(CastExpr *Node) { + OS << "(" << Node->getType().getAsString() << ")"; + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { + OS << "(" << Node->getType().getAsString() << ")"; + PrintExpr(Node->getInitializer()); +} +void StmtPrinter::VisitImplicitCastExpr(ImplicitCastExpr *Node) { + // No need to print anything, simply forward to the sub expression. + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitBinaryOperator(BinaryOperator *Node) { + PrintExpr(Node->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; + PrintExpr(Node->getRHS()); +} +void StmtPrinter::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + PrintExpr(Node->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(Node->getOpcode()) << " "; + PrintExpr(Node->getRHS()); +} +void StmtPrinter::VisitConditionalOperator(ConditionalOperator *Node) { + PrintExpr(Node->getCond()); + + if (Node->getLHS()) { + OS << " ? "; + PrintExpr(Node->getLHS()); + OS << " : "; + } + else { // Handle GCC extention where LHS can be NULL. + OS << " ?: "; + } + + PrintExpr(Node->getRHS()); +} + +// GNU extensions. + +void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { + OS << "&&" << Node->getLabel()->getName(); +} + +void StmtPrinter::VisitStmtExpr(StmtExpr *E) { + OS << "("; + PrintRawCompoundStmt(E->getSubStmt()); + OS << ")"; +} + +void StmtPrinter::VisitTypesCompatibleExpr(TypesCompatibleExpr *Node) { + OS << "__builtin_types_compatible_p("; + OS << Node->getArgType1().getAsString() << ","; + OS << Node->getArgType2().getAsString() << ")"; +} + +void StmtPrinter::VisitChooseExpr(ChooseExpr *Node) { + OS << "__builtin_choose_expr("; + PrintExpr(Node->getCond()); + OS << ", "; + PrintExpr(Node->getLHS()); + OS << ", "; + PrintExpr(Node->getRHS()); + OS << ")"; +} + +void StmtPrinter::VisitOverloadExpr(OverloadExpr *Node) { + OS << "__builtin_overload("; + for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << ")"; +} + +void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { + OS << "{ "; + for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getInit(i)); + } + OS << " }"; +} + +void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { + OS << "va_arg("; + PrintExpr(Node->getSubExpr()); + OS << ", "; + OS << Node->getType().getAsString(); + OS << ")"; +} + +// C++ + +void StmtPrinter::VisitCXXCastExpr(CXXCastExpr *Node) { + OS << CXXCastExpr::getOpcodeStr(Node->getOpcode()) << '<'; + OS << Node->getDestType().getAsString() << ">("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + OS << (Node->getValue() ? "true" : "false"); +} + +void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { + if (Node->getSubExpr() == 0) + OS << "throw"; + else { + OS << "throw "; + PrintExpr(Node->getSubExpr()); + } +} + +// Obj-C + +void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { + OS << "@"; + VisitStringLiteral(Node->getString()); +} + +void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + OS << "@encode(" << Node->getEncodedType().getAsString() << ")"; +} + +void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + OS << "@selector(" << Node->getSelector().getName() << ")"; +} + +void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + OS << "@protocol(" << Node->getProtocol()->getName() << ")"; +} + +void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { + OS << "["; + Expr *receiver = Mess->getReceiver(); + if (receiver) PrintExpr(receiver); + else OS << Mess->getClassName()->getName(); + Selector &selector = Mess->getSelector(); + if (selector.isUnarySelector()) { + OS << " " << selector.getIdentifierInfoForSlot(0)->getName(); + } else { + for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { + if (selector.getIdentifierInfoForSlot(i)) + OS << selector.getIdentifierInfoForSlot(i)->getName() << ":"; + else + OS << ":"; + PrintExpr(Mess->getArg(i)); + } + } + OS << "]"; +} + +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dumpPretty() const { + printPretty(*llvm::cerr.stream()); +} + +void Stmt::printPretty(std::ostream &OS, PrinterHelper* Helper) const { + if (this == 0) { + OS << "<NULL>"; + return; + } + + StmtPrinter P(OS, Helper); + P.Visit(const_cast<Stmt*>(this)); +} + +//===----------------------------------------------------------------------===// +// PrinterHelper +//===----------------------------------------------------------------------===// + +// Implement virtual destructor. +PrinterHelper::~PrinterHelper() {} diff --git a/clang/lib/AST/StmtSerialization.cpp b/clang/lib/AST/StmtSerialization.cpp new file mode 100644 index 00000000000..433e8e27026 --- /dev/null +++ b/clang/lib/AST/StmtSerialization.cpp @@ -0,0 +1,1001 @@ +//===--- StmtSerialization.cpp - Serialization of Statements --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the type-specific methods for serializing statements +// and expressions. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Expr.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; +using llvm::Serializer; +using llvm::Deserializer; + +void Stmt::Emit(Serializer& S) const { + S.FlushRecord(); + S.EmitInt(getStmtClass()); + EmitImpl(S); + S.FlushRecord(); +} + +Stmt* Stmt::Create(Deserializer& D) { + StmtClass SC = static_cast<StmtClass>(D.ReadInt()); + + switch (SC) { + default: + assert (false && "Not implemented."); + return NULL; + + case AddrLabelExprClass: + return AddrLabelExpr::CreateImpl(D); + + case ArraySubscriptExprClass: + return ArraySubscriptExpr::CreateImpl(D); + + case AsmStmtClass: + return AsmStmt::CreateImpl(D); + + case BinaryOperatorClass: + return BinaryOperator::CreateImpl(D); + + case BreakStmtClass: + return BreakStmt::CreateImpl(D); + + case CallExprClass: + return CallExpr::CreateImpl(D); + + case CaseStmtClass: + return CaseStmt::CreateImpl(D); + + case CastExprClass: + return CastExpr::CreateImpl(D); + + case CharacterLiteralClass: + return CharacterLiteral::CreateImpl(D); + + case CompoundAssignOperatorClass: + return CompoundAssignOperator::CreateImpl(D); + + case CompoundLiteralExprClass: + return CompoundLiteralExpr::CreateImpl(D); + + case CompoundStmtClass: + return CompoundStmt::CreateImpl(D); + + case ConditionalOperatorClass: + return ConditionalOperator::CreateImpl(D); + + case ContinueStmtClass: + return ContinueStmt::CreateImpl(D); + + case DeclRefExprClass: + return DeclRefExpr::CreateImpl(D); + + case DeclStmtClass: + return DeclStmt::CreateImpl(D); + + case DefaultStmtClass: + return DefaultStmt::CreateImpl(D); + + case DoStmtClass: + return DoStmt::CreateImpl(D); + + case FloatingLiteralClass: + return FloatingLiteral::CreateImpl(D); + + case ForStmtClass: + return ForStmt::CreateImpl(D); + + case GotoStmtClass: + return GotoStmt::CreateImpl(D); + + case IfStmtClass: + return IfStmt::CreateImpl(D); + + case ImaginaryLiteralClass: + return ImaginaryLiteral::CreateImpl(D); + + case ImplicitCastExprClass: + return ImplicitCastExpr::CreateImpl(D); + + case IndirectGotoStmtClass: + return IndirectGotoStmt::CreateImpl(D); + + case InitListExprClass: + return InitListExpr::CreateImpl(D); + + case IntegerLiteralClass: + return IntegerLiteral::CreateImpl(D); + + case LabelStmtClass: + return LabelStmt::CreateImpl(D); + + case MemberExprClass: + return MemberExpr::CreateImpl(D); + + case NullStmtClass: + return NullStmt::CreateImpl(D); + + case ParenExprClass: + return ParenExpr::CreateImpl(D); + + case PreDefinedExprClass: + return PreDefinedExpr::CreateImpl(D); + + case ReturnStmtClass: + return ReturnStmt::CreateImpl(D); + + case SizeOfAlignOfTypeExprClass: + return SizeOfAlignOfTypeExpr::CreateImpl(D); + + case StmtExprClass: + return StmtExpr::CreateImpl(D); + + case StringLiteralClass: + return StringLiteral::CreateImpl(D); + + case SwitchStmtClass: + return SwitchStmt::CreateImpl(D); + + case UnaryOperatorClass: + return UnaryOperator::CreateImpl(D); + + case WhileStmtClass: + return WhileStmt::CreateImpl(D); + + //==--------------------------------------==// + // Objective C + //==--------------------------------------==// + + case ObjCAtCatchStmtClass: + return ObjCAtCatchStmt::CreateImpl(D); + + case ObjCAtFinallyStmtClass: + return ObjCAtFinallyStmt::CreateImpl(D); + + case ObjCAtSynchronizedStmtClass: + return ObjCAtSynchronizedStmt::CreateImpl(D); + + case ObjCAtThrowStmtClass: + return ObjCAtThrowStmt::CreateImpl(D); + + case ObjCAtTryStmtClass: + return ObjCAtTryStmt::CreateImpl(D); + + case ObjCEncodeExprClass: + return ObjCEncodeExpr::CreateImpl(D); + + case ObjCForCollectionStmtClass: + return ObjCForCollectionStmt::CreateImpl(D); + + case ObjCIvarRefExprClass: + return ObjCIvarRefExpr::CreateImpl(D); + + case ObjCSelectorExprClass: + return ObjCSelectorExpr::CreateImpl(D); + + case ObjCStringLiteralClass: + return ObjCStringLiteral::CreateImpl(D); + } +} + +//===----------------------------------------------------------------------===// +// C Serialization +//===----------------------------------------------------------------------===// + +void AddrLabelExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(AmpAmpLoc); + S.Emit(LabelLoc); + S.EmitPtr(Label); +} + +AddrLabelExpr* AddrLabelExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation AALoc = SourceLocation::ReadVal(D); + SourceLocation LLoc = SourceLocation::ReadVal(D); + AddrLabelExpr* expr = new AddrLabelExpr(AALoc,LLoc,NULL,t); + D.ReadPtr(expr->Label); // Pointer may be backpatched. + return expr; +} + +void ArraySubscriptExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(RBracketLoc); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +ArraySubscriptExpr* ArraySubscriptExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Expr *LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + return new ArraySubscriptExpr(LHS,RHS,t,L); +} + +void AsmStmt::EmitImpl(Serializer& S) const { + S.Emit(AsmLoc); + + getAsmString()->EmitImpl(S); + S.Emit(RParenLoc); + + S.EmitBool(IsVolatile); + S.EmitBool(IsSimple); + S.EmitInt(NumOutputs); + S.EmitInt(NumInputs); + + unsigned size = NumOutputs + NumInputs; + + for (unsigned i = 0; i < size; ++i) + S.EmitCStr(Names[i].c_str()); + + for (unsigned i = 0; i < size; ++i) + Constraints[i]->EmitImpl(S); + + for (unsigned i = 0; i < size; ++i) + S.EmitOwnedPtr(Exprs[i]); + + S.EmitInt(Clobbers.size()); + for (unsigned i = 0, e = Clobbers.size(); i != e; ++i) + Clobbers[i]->EmitImpl(S); +} + +AsmStmt* AsmStmt::CreateImpl(Deserializer& D) { + SourceLocation ALoc = SourceLocation::ReadVal(D); + StringLiteral *AsmStr = StringLiteral::CreateImpl(D); + SourceLocation PLoc = SourceLocation::ReadVal(D); + + bool IsVolatile = D.ReadBool(); + bool IsSimple = D.ReadBool(); + AsmStmt *Stmt = new AsmStmt(ALoc, IsSimple, IsVolatile, 0, 0, 0, 0, 0, + AsmStr, + 0, 0, PLoc); + + Stmt->NumOutputs = D.ReadInt(); + Stmt->NumInputs = D.ReadInt(); + + unsigned size = Stmt->NumOutputs + Stmt->NumInputs; + + Stmt->Names.reserve(size); + for (unsigned i = 0; i < size; ++i) { + std::vector<char> data; + D.ReadCStr(data, false); + + Stmt->Names.push_back(std::string(data.begin(), data.end())); + } + + Stmt->Constraints.reserve(size); + for (unsigned i = 0; i < size; ++i) + Stmt->Constraints.push_back(StringLiteral::CreateImpl(D)); + + Stmt->Exprs.reserve(size); + for (unsigned i = 0; i < size; ++i) + Stmt->Exprs.push_back(D.ReadOwnedPtr<Expr>()); + + unsigned NumClobbers = D.ReadInt(); + Stmt->Clobbers.reserve(NumClobbers); + for (unsigned i = 0; i < NumClobbers; ++i) + Stmt->Clobbers.push_back(StringLiteral::CreateImpl(D)); + + return Stmt; +} + +void BinaryOperator::EmitImpl(Serializer& S) const { + S.EmitInt(Opc); + S.Emit(OpLoc);; + S.Emit(getType()); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +BinaryOperator* BinaryOperator::CreateImpl(Deserializer& D) { + Opcode Opc = static_cast<Opcode>(D.ReadInt()); + SourceLocation OpLoc = SourceLocation::ReadVal(D); + QualType Result = QualType::ReadVal(D); + Expr *LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + + return new BinaryOperator(LHS,RHS,Opc,Result,OpLoc); +} + +void BreakStmt::EmitImpl(Serializer& S) const { + S.Emit(BreakLoc); +} + +BreakStmt* BreakStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + return new BreakStmt(Loc); +} + +void CallExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(RParenLoc); + S.EmitInt(NumArgs); + S.BatchEmitOwnedPtrs(NumArgs+1,SubExprs); +} + +CallExpr* CallExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + unsigned NumArgs = D.ReadInt(); + Expr** SubExprs = new Expr*[NumArgs+1]; + D.BatchReadOwnedPtrs(NumArgs+1,SubExprs); + + return new CallExpr(SubExprs,NumArgs,t,L); +} + +void CaseStmt::EmitImpl(Serializer& S) const { + S.Emit(CaseLoc); + S.EmitPtr(getNextSwitchCase()); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubExprs[0]); +} + +CaseStmt* CaseStmt::CreateImpl(Deserializer& D) { + SourceLocation CaseLoc = SourceLocation::ReadVal(D); + CaseStmt* stmt = new CaseStmt(NULL,NULL,NULL,CaseLoc); + D.ReadPtr(stmt->NextSwitchCase); + D.BatchReadOwnedPtrs((unsigned) END_EXPR,&stmt->SubExprs[0]); + return stmt; +} + +void CastExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(Loc); + S.EmitOwnedPtr(Op); +} + +CastExpr* CastExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation Loc = SourceLocation::ReadVal(D); + Expr* Op = D.ReadOwnedPtr<Expr>(); + return new CastExpr(t,Op,Loc); +} + + +void CharacterLiteral::EmitImpl(Serializer& S) const { + S.Emit(Value); + S.Emit(Loc); + S.Emit(getType()); +} + +CharacterLiteral* CharacterLiteral::CreateImpl(Deserializer& D) { + unsigned value = D.ReadInt(); + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + return new CharacterLiteral(value,T,Loc); +} + +void CompoundAssignOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(ComputationType); + S.Emit(getOperatorLoc()); + S.EmitInt(getOpcode()); + S.BatchEmitOwnedPtrs(getLHS(),getRHS()); +} + +CompoundAssignOperator* +CompoundAssignOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + QualType c = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Opcode Opc = static_cast<Opcode>(D.ReadInt()); + Expr* LHS, *RHS; + D.BatchReadOwnedPtrs(LHS,RHS); + + return new CompoundAssignOperator(LHS,RHS,Opc,t,c,L); +} + +void CompoundLiteralExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(getLParenLoc()); + S.EmitBool(isFileScope()); + S.EmitOwnedPtr(Init); +} + +CompoundLiteralExpr* CompoundLiteralExpr::CreateImpl(Deserializer& D) { + QualType Q = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + bool fileScope = D.ReadBool(); + Expr* Init = D.ReadOwnedPtr<Expr>(); + return new CompoundLiteralExpr(L, Q, Init, fileScope); +} + +void CompoundStmt::EmitImpl(Serializer& S) const { + S.Emit(LBracLoc); + S.Emit(RBracLoc); + S.Emit(Body.size()); + + for (const_body_iterator I=body_begin(), E=body_end(); I!=E; ++I) + S.EmitOwnedPtr(*I); +} + +CompoundStmt* CompoundStmt::CreateImpl(Deserializer& D) { + SourceLocation LB = SourceLocation::ReadVal(D); + SourceLocation RB = SourceLocation::ReadVal(D); + unsigned size = D.ReadInt(); + + CompoundStmt* stmt = new CompoundStmt(NULL,0,LB,RB); + + stmt->Body.reserve(size); + + for (unsigned i = 0; i < size; ++i) + stmt->Body.push_back(D.ReadOwnedPtr<Stmt>()); + + return stmt; +} + +void ConditionalOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, SubExprs); +} + +ConditionalOperator* ConditionalOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + ConditionalOperator* c = new ConditionalOperator(NULL,NULL,NULL,t); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, c->SubExprs); + return c; +} + +void ContinueStmt::EmitImpl(Serializer& S) const { + S.Emit(ContinueLoc); +} + +ContinueStmt* ContinueStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + return new ContinueStmt(Loc); +} + +void DeclStmt::EmitImpl(Serializer& S) const { + // FIXME: special handling for struct decls. + S.EmitOwnedPtr(getDecl()); + S.Emit(StartLoc); + S.Emit(EndLoc); +} + +void DeclRefExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + + // Some DeclRefExprs can actually hold the owning reference to a FunctionDecl. + // This occurs when an implicitly defined function is called, and + // the decl does not appear in the source file. We thus check if the + // decl pointer has been registered, and if not, emit an owned pointer. + + // FIXME: While this will work for serialization, it won't work for + // memory management. The only reason this works for serialization is + // because we are tracking all serialized pointers. Either DeclRefExpr + // needs an explicit bit indicating that it owns the the object, + // or we need a different ownership model. + + const Decl* d = getDecl(); + + if (!S.isRegistered(d)) { + assert (isa<FunctionDecl>(d) + && "DeclRefExpr can only own FunctionDecls for implicitly def. funcs."); + + S.EmitBool(true); + S.EmitOwnedPtr(d); + } + else { + S.EmitBool(false); + S.EmitPtr(d); + } +} + +DeclRefExpr* DeclRefExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + bool OwnsDecl = D.ReadBool(); + ValueDecl* decl; + + if (!OwnsDecl) + D.ReadPtr(decl,false); // No backpatching. + else + decl = cast<ValueDecl>(D.ReadOwnedPtr<Decl>()); + + return new DeclRefExpr(decl,T,Loc); +} + + +DeclStmt* DeclStmt::CreateImpl(Deserializer& D) { + ScopedDecl* decl = cast<ScopedDecl>(D.ReadOwnedPtr<Decl>()); + SourceLocation StartLoc = SourceLocation::ReadVal(D); + SourceLocation EndLoc = SourceLocation::ReadVal(D); + return new DeclStmt(decl, StartLoc, EndLoc); +} + +void DefaultStmt::EmitImpl(Serializer& S) const { + S.Emit(DefaultLoc); + S.EmitOwnedPtr(getSubStmt()); + S.EmitPtr(getNextSwitchCase()); +} + +DefaultStmt* DefaultStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* SubStmt = D.ReadOwnedPtr<Stmt>(); + + DefaultStmt* stmt = new DefaultStmt(Loc,SubStmt); + stmt->setNextSwitchCase(D.ReadPtr<SwitchCase>()); + + return stmt; +} + +void DoStmt::EmitImpl(Serializer& S) const { + S.Emit(DoLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); +} + +DoStmt* DoStmt::CreateImpl(Deserializer& D) { + SourceLocation DoLoc = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr<Expr>(); + Stmt* Body = D.ReadOwnedPtr<Stmt>(); + return new DoStmt(Body,Cond,DoLoc); +} + +void FloatingLiteral::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.EmitBool(isExact()); + S.Emit(Value); +} + +FloatingLiteral* FloatingLiteral::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType t = QualType::ReadVal(D); + bool isExact = D.ReadBool(); + llvm::APFloat Val = llvm::APFloat::ReadVal(D); + FloatingLiteral* expr = new FloatingLiteral(Val,&isExact,t,Loc); + return expr; +} + +void ForStmt::EmitImpl(Serializer& S) const { + S.Emit(ForLoc); + S.EmitOwnedPtr(getInit()); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getInc()); + S.EmitOwnedPtr(getBody()); +} + +ForStmt* ForStmt::CreateImpl(Deserializer& D) { + SourceLocation ForLoc = SourceLocation::ReadVal(D); + Stmt* Init = D.ReadOwnedPtr<Stmt>(); + Expr* Cond = D.ReadOwnedPtr<Expr>(); + Expr* Inc = D.ReadOwnedPtr<Expr>(); + Stmt* Body = D.ReadOwnedPtr<Stmt>(); + return new ForStmt(Init,Cond,Inc,Body,ForLoc); +} + +void GotoStmt::EmitImpl(Serializer& S) const { + S.Emit(GotoLoc); + S.Emit(LabelLoc); + S.EmitPtr(Label); +} + +GotoStmt* GotoStmt::CreateImpl(Deserializer& D) { + SourceLocation GotoLoc = SourceLocation::ReadVal(D); + SourceLocation LabelLoc = SourceLocation::ReadVal(D); + GotoStmt* stmt = new GotoStmt(NULL,GotoLoc,LabelLoc); + D.ReadPtr(stmt->Label); // This pointer may be backpatched later. + return stmt; +} + +void IfStmt::EmitImpl(Serializer& S) const { + S.Emit(IfLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getThen()); + S.EmitOwnedPtr(getElse()); +} + +IfStmt* IfStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr<Expr>(); + Stmt* Then = D.ReadOwnedPtr<Stmt>(); + Stmt* Else = D.ReadOwnedPtr<Stmt>(); + return new IfStmt(L,Cond,Then,Else); +} + +void ImaginaryLiteral::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.EmitOwnedPtr(Val); +} + +ImaginaryLiteral* ImaginaryLiteral::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + Expr* expr = D.ReadOwnedPtr<Expr>(); + assert (isa<FloatingLiteral>(expr) || isa<IntegerLiteral>(expr)); + return new ImaginaryLiteral(expr,t); +} + +void ImplicitCastExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.EmitOwnedPtr(Op); +} + +ImplicitCastExpr* ImplicitCastExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + Expr* Op = D.ReadOwnedPtr<Expr>(); + return new ImplicitCastExpr(t,Op); +} + +void IndirectGotoStmt::EmitImpl(Serializer& S) const { + S.EmitOwnedPtr(Target); +} + +IndirectGotoStmt* IndirectGotoStmt::CreateImpl(Deserializer& D) { + Expr* Target = D.ReadOwnedPtr<Expr>(); + return new IndirectGotoStmt(Target); +} + +void InitListExpr::EmitImpl(Serializer& S) const { + S.Emit(LBraceLoc); + S.Emit(RBraceLoc); + S.EmitInt(NumInits); + S.BatchEmitOwnedPtrs(NumInits,InitExprs); +} + +InitListExpr* InitListExpr::CreateImpl(Deserializer& D) { + InitListExpr* expr = new InitListExpr(); + expr->LBraceLoc = SourceLocation::ReadVal(D); + expr->RBraceLoc = SourceLocation::ReadVal(D); + expr->NumInits = D.ReadInt(); + assert(expr->NumInits); + expr->InitExprs = new Expr*[expr->NumInits]; + D.BatchReadOwnedPtrs(expr->NumInits,expr->InitExprs); + return expr; +} + +void IntegerLiteral::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.Emit(getValue()); +} + +IntegerLiteral* IntegerLiteral::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + + // Create a dummy APInt because it is more efficient to deserialize + // it in place with the deserialized IntegerLiteral. (fewer copies) + llvm::APInt temp; + IntegerLiteral* expr = new IntegerLiteral(temp,T,Loc); + D.Read(expr->Value); + + return expr; +} + +void LabelStmt::EmitImpl(Serializer& S) const { + S.EmitPtr(Label); + S.Emit(IdentLoc); + S.EmitOwnedPtr(SubStmt); +} + +LabelStmt* LabelStmt::CreateImpl(Deserializer& D) { + IdentifierInfo* Label = D.ReadPtr<IdentifierInfo>(); + SourceLocation IdentLoc = SourceLocation::ReadVal(D); + Stmt* SubStmt = D.ReadOwnedPtr<Stmt>(); + return new LabelStmt(IdentLoc,Label,SubStmt); +} + +void MemberExpr::EmitImpl(Serializer& S) const { + S.Emit(MemberLoc); + S.EmitPtr(MemberDecl); + S.EmitBool(IsArrow); + S.Emit(getType()); + S.EmitOwnedPtr(Base); +} + +MemberExpr* MemberExpr::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + FieldDecl* MemberDecl = cast<FieldDecl>(D.ReadPtr<Decl>()); + bool IsArrow = D.ReadBool(); + QualType T = QualType::ReadVal(D); + Expr* base = D.ReadOwnedPtr<Expr>(); + + return new MemberExpr(base,IsArrow,MemberDecl,L,T); +} + +void NullStmt::EmitImpl(Serializer& S) const { + S.Emit(SemiLoc); +} + +NullStmt* NullStmt::CreateImpl(Deserializer& D) { + SourceLocation SemiLoc = SourceLocation::ReadVal(D); + return new NullStmt(SemiLoc); +} + +void ParenExpr::EmitImpl(Serializer& S) const { + S.Emit(L); + S.Emit(R); + S.EmitOwnedPtr(Val); +} + +ParenExpr* ParenExpr::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + SourceLocation R = SourceLocation::ReadVal(D); + Expr* val = D.ReadOwnedPtr<Expr>(); + return new ParenExpr(L,R,val); +} + +void PreDefinedExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.EmitInt(getIdentType()); + S.Emit(getType()); +} + +PreDefinedExpr* PreDefinedExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + IdentType it = static_cast<IdentType>(D.ReadInt()); + QualType Q = QualType::ReadVal(D); + return new PreDefinedExpr(Loc,Q,it); +} + +void ReturnStmt::EmitImpl(Serializer& S) const { + S.Emit(RetLoc); + S.EmitOwnedPtr(RetExpr); +} + +ReturnStmt* ReturnStmt::CreateImpl(Deserializer& D) { + SourceLocation RetLoc = SourceLocation::ReadVal(D); + Expr* RetExpr = D.ReadOwnedPtr<Expr>(); + return new ReturnStmt(RetLoc,RetExpr); +} + +void SizeOfAlignOfTypeExpr::EmitImpl(Serializer& S) const { + S.EmitBool(isSizeof); + S.Emit(Ty); + S.Emit(getType()); + S.Emit(OpLoc); + S.Emit(RParenLoc); +} + +SizeOfAlignOfTypeExpr* SizeOfAlignOfTypeExpr::CreateImpl(Deserializer& D) { + bool isSizeof = D.ReadBool(); + QualType Ty = QualType::ReadVal(D); + QualType Res = QualType::ReadVal(D); + SourceLocation OpLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + + return new SizeOfAlignOfTypeExpr(isSizeof,Ty,Res,OpLoc,RParenLoc); +} + +void StmtExpr::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(LParenLoc); + S.Emit(RParenLoc); + S.EmitOwnedPtr(SubStmt); +} + +StmtExpr* StmtExpr::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + SourceLocation R = SourceLocation::ReadVal(D); + CompoundStmt* SubStmt = cast<CompoundStmt>(D.ReadOwnedPtr<Stmt>()); + return new StmtExpr(SubStmt,t,L,R); +} + +void StringLiteral::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(firstTokLoc); + S.Emit(lastTokLoc); + S.EmitBool(isWide()); + S.Emit(getByteLength()); + + for (unsigned i = 0 ; i < ByteLength; ++i) + S.EmitInt(StrData[i]); +} + +StringLiteral* StringLiteral::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation firstTokLoc = SourceLocation::ReadVal(D); + SourceLocation lastTokLoc = SourceLocation::ReadVal(D); + bool isWide = D.ReadBool(); + unsigned ByteLength = D.ReadInt(); + + StringLiteral* sl = new StringLiteral(NULL,0,isWide,t,firstTokLoc,lastTokLoc); + + char* StrData = new char[ByteLength]; + for (unsigned i = 0; i < ByteLength; ++i) + StrData[i] = (char) D.ReadInt(); + + sl->ByteLength = ByteLength; + sl->StrData = StrData; + + return sl; +} + +void SwitchStmt::EmitImpl(Serializer& S) const { + S.Emit(SwitchLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); + S.EmitPtr(FirstCase); +} + +SwitchStmt* SwitchStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* Cond = D.ReadOwnedPtr<Stmt>(); + Stmt* Body = D.ReadOwnedPtr<Stmt>(); + SwitchCase* FirstCase = cast<SwitchCase>(D.ReadPtr<Stmt>()); + + SwitchStmt* stmt = new SwitchStmt(cast<Expr>(Cond)); + stmt->setBody(Body,Loc); + stmt->FirstCase = FirstCase; + + return stmt; +} + +void UnaryOperator::EmitImpl(Serializer& S) const { + S.Emit(getType()); + S.Emit(Loc); + S.EmitInt(Opc); + S.EmitOwnedPtr(Val); +} + +UnaryOperator* UnaryOperator::CreateImpl(Deserializer& D) { + QualType t = QualType::ReadVal(D); + SourceLocation L = SourceLocation::ReadVal(D); + Opcode Opc = static_cast<Opcode>(D.ReadInt()); + Expr* Val = D.ReadOwnedPtr<Expr>(); + return new UnaryOperator(Val,Opc,t,L); +} + +void WhileStmt::EmitImpl(Serializer& S) const { + S.Emit(WhileLoc); + S.EmitOwnedPtr(getCond()); + S.EmitOwnedPtr(getBody()); +} + +WhileStmt* WhileStmt::CreateImpl(Deserializer& D) { + SourceLocation WhileLoc = SourceLocation::ReadVal(D); + Expr* Cond = D.ReadOwnedPtr<Expr>(); + Stmt* Body = D.ReadOwnedPtr<Stmt>(); + return new WhileStmt(Cond,Body,WhileLoc); +} + +//===----------------------------------------------------------------------===// +// Objective C Serialization +//===----------------------------------------------------------------------===// + +void ObjCAtCatchStmt::EmitImpl(Serializer& S) const { + S.Emit(AtCatchLoc); + S.Emit(RParenLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubExprs[0]); +} + +ObjCAtCatchStmt* ObjCAtCatchStmt::CreateImpl(Deserializer& D) { + SourceLocation AtCatchLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + + ObjCAtCatchStmt* stmt = new ObjCAtCatchStmt(AtCatchLoc,RParenLoc); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubExprs[0]); + + return stmt; +} + +void ObjCAtFinallyStmt::EmitImpl(Serializer& S) const { + S.Emit(AtFinallyLoc); + S.EmitOwnedPtr(AtFinallyStmt); +} + +ObjCAtFinallyStmt* ObjCAtFinallyStmt::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + Stmt* AtFinallyStmt = D.ReadOwnedPtr<Stmt>(); + return new ObjCAtFinallyStmt(Loc,AtFinallyStmt); +} + +void ObjCAtSynchronizedStmt::EmitImpl(Serializer& S) const { + S.Emit(AtSynchronizedLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR,&SubStmts[0]); + } + +ObjCAtSynchronizedStmt* ObjCAtSynchronizedStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + ObjCAtSynchronizedStmt* stmt = new ObjCAtSynchronizedStmt(L,0,0); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); + return stmt; +} + +void ObjCAtThrowStmt::EmitImpl(Serializer& S) const { + S.Emit(AtThrowLoc); + S.EmitOwnedPtr(Throw); +} + +ObjCAtThrowStmt* ObjCAtThrowStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + Stmt* Throw = D.ReadOwnedPtr<Stmt>(); + return new ObjCAtThrowStmt(L,Throw); +} + +void ObjCAtTryStmt::EmitImpl(Serializer& S) const { + S.Emit(AtTryLoc); + S.BatchEmitOwnedPtrs((unsigned) END_EXPR, &SubStmts[0]); +} + +ObjCAtTryStmt* ObjCAtTryStmt::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + ObjCAtTryStmt* stmt = new ObjCAtTryStmt(L,NULL,NULL,NULL); + D.BatchReadOwnedPtrs((unsigned) END_EXPR, &stmt->SubStmts[0]); + return stmt; +} + +void ObjCEncodeExpr::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(RParenLoc); + S.Emit(getType()); + S.Emit(EncType); +} + +ObjCEncodeExpr* ObjCEncodeExpr::CreateImpl(Deserializer& D) { + SourceLocation AtLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + QualType ET = QualType::ReadVal(D); + return new ObjCEncodeExpr(T,ET,AtLoc,RParenLoc); +} + +void ObjCForCollectionStmt::EmitImpl(Serializer& S) const { + S.Emit(ForLoc); + S.Emit(RParenLoc); + S.BatchEmitOwnedPtrs(getElement(),getCollection(),getBody()); +} + +ObjCForCollectionStmt* ObjCForCollectionStmt::CreateImpl(Deserializer& D) { + SourceLocation ForLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + Stmt* Element; + Expr* Collection; + Stmt* Body; + D.BatchReadOwnedPtrs(Element,Collection,Body); + return new ObjCForCollectionStmt(Element,Collection,Body,ForLoc, RParenLoc); +} + +void ObjCIvarRefExpr::EmitImpl(Serializer& S) const { + S.Emit(Loc); + S.Emit(getType()); + S.EmitPtr(getDecl()); +} + +ObjCIvarRefExpr* ObjCIvarRefExpr::CreateImpl(Deserializer& D) { + SourceLocation Loc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + ObjCIvarRefExpr* dr = new ObjCIvarRefExpr(NULL,T,Loc); + D.ReadPtr(dr->D,false); + return dr; +} + +void ObjCSelectorExpr::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(RParenLoc); + S.Emit(getType()); + S.Emit(SelName); +} + +ObjCSelectorExpr* ObjCSelectorExpr::CreateImpl(Deserializer& D) { + SourceLocation AtLoc = SourceLocation::ReadVal(D); + SourceLocation RParenLoc = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + Selector SelName = Selector::ReadVal(D); + + return new ObjCSelectorExpr(T,SelName,AtLoc,RParenLoc); +} + +void ObjCStringLiteral::EmitImpl(Serializer& S) const { + S.Emit(AtLoc); + S.Emit(getType()); + S.EmitOwnedPtr(String); +} + +ObjCStringLiteral* ObjCStringLiteral::CreateImpl(Deserializer& D) { + SourceLocation L = SourceLocation::ReadVal(D); + QualType T = QualType::ReadVal(D); + StringLiteral* String = cast<StringLiteral>(D.ReadOwnedPtr<Stmt>()); + return new ObjCStringLiteral(String,T,L); +} diff --git a/clang/lib/AST/StmtViz.cpp b/clang/lib/AST/StmtViz.cpp new file mode 100644 index 00000000000..51d514b20aa --- /dev/null +++ b/clang/lib/AST/StmtViz.cpp @@ -0,0 +1,59 @@ +//===--- StmtViz.cpp - Graphviz visualization for Stmt ASTs -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements Stmt::viewAST, which generates a Graphviz DOT file +// that depicts the AST and then calls Graphviz/dot+gv on it. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/StmtGraphTraits.h" +#include "llvm/Support/GraphWriter.h" +#include <sstream> + +using namespace clang; + +void Stmt::viewAST() const { +#ifndef NDEBUG + llvm::ViewGraph(this,"AST"); +#else + llvm::cerr << "Stmt::viewAST is only available in debug builds on " + << "systems with Graphviz or gv!\n"; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits<const Stmt*> : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const Stmt* Node, const Stmt* Graph) { + +#ifndef NDEBUG + std::ostringstream Out; + + if (Node) + Out << Node->getStmtClassName(); + else + Out << "<NULL>"; + + std::string OutStr = Out.str(); + if (OutStr[0] == '\n') OutStr.erase(OutStr.begin()); + + // Process string output to make it nicer... + for (unsigned i = 0; i != OutStr.length(); ++i) + if (OutStr[i] == '\n') { // Left justify + OutStr[i] = '\\'; + OutStr.insert(OutStr.begin()+i+1, 'l'); + } + + return OutStr; +#else + return ""; +#endif + } +}; +} // end namespace llvm diff --git a/clang/lib/AST/TranslationUnit.cpp b/clang/lib/AST/TranslationUnit.cpp new file mode 100644 index 00000000000..b91448b2d3f --- /dev/null +++ b/clang/lib/AST/TranslationUnit.cpp @@ -0,0 +1,225 @@ +//===--- TranslationUnit.cpp - Abstraction for Translation Units ----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +// FIXME: This should eventually be moved out of the driver, or replaced +// with its eventual successor. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TranslationUnit.h" + +#include "clang/Basic/TargetInfo.h" +#include "clang/Basic/SourceManager.h" +#include "clang/AST/AST.h" + +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/System/Path.h" +#include "llvm/ADT/OwningPtr.h" + +#include <stdio.h> + +using namespace clang; + +enum { BasicMetadataBlock = 1, + ASTContextBlock = 2, + DeclsBlock = 3 }; + + +bool clang::EmitASTBitcodeFile(const TranslationUnit& TU, + const llvm::sys::Path& Filename) { + + // Reserve 256K for bitstream buffer. + std::vector<unsigned char> Buffer; + Buffer.reserve(256*1024); + + // Create bitstream. + llvm::BitstreamWriter Stream(Buffer); + + // Emit the preamble. + Stream.Emit((unsigned)'B', 8); + Stream.Emit((unsigned)'C', 8); + Stream.Emit(0xC, 4); + Stream.Emit(0xF, 4); + Stream.Emit(0xE, 4); + Stream.Emit(0x0, 4); + + { + // Create serializer. Placing it in its own scope assures any necessary + // finalization of bits to the buffer in the serializer's dstor. + llvm::Serializer Sezr(Stream); + + // Emit the translation unit. + TU.Emit(Sezr); + } + + // Write the bits to disk. + if (FILE* fp = fopen(Filename.c_str(),"wb")) { + fwrite((char*)&Buffer.front(), sizeof(char), Buffer.size(), fp); + fclose(fp); + return true; + } + + return false; +} + +void TranslationUnit::Emit(llvm::Serializer& Sezr) const { + + // ===---------------------------------------------------===/ + // Serialize the top-level decls. + // ===---------------------------------------------------===/ + + Sezr.EnterBlock(DeclsBlock); + + // Only serialize the head of a decl chain. The ASTConsumer interfaces + // provides us with each top-level decl, including those nested in + // a decl chain, so we may be passed decls that are already serialized. + for (const_iterator I=begin(), E=end(); I!=E; ++I) + if (!Sezr.isRegistered(*I)) + Sezr.EmitOwnedPtr(*I); + + Sezr.ExitBlock(); + + // ===---------------------------------------------------===/ + // Serialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Emit ASTContext. + Sezr.EnterBlock(ASTContextBlock); + Sezr.EmitOwnedPtr(Context); + Sezr.ExitBlock(); + + Sezr.EnterBlock(BasicMetadataBlock); + + // Block for SourceManager, LangOptions, and Target. Allows easy skipping + // around to the block for the Selectors during deserialization. + Sezr.EnterBlock(); + + // Emit the SourceManager. + Sezr.Emit(Context->getSourceManager()); + + // Emit the LangOptions. + Sezr.Emit(LangOpts); + + // Emit the Target. + Sezr.EmitPtr(&Context->Target); + Sezr.EmitCStr(Context->Target.getTargetTriple()); + + Sezr.ExitBlock(); // exit "BasicMetadataBlock" + + // Emit the Selectors. + Sezr.Emit(Context->Selectors); + + // Emit the Identifier Table. + Sezr.Emit(Context->Idents); + + Sezr.ExitBlock(); // exit "ASTContextBlock" +} + +TranslationUnit* +clang::ReadASTBitcodeFile(const llvm::sys::Path& Filename, FileManager& FMgr) { + + // Create the memory buffer that contains the contents of the file. + llvm::OwningPtr<llvm::MemoryBuffer> + MBuffer(llvm::MemoryBuffer::getFile(Filename.c_str(), + strlen(Filename.c_str()))); + + if (!MBuffer) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Check if the file is of the proper length. + if (MBuffer->getBufferSize() & 0x3) { + // FIXME: Provide diagnostic: "Length should be a multiple of 4 bytes." + return NULL; + } + + // Create the bitstream reader. + unsigned char *BufPtr = (unsigned char *) MBuffer->getBufferStart(); + llvm::BitstreamReader Stream(BufPtr,BufPtr+MBuffer->getBufferSize()); + + if (Stream.Read(8) != 'B' || + Stream.Read(8) != 'C' || + Stream.Read(4) != 0xC || + Stream.Read(4) != 0xF || + Stream.Read(4) != 0xE || + Stream.Read(4) != 0x0) { + // FIXME: Provide diagnostic. + return NULL; + } + + // Create the deserializer. + llvm::Deserializer Dezr(Stream); + + return TranslationUnit::Create(Dezr,FMgr); +} + +TranslationUnit* TranslationUnit::Create(llvm::Deserializer& Dezr, + FileManager& FMgr) { + + // Create the translation unit object. + TranslationUnit* TU = new TranslationUnit(); + + // ===---------------------------------------------------===/ + // Deserialize the "Translation Unit" metadata. + // ===---------------------------------------------------===/ + + // Skip to the BasicMetaDataBlock. First jump to ASTContextBlock + // (which will appear earlier) and record its location. + + bool FoundBlock = Dezr.SkipToBlock(ASTContextBlock); + assert (FoundBlock); + + llvm::Deserializer::Location ASTContextBlockLoc = + Dezr.getCurrentBlockLocation(); + + FoundBlock = Dezr.SkipToBlock(BasicMetadataBlock); + assert (FoundBlock); + + // Read the SourceManager. + SourceManager::CreateAndRegister(Dezr,FMgr); + + // Read the LangOptions. + TU->LangOpts.Read(Dezr); + + { // Read the TargetInfo. + llvm::SerializedPtrID PtrID = Dezr.ReadPtrID(); + char* triple = Dezr.ReadCStr(NULL,0,true); + Dezr.RegisterPtr(PtrID,TargetInfo::CreateTargetInfo(std::string(triple))); + delete [] triple; + } + + // For Selectors, we must read the identifier table first because the + // SelectorTable depends on the identifiers being already deserialized. + llvm::Deserializer::Location SelectorBlkLoc = Dezr.getCurrentBlockLocation(); + Dezr.SkipBlock(); + + // Read the identifier table. + IdentifierTable::CreateAndRegister(Dezr); + + // Now jump back and read the selectors. + Dezr.JumpTo(SelectorBlkLoc); + SelectorTable::CreateAndRegister(Dezr); + + // Now jump back to ASTContextBlock and read the ASTContext. + Dezr.JumpTo(ASTContextBlockLoc); + TU->Context = Dezr.ReadOwnedPtr<ASTContext>(); + + // "Rewind" the stream. Find the block with the serialized top-level decls. + Dezr.Rewind(); + FoundBlock = Dezr.SkipToBlock(DeclsBlock); + assert (FoundBlock); + llvm::Deserializer::Location DeclBlockLoc = Dezr.getCurrentBlockLocation(); + + while (!Dezr.FinishedBlock(DeclBlockLoc)) + TU->AddTopLevelDecl(Dezr.ReadOwnedPtr<Decl>()); + + return TU; +} + diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp new file mode 100644 index 00000000000..80b2d5cb93d --- /dev/null +++ b/clang/lib/AST/Type.cpp @@ -0,0 +1,978 @@ +//===--- Type.cpp - Type representation and manipulation ------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements type-related functionality. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/Streams.h" +#include "llvm/ADT/StringExtras.h" +#include <sstream> + +using namespace clang; + +Type::~Type() {} + +/// isVoidType - Helper method to determine if this is the 'void' type. +bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +bool Type::isObjectType() const { + if (isa<FunctionType>(CanonicalType)) + return false; + else if (CanonicalType->isIncompleteType()) + return false; + else + return true; +} + +bool Type::isDerivedType() const { + switch (CanonicalType->getTypeClass()) { + case Pointer: + case VariableArray: + case ConstantArray: + case IncompleteArray: + case FunctionProto: + case FunctionNoProto: + case Reference: + return true; + case Tagged: { + const TagType *TT = cast<TagType>(CanonicalType); + const Decl::Kind Kind = TT->getDecl()->getKind(); + return Kind == Decl::Struct || Kind == Decl::Union; + } + default: + return false; + } +} + +bool Type::isStructureType() const { + if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) + if (RT->getDecl()->getKind() == Decl::Struct) + return true; + return false; +} +bool Type::isUnionType() const { + if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) + if (RT->getDecl()->getKind() == Decl::Union) + return true; + return false; +} + +bool Type::isComplexType() const { + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isFloatingType(); + return false; +} + +bool Type::isComplexIntegerType() const { + // Check for GCC complex integer extension. + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isIntegerType(); + return false; +} + +const ComplexType *Type::getAsComplexIntegerType() const { + // Are we directly a complex type? + if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) { + if (CTy->getElementType()->isIntegerType()) + return CTy; + } + // If the canonical form of this type isn't the right kind, reject it. + const ComplexType *CTy = dyn_cast<ComplexType>(CanonicalType); + if (!CTy || !CTy->getElementType()->isIntegerType()) + return 0; + + // If this is a typedef for a complex type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsComplexIntegerType(); +} + +/// getDesugaredType - Return the specified type with any "sugar" removed from +/// type type. This takes off typedefs, typeof's etc. If the outer level of +/// the type is already concrete, it returns it unmodified. This is similar +/// to getting the canonical type, but it doesn't remove *all* typedefs. For +/// example, it return "T*" as "T*", (not as "int*"), because the pointer is +/// concrete. +const Type *Type::getDesugaredType() const { + if (const TypedefType *TDT = dyn_cast<TypedefType>(this)) + return TDT->LookThroughTypedefs().getTypePtr(); + if (const TypeOfExpr *TOE = dyn_cast<TypeOfExpr>(this)) + return TOE->getUnderlyingExpr()->getType().getTypePtr(); + if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this)) + return TOT->getUnderlyingType().getTypePtr(); + return this; +} + + +const BuiltinType *Type::getAsBuiltinType() const { + // If this is directly a builtin type, return it. + if (const BuiltinType *BTy = dyn_cast<BuiltinType>(this)) + return BTy; + + // If the canonical form of this type isn't a builtin type, reject it. + if (!isa<BuiltinType>(CanonicalType)) { + // Look through type qualifiers + if (isa<BuiltinType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsBuiltinType(); + return 0; + } + + // If this is a typedef for a builtin type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsBuiltinType(); +} + +const FunctionType *Type::getAsFunctionType() const { + // If this is directly a function type, return it. + if (const FunctionType *FTy = dyn_cast<FunctionType>(this)) + return FTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<FunctionType>(CanonicalType)) { + // Look through type qualifiers + if (isa<FunctionType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsFunctionType(); + return 0; + } + + // If this is a typedef for a function type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsFunctionType(); +} + +const PointerType *Type::getAsPointerType() const { + // If this is directly a pointer type, return it. + if (const PointerType *PTy = dyn_cast<PointerType>(this)) + return PTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<PointerType>(CanonicalType)) { + // Look through type qualifiers + if (isa<PointerType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsPointerType(); + return 0; + } + + // If this is a typedef for a pointer type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsPointerType(); +} + +const ReferenceType *Type::getAsReferenceType() const { + // If this is directly a reference type, return it. + if (const ReferenceType *RTy = dyn_cast<ReferenceType>(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ReferenceType>(CanonicalType)) { + // Look through type qualifiers + if (isa<ReferenceType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsReferenceType(); + return 0; + } + + // If this is a typedef for a reference type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsReferenceType(); +} + +const ArrayType *Type::getAsArrayType() const { + // If this is directly an array type, return it. + if (const ArrayType *ATy = dyn_cast<ArrayType>(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) { + // Look through type qualifiers + if (isa<ArrayType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsArrayType(); + return 0; + } + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsArrayType(); +} + +const ConstantArrayType *Type::getAsConstantArrayType() const { + // If this is directly a constant array type, return it. + if (const ConstantArrayType *ATy = dyn_cast<ConstantArrayType>(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ConstantArrayType>(CanonicalType)) { + // Look through type qualifiers + if (isa<ConstantArrayType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsConstantArrayType(); + return 0; + } + + // If this is a typedef for a constant array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsConstantArrayType(); +} + +const VariableArrayType *Type::getAsVariableArrayType() const { + // If this is directly a variable array type, return it. + if (const VariableArrayType *ATy = dyn_cast<VariableArrayType>(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<VariableArrayType>(CanonicalType)) { + // Look through type qualifiers + if (isa<VariableArrayType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVariableArrayType(); + return 0; + } + + // If this is a typedef for a variable array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsVariableArrayType(); +} + +/// isVariablyModifiedType (C99 6.7.5p3) - Return true for variable length +/// array types and types that contain variable array types in their +/// declarator +bool Type::isVariablyModifiedType() const { + // A VLA is a veriably modified type + if (getAsVariableArrayType()) + return true; + + // An array can contain a variably modified type + if (const ArrayType* AT = getAsArrayType()) + return AT->getElementType()->isVariablyModifiedType(); + + // A pointer can point to a variably modified type + if (const PointerType* PT = getAsPointerType()) + return PT->getPointeeType()->isVariablyModifiedType(); + + // A function can return a variably modified type + // This one isn't completely obvious, but it follows from the + // definition in C99 6.7.5p3. Because of this rule, it's + // illegal to declare a function returning a variably modified type. + if (const FunctionType* FT = getAsFunctionType()) + return FT->getResultType()->isVariablyModifiedType(); + + return false; +} + +bool Type::isIncompleteArrayType() const { + return isa<IncompleteArrayType>(CanonicalType); +} + +const IncompleteArrayType *Type::getAsIncompleteArrayType() const { + // If this is directly a variable array type, return it. + if (const IncompleteArrayType *ATy = dyn_cast<IncompleteArrayType>(this)) + return ATy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<IncompleteArrayType>(CanonicalType)) { + // Look through type qualifiers + if (isa<IncompleteArrayType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsIncompleteArrayType(); + return 0; + } + + // If this is a typedef for a variable array type, strip the typedef off + // without losing all typedef information. + return getDesugaredType()->getAsIncompleteArrayType(); +} + +const RecordType *Type::getAsRecordType() const { + // If this is directly a reference type, return it. + if (const RecordType *RTy = dyn_cast<RecordType>(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<RecordType>(CanonicalType)) { + // Look through type qualifiers + if (isa<RecordType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsRecordType(); + return 0; + } + + // If this is a typedef for a record type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsRecordType(); +} + +const RecordType *Type::getAsStructureType() const { + // If this is directly a structure type, return it. + if (const RecordType *RT = dyn_cast<RecordType>(this)) { + if (RT->getDecl()->getKind() == Decl::Struct) + return RT; + } + + // If the canonical form of this type isn't the right kind, reject it. + if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { + if (RT->getDecl()->getKind() != Decl::Struct) + return 0; + + // If this is a typedef for a structure type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsStructureType(); + } + // Look through type qualifiers + if (isa<RecordType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsStructureType(); + return 0; +} + +const RecordType *Type::getAsUnionType() const { + // If this is directly a union type, return it. + if (const RecordType *RT = dyn_cast<RecordType>(this)) { + if (RT->getDecl()->getKind() == Decl::Union) + return RT; + } + + // If the canonical form of this type isn't the right kind, reject it. + if (const RecordType *RT = dyn_cast<RecordType>(CanonicalType)) { + if (RT->getDecl()->getKind() != Decl::Union) + return 0; + + // If this is a typedef for a union type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsUnionType(); + } + + // Look through type qualifiers + if (isa<RecordType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsUnionType(); + return 0; +} + +const ComplexType *Type::getAsComplexType() const { + // Are we directly a complex type? + if (const ComplexType *CTy = dyn_cast<ComplexType>(this)) + return CTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ComplexType>(CanonicalType)) { + // Look through type qualifiers + if (isa<ComplexType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsComplexType(); + return 0; + } + + // If this is a typedef for a complex type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsComplexType(); +} + +const VectorType *Type::getAsVectorType() const { + // Are we directly a vector type? + if (const VectorType *VTy = dyn_cast<VectorType>(this)) + return VTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<VectorType>(CanonicalType)) { + // Look through type qualifiers + if (isa<VectorType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsVectorType(); + return 0; + } + + // If this is a typedef for a vector type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsVectorType(); +} + +const OCUVectorType *Type::getAsOCUVectorType() const { + // Are we directly an OpenCU vector type? + if (const OCUVectorType *VTy = dyn_cast<OCUVectorType>(this)) + return VTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<OCUVectorType>(CanonicalType)) { + // Look through type qualifiers + if (isa<OCUVectorType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsOCUVectorType(); + return 0; + } + + // If this is a typedef for an ocuvector type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsOCUVectorType(); +} + +bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongLong; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isIntegerType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isIntegerType(); + return false; +} + +bool Type::isIntegralType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongLong; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isIntegralType(); + return false; +} + +bool Type::isEnumeralType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isEnumeralType(); + return false; +} + +bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isBooleanType(); + return false; +} + +bool Type::isCharType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Char_U || + BT->getKind() == BuiltinType::UChar || + BT->getKind() == BuiltinType::Char_S || + BT->getKind() == BuiltinType::SChar; + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isCharType(); + return false; +} + +/// isSignedIntegerType - Return true if this is an integer type that is +/// signed, according to C99 6.2.5p4 [char, signed char, short, int, long..], +/// an enum decl which has a signed representation, or a vector of signed +/// integer element type. +bool Type::isSignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::LongLong; + } + + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) + return ED->getIntegerType()->isSignedIntegerType(); + + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isSignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isSignedIntegerType(); + return false; +} + +/// isUnsignedIntegerType - Return true if this is an integer type that is +/// unsigned, according to C99 6.2.5p6 [which returns true for _Bool], an enum +/// decl which has an unsigned representation, or a vector of unsigned integer +/// element type. +bool Type::isUnsignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::ULongLong; + } + + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) + return ED->getIntegerType()->isUnsignedIntegerType(); + + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isUnsignedIntegerType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isUnsignedIntegerType(); + return false; +} + +bool Type::isFloatingType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isFloatingType(); + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isFloatingType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isFloatingType(); + return false; +} + +bool Type::isRealFloatingType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Float && + BT->getKind() <= BuiltinType::LongDouble; + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isRealFloatingType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isRealFloatingType(); + return false; +} + +bool Type::isRealType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongDouble; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isRealType(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isRealType(); + return false; +} + +bool Type::isArithmeticType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + if (const EnumDecl *ED = dyn_cast<EnumDecl>(TT->getDecl())) + // GCC allows forward declaration of enum types (forbid by C99 6.7.2.3p2). + // If a body isn't seen by the time we get here, return false. + return ED->isDefinition(); + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isArithmeticType(); + return isa<ComplexType>(CanonicalType) || isa<VectorType>(CanonicalType); +} + +bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() != BuiltinType::Void; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Enum) + return true; + return false; + } + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isScalarType(); + return isa<PointerType>(CanonicalType) || isa<ComplexType>(CanonicalType) || + isa<ObjCQualifiedIdType>(CanonicalType); +} + +bool Type::isAggregateType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) { + if (TT->getDecl()->getKind() == Decl::Struct) + return true; + return false; + } + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isAggregateType(); + return isa<ArrayType>(CanonicalType); +} + +/// isConstantSizeType - Return true if this is not a variable sized type, +/// according to the rules of C99 6.7.5p3. It is not legal to call this on +/// incomplete types. +bool Type::isConstantSizeType() const { + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isConstantSizeType(); + assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); + // The VAT must have a size, as it is known to be complete. + return !isa<VariableArrayType>(CanonicalType); +} + +/// isIncompleteType - Return true if this is an incomplete type (C99 6.2.5p1) +/// - a type that can describe objects, but which lacks information needed to +/// determine its size. +bool Type::isIncompleteType() const { + switch (CanonicalType->getTypeClass()) { + default: return false; + case ASQual: + return cast<ASQualType>(CanonicalType)->getBaseType()->isIncompleteType(); + case Builtin: + // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never + // be completed. + return isVoidType(); + case Tagged: + // A tagged type (struct/union/enum/class) is incomplete if the decl is a + // forward declaration, but not a full definition (C99 6.2.5p22). + return !cast<TagType>(CanonicalType)->getDecl()->isDefinition(); + case IncompleteArray: + // An array of unknown size is an incomplete type (C99 6.2.5p22). + return true; + } +} + +bool Type::isPromotableIntegerType() const { + if (const ASQualType *ASQT = dyn_cast<ASQualType>(CanonicalType)) + return ASQT->getBaseType()->isPromotableIntegerType(); + const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType); + if (!BT) return false; + switch (BT->getKind()) { + case BuiltinType::Bool: + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + case BuiltinType::Short: + case BuiltinType::UShort: + return true; + default: + return false; + } +} + +const char *BuiltinType::getName() const { + switch (getKind()) { + default: assert(0 && "Unknown builtin type!"); + case Void: return "void"; + case Bool: return "_Bool"; + case Char_S: return "char"; + case Char_U: return "char"; + case SChar: return "signed char"; + case Short: return "short"; + case Int: return "int"; + case Long: return "long"; + case LongLong: return "long long"; + case UChar: return "unsigned char"; + case UShort: return "unsigned short"; + case UInt: return "unsigned int"; + case ULong: return "unsigned long"; + case ULongLong: return "unsigned long long"; + case Float: return "float"; + case Double: return "double"; + case LongDouble: return "long double"; + } +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID, QualType Result, + arg_type_iterator ArgTys, + unsigned NumArgs, bool isVariadic) { + ID.AddPointer(Result.getAsOpaquePtr()); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i].getAsOpaquePtr()); + ID.AddInteger(isVariadic); +} + +void FunctionTypeProto::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic()); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, &Protocols[0], getNumProtocols()); +} + +void ObjCQualifiedIdType::Profile(llvm::FoldingSetNodeID &ID, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjCQualifiedIdType::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: +/// typedef const int A; +/// typedef volatile A B; +/// looking through the typedefs for B will give you "const volatile A". +/// +QualType TypedefType::LookThroughTypedefs() const { + // Usually, there is only a single level of typedefs, be fast in that case. + QualType FirstType = getDecl()->getUnderlyingType(); + if (!isa<TypedefType>(FirstType)) + return FirstType; + + // Otherwise, do the fully general loop. + unsigned TypeQuals = 0; + const TypedefType *TDT = this; + while (1) { + QualType CurType = TDT->getDecl()->getUnderlyingType(); + + + /// FIXME: + /// FIXME: This is incorrect for ASQuals! + /// FIXME: + TypeQuals |= CurType.getCVRQualifiers(); + + TDT = dyn_cast<TypedefType>(CurType); + if (TDT == 0) + return QualType(CurType.getTypePtr(), TypeQuals); + } +} + +bool RecordType::classof(const Type *T) { + if (const TagType *TT = dyn_cast<TagType>(T)) + return isa<RecordDecl>(TT->getDecl()); + return false; +} + + +//===----------------------------------------------------------------------===// +// Type Printing +//===----------------------------------------------------------------------===// + +void QualType::dump(const char *msg) const { + std::string R = "identifier"; + getAsStringInternal(R); + if (msg) + fprintf(stderr, "%s: %s\n", msg, R.c_str()); + else + fprintf(stderr, "%s\n", R.c_str()); +} + +static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { + // Note: funkiness to ensure we get a space only between quals. + bool NonePrinted = true; + if (TypeQuals & QualType::Const) + S += "const", NonePrinted = false; + if (TypeQuals & QualType::Volatile) + S += (NonePrinted+" volatile"), NonePrinted = false; + if (TypeQuals & QualType::Restrict) + S += (NonePrinted+" restrict"), NonePrinted = false; +} + +void QualType::getAsStringInternal(std::string &S) const { + if (isNull()) { + S += "NULL TYPE\n"; + return; + } + + // Print qualifiers as appropriate. + if (unsigned Tq = getCVRQualifiers()) { + std::string TQS; + AppendTypeQualList(TQS, Tq); + if (!S.empty()) + S = TQS + ' ' + S; + else + S = TQS; + } + + getTypePtr()->getAsStringInternal(S); +} + +void BuiltinType::getAsStringInternal(std::string &S) const { + if (S.empty()) { + S = getName(); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = getName() + S; + } +} + +void ComplexType::getAsStringInternal(std::string &S) const { + ElementType->getAsStringInternal(S); + S = "_Complex " + S; +} + +void ASQualType::getAsStringInternal(std::string &S) const { + S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; + BaseType->getAsStringInternal(S); +} + +void PointerType::getAsStringInternal(std::string &S) const { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(PointeeType.getTypePtr())) + S = '(' + S + ')'; + + PointeeType.getAsStringInternal(S); +} + +void ReferenceType::getAsStringInternal(std::string &S) const { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(ReferenceeType.getTypePtr())) + S = '(' + S + ')'; + + ReferenceeType.getAsStringInternal(S); +} + +void ConstantArrayType::getAsStringInternal(std::string &S) const { + S += '['; + S += llvm::utostr(getSize().getZExtValue()); + S += ']'; + + getElementType().getAsStringInternal(S); +} + +void IncompleteArrayType::getAsStringInternal(std::string &S) const { + S += "[]"; + + getElementType().getAsStringInternal(S); +} + +void VariableArrayType::getAsStringInternal(std::string &S) const { + S += '['; + + if (getIndexTypeQualifier()) { + AppendTypeQualList(S, getIndexTypeQualifier()); + S += ' '; + } + + if (getSizeModifier() == Static) + S += "static"; + else if (getSizeModifier() == Star) + S += '*'; + + if (getSizeExpr()) { + std::ostringstream s; + getSizeExpr()->printPretty(s); + S += s.str(); + } + S += ']'; + + getElementType().getAsStringInternal(S); +} + +void VectorType::getAsStringInternal(std::string &S) const { + S += " __attribute__((__vector_size__("; + // FIXME: should multiply by element size somehow. + S += llvm::utostr_32(NumElements*4); // convert back to bytes. + S += ")))"; + ElementType.getAsStringInternal(S); +} + +void OCUVectorType::getAsStringInternal(std::string &S) const { + S += " __attribute__((ocu_vector_type("; + S += llvm::utostr_32(NumElements); + S += ")))"; + ElementType.getAsStringInternal(S); +} + +void TypeOfExpr::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. + InnerString = ' ' + InnerString; + std::ostringstream s; + getUnderlyingExpr()->printPretty(s); + InnerString = "typeof(" + s.str() + ")" + InnerString; +} + +void TypeOfType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. + InnerString = ' ' + InnerString; + std::string Tmp; + getUnderlyingType().getAsStringInternal(Tmp); + InnerString = "typeof(" + Tmp + ")" + InnerString; +} + +void FunctionTypeNoProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + getResultType().getAsStringInternal(S); +} + +void FunctionTypeProto::getAsStringInternal(std::string &S) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "("; + std::string Tmp; + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { + if (i) S += ", "; + getArgType(i).getAsStringInternal(Tmp); + S += Tmp; + Tmp.clear(); + } + + if (isVariadic()) { + if (getNumArgs()) + S += ", "; + S += "..."; + } else if (getNumArgs() == 0) { + // Do not emit int() if we have a proto, emit 'int(void)'. + S += "void"; + } + + S += ")"; + getResultType().getAsStringInternal(S); +} + + +void TypedefType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void ObjCQualifiedInterfaceType::getAsStringInternal( + std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = getDecl()->getName(); + ObjCQIString += '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + ObjCQIString += getProtocols(i)->getName(); + if (i < num-1) + ObjCQIString += ','; + } + ObjCQIString += '>'; + InnerString = ObjCQIString + InnerString; +} + +void ObjCQualifiedIdType::getAsStringInternal( + std::string &InnerString) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = "id"; + ObjCQIString += '<'; + int num = getNumProtocols(); + for (int i = 0; i < num; i++) { + ObjCQIString += getProtocols(i)->getName(); + 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; + + const char *Kind = getDecl()->getKindName(); + const char *ID; + if (const IdentifierInfo *II = getDecl()->getIdentifier()) + ID = II->getName(); + else + ID = "<anonymous>"; + + InnerString = std::string(Kind) + " " + ID + InnerString; +} diff --git a/clang/lib/AST/TypeSerialization.cpp b/clang/lib/AST/TypeSerialization.cpp new file mode 100644 index 00000000000..55c0a48a00d --- /dev/null +++ b/clang/lib/AST/TypeSerialization.cpp @@ -0,0 +1,293 @@ +//===--- TypeSerialization.cpp - Serialization of Decls ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines methods that implement bitcode serialization for Types. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Type.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Bitcode/Serialize.h" +#include "llvm/Bitcode/Deserialize.h" + +using namespace clang; +using llvm::Serializer; +using llvm::Deserializer; +using llvm::SerializedPtrID; + + +void QualType::Emit(Serializer& S) const { + S.EmitPtr(getTypePtr()); + S.EmitInt(getCVRQualifiers()); +} + +QualType QualType::ReadVal(Deserializer& D) { + QualType Q; + D.ReadUIntPtr(Q.ThePtr,false); + Q.ThePtr |= D.ReadInt(); + return Q; +} + +void QualType::ReadBackpatch(Deserializer& D) { + D.ReadUIntPtr(ThePtr,true); + ThePtr |= D.ReadInt(); +} + +//===----------------------------------------------------------------------===// +// Type Serialization: Dispatch code to handle specific types. +//===----------------------------------------------------------------------===// + +void Type::Emit(Serializer& S) const { + S.EmitInt(getTypeClass()); + S.EmitPtr(this); + + if (!isa<BuiltinType>(this)) + EmitImpl(S); +} + +void Type::EmitImpl(Serializer& S) const { + assert (false && "Serializization for type not supported."); +} + +void Type::Create(ASTContext& Context, unsigned i, Deserializer& D) { + Type::TypeClass K = static_cast<Type::TypeClass>(D.ReadInt()); + SerializedPtrID PtrID = D.ReadPtrID(); + + switch (K) { + default: + assert (false && "Deserialization for type not supported."); + break; + + case Type::Builtin: + assert (i < Context.getTypes().size()); + assert (isa<BuiltinType>(Context.getTypes()[i])); + D.RegisterPtr(PtrID,Context.getTypes()[i]); + break; + + case Type::ASQual: + D.RegisterPtr(PtrID,ASQualType::CreateImpl(Context,D)); + break; + + case Type::Complex: + D.RegisterPtr(PtrID,ComplexType::CreateImpl(Context,D)); + break; + + case Type::ConstantArray: + D.RegisterPtr(PtrID,ConstantArrayType::CreateImpl(Context,D)); + break; + + case Type::FunctionNoProto: + D.RegisterPtr(PtrID,FunctionTypeNoProto::CreateImpl(Context,D)); + break; + + case Type::FunctionProto: + D.RegisterPtr(PtrID,FunctionTypeProto::CreateImpl(Context,D)); + break; + + case Type::IncompleteArray: + D.RegisterPtr(PtrID,IncompleteArrayType::CreateImpl(Context,D)); + break; + + case Type::Pointer: + D.RegisterPtr(PtrID,PointerType::CreateImpl(Context,D)); + break; + + case Type::Tagged: + D.RegisterPtr(PtrID,TagType::CreateImpl(Context,D)); + break; + + case Type::TypeName: + D.RegisterPtr(PtrID,TypedefType::CreateImpl(Context,D)); + break; + + case Type::VariableArray: + D.RegisterPtr(PtrID,VariableArrayType::CreateImpl(Context,D)); + break; + } +} + +//===----------------------------------------------------------------------===// +// ASQualType +//===----------------------------------------------------------------------===// + +void ASQualType::EmitImpl(Serializer& S) const { + S.EmitPtr(getBaseType()); + S.EmitInt(getAddressSpace()); +} + +Type* ASQualType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType BaseTy = QualType::ReadVal(D); + unsigned AddressSpace = D.ReadInt(); + return Context.getASQualType(BaseTy, AddressSpace).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// ComplexType +//===----------------------------------------------------------------------===// + +void ComplexType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); +} + +Type* ComplexType::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getComplexType(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// ConstantArray +//===----------------------------------------------------------------------===// + +void ConstantArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); + S.Emit(Size); +} + +Type* ConstantArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + + llvm::APInt Size; + D.Read(Size); + + return Context.getConstantArrayType(ElTy,Size,am,ITQ).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// FunctionTypeNoProto +//===----------------------------------------------------------------------===// + +void FunctionTypeNoProto::EmitImpl(Serializer& S) const { + S.Emit(getResultType()); +} + +Type* FunctionTypeNoProto::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getFunctionTypeNoProto(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// FunctionTypeProto +//===----------------------------------------------------------------------===// + +void FunctionTypeProto::EmitImpl(Serializer& S) const { + S.Emit(getResultType()); + S.EmitBool(isVariadic()); + S.EmitInt(getNumArgs()); + + for (arg_type_iterator I=arg_type_begin(), E=arg_type_end(); I!=E; ++I) + S.Emit(*I); +} + +Type* FunctionTypeProto::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ResultType = QualType::ReadVal(D); + bool isVariadic = D.ReadBool(); + unsigned NumArgs = D.ReadInt(); + + llvm::SmallVector<QualType,15> Args; + + for (unsigned j = 0; j < NumArgs; ++j) + Args.push_back(QualType::ReadVal(D)); + + return Context.getFunctionType(ResultType,&*Args.begin(), + NumArgs,isVariadic).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// PointerType +//===----------------------------------------------------------------------===// + +void PointerType::EmitImpl(Serializer& S) const { + S.Emit(getPointeeType()); +} + +Type* PointerType::CreateImpl(ASTContext& Context, Deserializer& D) { + return Context.getPointerType(QualType::ReadVal(D)).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// TagType +//===----------------------------------------------------------------------===// + +void TagType::EmitImpl(Serializer& S) const { + S.EmitOwnedPtr(getDecl()); +} + +Type* TagType::CreateImpl(ASTContext& Context, Deserializer& D) { + std::vector<Type*>& Types = + const_cast<std::vector<Type*>&>(Context.getTypes()); + + TagType* T = new TagType(NULL,QualType()); + Types.push_back(T); + + // Deserialize the decl. + T->decl = cast<TagDecl>(D.ReadOwnedPtr<Decl>()); + + return T; +} + +//===----------------------------------------------------------------------===// +// TypedefType +//===----------------------------------------------------------------------===// + +void TypedefType::EmitImpl(Serializer& S) const { + S.Emit(QualType((Type*)this,0).getCanonicalType()); + S.EmitPtr(Decl); +} + +Type* TypedefType::CreateImpl(ASTContext& Context, Deserializer& D) { + std::vector<Type*>& Types = + const_cast<std::vector<Type*>&>(Context.getTypes()); + + TypedefType* T = new TypedefType(Type::TypeName, NULL,QualType::ReadVal(D)); + Types.push_back(T); + + D.ReadPtr(T->Decl); // May be backpatched. + return T; +} + +//===----------------------------------------------------------------------===// +// VariableArrayType +//===----------------------------------------------------------------------===// + +void VariableArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); + S.EmitOwnedPtr(SizeExpr); +} + +Type* VariableArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + Expr* SizeExpr = D.ReadOwnedPtr<Expr>(); + + return Context.getVariableArrayType(ElTy,SizeExpr,am,ITQ).getTypePtr(); +} + +//===----------------------------------------------------------------------===// +// IncompleteArrayType +//===----------------------------------------------------------------------===// + +void IncompleteArrayType::EmitImpl(Serializer& S) const { + S.Emit(getElementType()); + S.EmitInt(getSizeModifier()); + S.EmitInt(getIndexTypeQualifier()); +} + +Type* IncompleteArrayType::CreateImpl(ASTContext& Context, Deserializer& D) { + QualType ElTy = QualType::ReadVal(D); + ArraySizeModifier am = static_cast<ArraySizeModifier>(D.ReadInt()); + unsigned ITQ = D.ReadInt(); + + return Context.getIncompleteArrayType(ElTy,am,ITQ).getTypePtr(); +} |