diff options
Diffstat (limited to 'lib/AST')
-rw-r--r-- | lib/AST/APValue.cpp | 108 | ||||
-rw-r--r-- | lib/AST/ASTConsumer.cpp | 19 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 3332 | ||||
-rw-r--r-- | lib/AST/Builtins.cpp | 290 | ||||
-rw-r--r-- | lib/AST/CFG.cpp | 1913 | ||||
-rw-r--r-- | lib/AST/CMakeLists.txt | 32 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 630 | ||||
-rw-r--r-- | lib/AST/DeclBase.cpp | 756 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 462 | ||||
-rw-r--r-- | lib/AST/DeclGroup.cpp | 37 | ||||
-rw-r--r-- | lib/AST/DeclObjC.cpp | 693 | ||||
-rw-r--r-- | lib/AST/DeclPrinter.cpp | 722 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 324 | ||||
-rw-r--r-- | lib/AST/DeclarationName.cpp | 355 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 2059 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 424 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 1723 | ||||
-rw-r--r-- | lib/AST/InheritViz.cpp | 168 | ||||
-rw-r--r-- | lib/AST/Makefile | 22 | ||||
-rw-r--r-- | lib/AST/NestedNameSpecifier.cpp | 160 | ||||
-rw-r--r-- | lib/AST/ParentMap.cpp | 94 | ||||
-rw-r--r-- | lib/AST/Stmt.cpp | 587 | ||||
-rw-r--r-- | lib/AST/StmtDumper.cpp | 542 | ||||
-rw-r--r-- | lib/AST/StmtIterator.cpp | 155 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 1239 | ||||
-rw-r--r-- | lib/AST/StmtViz.cpp | 61 | ||||
-rw-r--r-- | lib/AST/TemplateName.cpp | 65 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 1658 |
28 files changed, 18630 insertions, 0 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp new file mode 100644 index 0000000..4df7671 --- /dev/null +++ b/lib/AST/APValue.cpp @@ -0,0 +1,108 @@ +//===--- APValue.cpp - Union class for APFloat/APSInt/Complex -------------===// +// +// 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 APValue class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/APValue.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + + +const APValue &APValue::operator=(const APValue &RHS) { + if (Kind != RHS.Kind) { + MakeUninit(); + if (RHS.isInt()) + MakeInt(); + else if (RHS.isFloat()) + MakeFloat(); + else if (RHS.isVector()) + MakeVector(); + else if (RHS.isComplexInt()) + MakeComplexInt(); + else if (RHS.isComplexFloat()) + MakeComplexFloat(); + else if (RHS.isLValue()) + MakeLValue(); + } + if (isInt()) + setInt(RHS.getInt()); + else if (isFloat()) + setFloat(RHS.getFloat()); + else if (isVector()) + setVector(((Vec*)(void*)RHS.Data)->Elts, RHS.getVectorLength()); + else if (isComplexInt()) + setComplexInt(RHS.getComplexIntReal(), RHS.getComplexIntImag()); + else if (isComplexFloat()) + setComplexFloat(RHS.getComplexFloatReal(), RHS.getComplexFloatImag()); + else if (isLValue()) + setLValue(RHS.getLValueBase(), RHS.getLValueOffset()); + return *this; +} + +void APValue::MakeUninit() { + if (Kind == Int) + ((APSInt*)(void*)Data)->~APSInt(); + else if (Kind == Float) + ((APFloat*)(void*)Data)->~APFloat(); + else if (Kind == Vector) + ((Vec*)(void*)Data)->~Vec(); + else if (Kind == ComplexInt) + ((ComplexAPSInt*)(void*)Data)->~ComplexAPSInt(); + else if (Kind == ComplexFloat) + ((ComplexAPFloat*)(void*)Data)->~ComplexAPFloat(); + else if (Kind == LValue) { + ((LV*)(void*)Data)->~LV(); + } + Kind = Uninitialized; +} + +void APValue::dump() const { + print(llvm::errs()); + llvm::errs() << '\n'; +} + +static double GetApproxValue(const llvm::APFloat &F) { + llvm::APFloat V = F; + bool ignored; + V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven, + &ignored); + return V.convertToDouble(); +} + +void APValue::print(llvm::raw_ostream &OS) const { + switch (getKind()) { + default: assert(0 && "Unknown APValue kind!"); + case Uninitialized: + OS << "Uninitialized"; + return; + case Int: + OS << "Int: " << getInt(); + return; + case Float: + OS << "Float: " << GetApproxValue(getFloat()); + return; + case Vector: + OS << "Vector: " << getVectorElt(0); + for (unsigned i = 1; i != getVectorLength(); ++i) + OS << ", " << getVectorElt(i); + return; + case ComplexInt: + OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag(); + return; + case ComplexFloat: + OS << "ComplexFloat: " << GetApproxValue(getComplexFloatReal()) + << ", " << GetApproxValue(getComplexFloatImag()); + case LValue: + OS << "LValue: <todo>"; + return; + } +} + diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp new file mode 100644 index 0000000..f37cbde --- /dev/null +++ b/lib/AST/ASTConsumer.cpp @@ -0,0 +1,19 @@ +//===--- 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/DeclGroup.h" +using namespace clang; + +void ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) {} + diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp new file mode 100644 index 0000000..29bca29 --- /dev/null +++ b/lib/AST/ASTContext.cpp @@ -0,0 +1,3332 @@ +//===--- 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/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBuffer.h" +using namespace clang; + +enum FloatingRank { + FloatRank, DoubleRank, LongDoubleRank +}; + +ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, + TargetInfo &t, + IdentifierTable &idents, SelectorTable &sels, + bool FreeMem, unsigned size_reserve, + bool InitializeBuiltins) : + GlobalNestedNameSpecifier(0), CFConstantStringTypeDecl(0), + ObjCFastEnumerationStateTypeDecl(0), SourceMgr(SM), LangOpts(LOpts), + FreeMemory(FreeMem), Target(t), Idents(idents), Selectors(sels), + ExternalSource(0) { + if (size_reserve > 0) Types.reserve(size_reserve); + InitBuiltinTypes(); + TUDecl = TranslationUnitDecl::Create(*this); + BuiltinInfo.InitializeTargetBuiltins(Target); + if (InitializeBuiltins) + this->InitializeBuiltins(idents); + PrintingPolicy.CPlusPlus = LangOpts.CPlusPlus; +} + +ASTContext::~ASTContext() { + // Deallocate all the types. + while (!Types.empty()) { + Types.back()->Destroy(*this); + Types.pop_back(); + } + + { + llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator + I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); + while (I != E) { + ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); + delete R; + } + } + + { + llvm::DenseMap<const ObjCContainerDecl*, const ASTRecordLayout*>::iterator + I = ObjCLayouts.begin(), E = ObjCLayouts.end(); + while (I != E) { + ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second); + delete R; + } + } + + // Destroy nested-name-specifiers. + for (llvm::FoldingSet<NestedNameSpecifier>::iterator + NNS = NestedNameSpecifiers.begin(), + NNSEnd = NestedNameSpecifiers.end(); + NNS != NNSEnd; + /* Increment in loop */) + (*NNS++).Destroy(*this); + + if (GlobalNestedNameSpecifier) + GlobalNestedNameSpecifier->Destroy(*this); + + TUDecl->Destroy(*this); +} + +void ASTContext::InitializeBuiltins(IdentifierTable &idents) { + BuiltinInfo.InitializeBuiltins(idents, LangOpts.NoBuiltin); +} + +void +ASTContext::setExternalSource(llvm::OwningPtr<ExternalASTSource> &Source) { + ExternalSource.reset(Source.take()); +} + +void ASTContext::PrintStats() const { + fprintf(stderr, "*** AST Context Stats:\n"); + fprintf(stderr, " %d types total.\n", (int)Types.size()); + + unsigned counts[] = { +#define TYPE(Name, Parent) 0, +#define ABSTRACT_TYPE(Name, Parent) +#include "clang/AST/TypeNodes.def" + 0 // Extra + }; + + for (unsigned i = 0, e = Types.size(); i != e; ++i) { + Type *T = Types[i]; + counts[(unsigned)T->getTypeClass()]++; + } + + unsigned Idx = 0; + unsigned TotalBytes = 0; +#define TYPE(Name, Parent) \ + if (counts[Idx]) \ + fprintf(stderr, " %d %s types\n", (int)counts[Idx], #Name); \ + TotalBytes += counts[Idx] * sizeof(Name##Type); \ + ++Idx; +#define ABSTRACT_TYPE(Name, Parent) +#include "clang/AST/TypeNodes.def" + + fprintf(stderr, "Total bytes = %d\n", int(TotalBytes)); + + if (ExternalSource.get()) { + fprintf(stderr, "\n"); + ExternalSource->PrintStats(); + } +} + + +void ASTContext::InitBuiltinType(QualType &R, BuiltinType::Kind K) { + Types.push_back((R = QualType(new (*this,8) 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); + + // GNU extension, 128-bit integers. + InitBuiltinType(Int128Ty, BuiltinType::Int128); + InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); + + if (LangOpts.CPlusPlus) // C++ 3.9.1p5 + InitBuiltinType(WCharTy, BuiltinType::WChar); + else // C99 + WCharTy = getFromTargetType(Target.getWCharType()); + + // Placeholder type for functions. + InitBuiltinType(OverloadTy, BuiltinType::Overload); + + // Placeholder type for type-dependent expressions whose type is + // completely unknown. No code should ever check a type against + // DependentTy and users should never see it; however, it is here to + // help diagnose failures to properly check for type-dependent + // expressions. + InitBuiltinType(DependentTy, BuiltinType::Dependent); + + // 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); + + // nullptr type (C++0x 2.14.7) + InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); +} + +//===----------------------------------------------------------------------===// +// Type Sizing and Analysis +//===----------------------------------------------------------------------===// + +/// getFloatTypeSemantics - Return the APFloat 'semantics' for the specified +/// scalar floating point type. +const llvm::fltSemantics &ASTContext::getFloatTypeSemantics(QualType T) const { + const BuiltinType *BT = T->getAsBuiltinType(); + assert(BT && "Not a floating point type!"); + switch (BT->getKind()) { + default: assert(0 && "Not a floating point type!"); + case BuiltinType::Float: return Target.getFloatFormat(); + case BuiltinType::Double: return Target.getDoubleFormat(); + case BuiltinType::LongDouble: return Target.getLongDoubleFormat(); + } +} + +/// getDeclAlign - Return a conservative estimate of the alignment of the +/// specified decl. Note that bitfields do not have a valid alignment, so +/// this method will assert on them. +unsigned ASTContext::getDeclAlignInBytes(const Decl *D) { + unsigned Align = Target.getCharWidth(); + + if (const AlignedAttr* AA = D->getAttr<AlignedAttr>()) + Align = std::max(Align, AA->getAlignment()); + + if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + QualType T = VD->getType(); + if (const ReferenceType* RT = T->getAsReferenceType()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + Align = Target.getPointerAlign(AS); + } else if (!T->isIncompleteType() && !T->isFunctionType()) { + // Incomplete or function types default to 1. + while (isa<VariableArrayType>(T) || isa<IncompleteArrayType>(T)) + T = cast<ArrayType>(T)->getElementType(); + + Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); + } + } + + return Align / Target.getCharWidth(); +} + +/// 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(const Type *T) { + uint64_t Width=0; + unsigned Align=8; + switch (T->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Should not see dependent types"); + break; + + case Type::FunctionNoProto: + case Type::FunctionProto: + // GCC extension: alignof(function) = 32 bits + Width = 0; + Align = 32; + break; + + case Type::IncompleteArray: + case Type::VariableArray: + Width = 0; + Align = getTypeAlign(cast<ArrayType>(T)->getElementType()); + break; + + case Type::ConstantArray: { + const 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::ExtVector: + case Type::Vector: { + std::pair<uint64_t, unsigned> EltInfo = + getTypeInfo(cast<VectorType>(T)->getElementType()); + Width = EltInfo.first*cast<VectorType>(T)->getNumElements(); + Align = Width; + // If the alignment is not a power of 2, round up to the next power of 2. + // This happens for non-power-of-2 length vectors. + // FIXME: this should probably be a target property. + Align = 1 << llvm::Log2_32_Ceil(Align); + break; + } + + case Type::Builtin: + switch (cast<BuiltinType>(T)->getKind()) { + default: assert(0 && "Unknown builtin type!"); + case BuiltinType::Void: + // GCC extension: alignof(void) = 8 bits. + Width = 0; + Align = 8; + break; + + 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::WChar: + Width = Target.getWCharWidth(); + Align = Target.getWCharAlign(); + 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::Int128: + case BuiltinType::UInt128: + Width = 128; + Align = 128; // int128_t is 128-bit aligned on all targets. + 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; + case BuiltinType::NullPtr: + Width = Target.getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) + Align = Target.getPointerAlign(0); // == sizeof(void*) + break; + } + break; + case Type::FixedWidthInt: + // FIXME: This isn't precisely correct; the width/alignment should depend + // on the available types for the target + Width = cast<FixedWidthIntType>(T)->getWidth(); + Width = std::max(llvm::NextPowerOf2(Width - 1), (uint64_t)8); + Align = Width; + break; + case Type::ExtQual: + // FIXME: Pointers into different addr spaces could have different sizes and + // alignment requirements: getPointerInfo should take an AddrSpace. + return getTypeInfo(QualType(cast<ExtQualType>(T)->getBaseType(), 0)); + case Type::ObjCQualifiedId: + case Type::ObjCQualifiedInterface: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; + case Type::BlockPointer: { + unsigned AS = cast<BlockPointerType>(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::Pointer: { + unsigned AS = cast<PointerType>(T)->getPointeeType().getAddressSpace(); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::LValueReference: + case Type::RValueReference: + // "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)->getPointeeType()); + case Type::MemberPointer: { + // FIXME: This is ABI dependent. We use the Itanium C++ ABI. + // http://www.codesourcery.com/public/cxx-abi/abi.html#member-pointers + // If we ever want to support other ABIs this needs to be abstracted. + + QualType Pointee = cast<MemberPointerType>(T)->getPointeeType(); + std::pair<uint64_t, unsigned> PtrDiffInfo = + getTypeInfo(getPointerDiffType()); + Width = PtrDiffInfo.first; + if (Pointee->isFunctionType()) + Width *= 2; + Align = PtrDiffInfo.second; + break; + } + 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::ObjCInterface: { + const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); + const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); + Width = Layout.getSize(); + Align = Layout.getAlignment(); + break; + } + case Type::Record: + case Type::Enum: { + const TagType *TT = cast<TagType>(T); + + if (TT->getDecl()->isInvalidDecl()) { + Width = 1; + Align = 1; + break; + } + + if (const EnumType *ET = dyn_cast<EnumType>(TT)) + return getTypeInfo(ET->getDecl()->getIntegerType()); + + const RecordType *RT = cast<RecordType>(TT); + const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); + Width = Layout.getSize(); + Align = Layout.getAlignment(); + break; + } + + case Type::Typedef: { + const TypedefDecl *Typedef = cast<TypedefType>(T)->getDecl(); + if (const AlignedAttr *Aligned = Typedef->getAttr<AlignedAttr>()) { + Align = Aligned->getAlignment(); + Width = getTypeSize(Typedef->getUnderlyingType().getTypePtr()); + } else + return getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + break; + } + + case Type::TypeOfExpr: + return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType() + .getTypePtr()); + + case Type::TypeOf: + return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr()); + + case Type::QualifiedName: + return getTypeInfo(cast<QualifiedNameType>(T)->getNamedType().getTypePtr()); + + case Type::TemplateSpecialization: + assert(getCanonicalType(T) != T && + "Cannot request the size of a dependent type"); + // FIXME: this is likely to be wrong once we support template + // aliases, since a template alias could refer to a typedef that + // has an __aligned__ attribute on it. + return getTypeInfo(getCanonicalType(T)); + } + + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); + return std::make_pair(Width, Align); +} + +/// getPreferredTypeAlign - Return the "preferred" alignment of the specified +/// type for the current target in bits. This can be different than the ABI +/// alignment in cases where it is beneficial for performance to overalign +/// a data type. +unsigned ASTContext::getPreferredTypeAlign(const Type *T) { + unsigned ABIAlign = getTypeAlign(T); + + // Double and long long should be naturally aligned if possible. + if (const ComplexType* CT = T->getAsComplexType()) + T = CT->getElementType().getTypePtr(); + if (T->isSpecificBuiltinType(BuiltinType::Double) || + T->isSpecificBuiltinType(BuiltinType::LongLong)) + return std::max(ABIAlign, (unsigned)getTypeSize(T)); + + return ABIAlign; +} + + +/// LayoutField - Field layout. +void ASTRecordLayout::LayoutField(const FieldDecl *FD, unsigned FieldNo, + bool IsUnion, unsigned StructPacking, + ASTContext &Context) { + unsigned FieldPacking = StructPacking; + uint64_t FieldOffset = IsUnion ? 0 : Size; + uint64_t FieldSize; + unsigned FieldAlign; + + // FIXME: Should this override struct packing? Probably we want to + // take the minimum? + if (const PackedAttr *PA = FD->getAttr<PackedAttr>()) + FieldPacking = PA->getAlignment(); + + if (const Expr *BitWidthExpr = FD->getBitWidth()) { + // TODO: Need to check this algorithm on other targets! + // (tested on Linux-X86) + FieldSize = BitWidthExpr->EvaluateAsInt(Context).getZExtValue(); + + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + + // Determine the alignment of this bitfield. The packing + // attributes define a maximum and the alignment attribute defines + // a minimum. + // FIXME: What is the right behavior when the specified alignment + // is smaller than the specified packing? + FieldAlign = FieldInfo.second; + if (FieldPacking) + FieldAlign = std::min(FieldAlign, FieldPacking); + if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + + // Check if we need to add padding to give the field the correct + // alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + + // Padding members don't affect overall alignment + if (!FD->getIdentifier()) + FieldAlign = 1; + } else { + if (FD->getType()->isIncompleteArrayType()) { + // This is 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. + FieldSize = 0; + const ArrayType* ATy = Context.getAsArrayType(FD->getType()); + FieldAlign = Context.getTypeAlign(ATy->getElementType()); + } else if (const ReferenceType *RT = FD->getType()->getAsReferenceType()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = Context.Target.getPointerWidth(AS); + FieldAlign = Context.Target.getPointerAlign(AS); + } else { + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + } + + // Determine the alignment of this bitfield. The packing + // attributes define a maximum and the alignment attribute defines + // a minimum. Additionally, the packing alignment must be at least + // a byte for non-bitfields. + // + // FIXME: What is the right behavior when the specified alignment + // is smaller than the specified packing? + if (FieldPacking) + FieldAlign = std::min(FieldAlign, std::max(8U, FieldPacking)); + if (const AlignedAttr *AA = FD->getAttr<AlignedAttr>()) + FieldAlign = std::max(FieldAlign, AA->getAlignment()); + + // Round up the current record size to the field's alignment boundary. + FieldOffset = (FieldOffset + (FieldAlign-1)) & ~(FieldAlign-1); + } + + // Place this field at the current location. + FieldOffsets[FieldNo] = FieldOffset; + + // Reserve space for this field. + if (IsUnion) { + Size = std::max(Size, FieldSize); + } else { + Size = FieldOffset + FieldSize; + } + + // Remember the next available offset. + NextOffset = Size; + + // Remember max struct/class alignment. + Alignment = std::max(Alignment, FieldAlign); +} + +static void CollectLocalObjCIvars(ASTContext *Ctx, + const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<FieldDecl*> &Fields) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) { + ObjCIvarDecl *IVDecl = *I; + if (!IVDecl->isInvalidDecl()) + Fields.push_back(cast<FieldDecl>(IVDecl)); + } +} + +void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<FieldDecl*> &Fields) { + if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) + CollectObjCIvars(SuperClass, Fields); + CollectLocalObjCIvars(this, OI, Fields); +} + +void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(*this), + E = PD->prop_end(*this); I != E; ++I) + if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) + Ivars.push_back(Ivar); + + // Also look into nested protocols. + for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), + E = PD->protocol_end(); P != E; ++P) + CollectProtocolSynthesizedIvars(*P, Ivars); +} + +/// CollectSynthesizedIvars - +/// This routine collect synthesized ivars for the designated class. +/// +void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) { + for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(*this), + E = OI->prop_end(*this); I != E; ++I) { + if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) + Ivars.push_back(Ivar); + } + // Also look into interface's protocol list for properties declared + // in the protocol and whose ivars are synthesized. + for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), + PE = OI->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *PD = (*P); + CollectProtocolSynthesizedIvars(PD, Ivars); + } +} + +/// getInterfaceLayoutImpl - Get or compute information about the +/// layout of the given interface. +/// +/// \param Impl - If given, also include the layout of the interface's +/// implementation. This may differ by including synthesized ivars. +const ASTRecordLayout & +ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, + const ObjCImplementationDecl *Impl) { + assert(!D->isForwardDecl() && "Invalid interface decl!"); + + // Look up this layout, if already laid out, return what we have. + ObjCContainerDecl *Key = + Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; + if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) + return *Entry; + + unsigned FieldCount = D->ivar_size(); + // Add in synthesized ivar count if laying out an implementation. + if (Impl) { + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + CollectSynthesizedIvars(D, Ivars); + FieldCount += Ivars.size(); + // If there aren't any sythesized ivars then reuse the interface + // entry. Note we can't cache this because we simply free all + // entries later; however we shouldn't look up implementations + // frequently. + if (FieldCount == D->ivar_size()) + return getObjCLayout(D, 0); + } + + ASTRecordLayout *NewEntry = NULL; + if (ObjCInterfaceDecl *SD = D->getSuperClass()) { + const ASTRecordLayout &SL = getASTObjCInterfaceLayout(SD); + unsigned Alignment = SL.getAlignment(); + + // We start laying out ivars not at the end of the superclass + // structure, but at the next byte following the last field. + uint64_t Size = llvm::RoundUpToAlignment(SL.NextOffset, 8); + + ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(Size, Alignment); + NewEntry->InitializeLayout(FieldCount); + } else { + ObjCLayouts[Key] = NewEntry = new ASTRecordLayout(); + NewEntry->InitializeLayout(FieldCount); + } + + unsigned StructPacking = 0; + if (const PackedAttr *PA = D->getAttr<PackedAttr>()) + StructPacking = PA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), + AA->getAlignment())); + + // Layout each ivar sequentially. + unsigned i = 0; + for (ObjCInterfaceDecl::ivar_iterator IVI = D->ivar_begin(), + IVE = D->ivar_end(); IVI != IVE; ++IVI) { + const ObjCIvarDecl* Ivar = (*IVI); + NewEntry->LayoutField(Ivar, i++, false, StructPacking, *this); + } + // And synthesized ivars, if this is an implementation. + if (Impl) { + // FIXME. Do we need to colltect twice? + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + CollectSynthesizedIvars(D, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); + } + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + NewEntry->FinalizeLayout(); + return *NewEntry; +} + +const ASTRecordLayout & +ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) { + return getObjCLayout(D, 0); +} + +const ASTRecordLayout & +ASTContext::getASTObjCImplementationLayout(const ObjCImplementationDecl *D) { + return getObjCLayout(D->getClassInterface(), D); +} + +/// 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) { + D = D->getDefinition(*this); + assert(D && "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; + + // FIXME: Avoid linear walk through the fields, if possible. + NewEntry->InitializeLayout(std::distance(D->field_begin(*this), + D->field_end(*this))); + bool IsUnion = D->isUnion(); + + unsigned StructPacking = 0; + if (const PackedAttr *PA = D->getAttr<PackedAttr>()) + StructPacking = PA->getAlignment(); + + if (const AlignedAttr *AA = D->getAttr<AlignedAttr>()) + NewEntry->SetAlignment(std::max(NewEntry->getAlignment(), + AA->getAlignment())); + + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + unsigned FieldIdx = 0; + for (RecordDecl::field_iterator Field = D->field_begin(*this), + FieldEnd = D->field_end(*this); + Field != FieldEnd; (void)++Field, ++FieldIdx) + NewEntry->LayoutField(*Field, FieldIdx, IsUnion, StructPacking, *this); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + NewEntry->FinalizeLayout(getLangOptions().CPlusPlus); + return *NewEntry; +} + +//===----------------------------------------------------------------------===// +// Type creation/memoization methods +//===----------------------------------------------------------------------===// + +QualType ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) { + QualType CanT = getCanonicalType(T); + if (CanT.getAddressSpace() == AddressSpace) + return T; + + // If we are composing extended qualifiers together, merge together into one + // ExtQualType node. + unsigned CVRQuals = T.getCVRQualifiers(); + QualType::GCAttrTypes GCAttr = QualType::GCNone; + Type *TypeNode = T.getTypePtr(); + + if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) { + // If this type already has an address space specified, it cannot get + // another one. + assert(EQT->getAddressSpace() == 0 && + "Type cannot be in multiple addr spaces!"); + GCAttr = EQT->getObjCGCAttr(); + TypeNode = EQT->getBaseType(); + } + + // Check if we've already instantiated this type. + llvm::FoldingSetNodeID ID; + ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); + void *InsertPos = 0; + if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(EXTQy, CVRQuals); + + // 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 (!TypeNode->isCanonical()) { + Canonical = getAddrSpaceQualType(CanT, AddressSpace); + + // Update InsertPos, the previous call could have invalidated it. + ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + ExtQualType *New = + new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); + ExtQualTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, CVRQuals); +} + +QualType ASTContext::getObjCGCQualType(QualType T, + QualType::GCAttrTypes GCAttr) { + QualType CanT = getCanonicalType(T); + if (CanT.getObjCGCAttr() == GCAttr) + return T; + + // If we are composing extended qualifiers together, merge together into one + // ExtQualType node. + unsigned CVRQuals = T.getCVRQualifiers(); + Type *TypeNode = T.getTypePtr(); + unsigned AddressSpace = 0; + + if (ExtQualType *EQT = dyn_cast<ExtQualType>(TypeNode)) { + // If this type already has an address space specified, it cannot get + // another one. + assert(EQT->getObjCGCAttr() == QualType::GCNone && + "Type cannot be in multiple addr spaces!"); + AddressSpace = EQT->getAddressSpace(); + TypeNode = EQT->getBaseType(); + } + + // Check if we've already instantiated an gc qual'd type of this type. + llvm::FoldingSetNodeID ID; + ExtQualType::Profile(ID, TypeNode, AddressSpace, GCAttr); + void *InsertPos = 0; + if (ExtQualType *EXTQy = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(EXTQy, CVRQuals); + + // If the base type isn't canonical, this won't be a canonical type either, + // so fill in the canonical type field. + // FIXME: Isn't this also not canonical if the base type is a array + // or pointer type? I can't find any documentation for objc_gc, though... + QualType Canonical; + if (!T->isCanonical()) { + Canonical = getObjCGCQualType(CanT, GCAttr); + + // Update InsertPos, the previous call could have invalidated it. + ExtQualType *NewIP = ExtQualTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + ExtQualType *New = + new (*this, 8) ExtQualType(TypeNode, Canonical, AddressSpace, GCAttr); + ExtQualTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, CVRQuals); +} + +/// 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(getCanonicalType(T)); + + // 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!"); NewIP = NewIP; + } + ComplexType *New = new (*this,8) ComplexType(T, Canonical); + Types.push_back(New); + ComplexTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +QualType ASTContext::getFixedWidthIntType(unsigned Width, bool Signed) { + llvm::DenseMap<unsigned, FixedWidthIntType*> &Map = Signed ? + SignedFixedWidthIntTypes : UnsignedFixedWidthIntTypes; + FixedWidthIntType *&Entry = Map[Width]; + if (!Entry) + Entry = new FixedWidthIntType(Width, Signed); + return QualType(Entry, 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(getCanonicalType(T)); + + // 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!"); NewIP = NewIP; + } + PointerType *New = new (*this,8) PointerType(T, Canonical); + Types.push_back(New); + PointerTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getBlockPointerType - Return the uniqued reference to the type for +/// a pointer to the specified block. +QualType ASTContext::getBlockPointerType(QualType T) { + assert(T->isFunctionType() && "block of function types only"); + // Unique pointers, to guarantee there is only one block of a particular + // structure. + llvm::FoldingSetNodeID ID; + BlockPointerType::Profile(ID, T); + + void *InsertPos = 0; + if (BlockPointerType *PT = + BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the block 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 = getBlockPointerType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + BlockPointerType *NewIP = + BlockPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + BlockPointerType *New = new (*this,8) BlockPointerType(T, Canonical); + Types.push_back(New); + BlockPointerTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getLValueReferenceType - Return the uniqued reference to the type for an +/// lvalue reference to the specified type. +QualType ASTContext::getLValueReferenceType(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 (LValueReferenceType *RT = + LValueReferenceTypes.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 = getLValueReferenceType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + LValueReferenceType *NewIP = + LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + + LValueReferenceType *New = new (*this,8) LValueReferenceType(T, Canonical); + Types.push_back(New); + LValueReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getRValueReferenceType - Return the uniqued reference to the type for an +/// rvalue reference to the specified type. +QualType ASTContext::getRValueReferenceType(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 (RValueReferenceType *RT = + RValueReferenceTypes.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 = getRValueReferenceType(getCanonicalType(T)); + + // Get the new insert position for the node we care about. + RValueReferenceType *NewIP = + RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + + RValueReferenceType *New = new (*this,8) RValueReferenceType(T, Canonical); + Types.push_back(New); + RValueReferenceTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getMemberPointerType - Return the uniqued reference to the type for a +/// member pointer to the specified type, in the specified class. +QualType ASTContext::getMemberPointerType(QualType T, const Type *Cls) +{ + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + MemberPointerType::Profile(ID, T, Cls); + + void *InsertPos = 0; + if (MemberPointerType *PT = + MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(PT, 0); + + // If the pointee or class 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 = getMemberPointerType(getCanonicalType(T),getCanonicalType(Cls)); + + // Get the new insert position for the node we care about. + MemberPointerType *NewIP = + MemberPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + MemberPointerType *New = new (*this,8) MemberPointerType(T, Cls, Canonical); + Types.push_back(New); + MemberPointerTypes.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 &ArySizeIn, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + assert((EltTy->isDependentType() || EltTy->isConstantSizeType()) && + "Constant array of VLAs is illegal!"); + + // Convert the array size into a canonical width matching the pointer size for + // the target. + llvm::APInt ArySize(ArySizeIn); + ArySize.zextOrTrunc(Target.getPointerWidth(EltTy.getAddressSpace())); + + llvm::FoldingSetNodeID ID; + ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, EltTypeQuals); + + 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(getCanonicalType(EltTy), 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!"); NewIP = NewIP; + } + + ConstantArrayType *New = + new(*this,8)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(*this,8)VariableArrayType(EltTy,QualType(), NumElts, ASM, EltTypeQuals); + + VariableArrayTypes.push_back(New); + Types.push_back(New); + return QualType(New, 0); +} + +/// getDependentSizedArrayType - Returns a non-unique reference to +/// the type for a dependently-sized array of the specified element +/// type. FIXME: We will need these to be uniqued, or at least +/// comparable, at some point. +QualType ASTContext::getDependentSizedArrayType(QualType EltTy, Expr *NumElts, + ArrayType::ArraySizeModifier ASM, + unsigned EltTypeQuals) { + assert((NumElts->isTypeDependent() || NumElts->isValueDependent()) && + "Size must be type- or value-dependent!"); + + // Since we don't unique expressions, it isn't possible to unique + // dependently-sized array types. + + DependentSizedArrayType *New = + new (*this,8) DependentSizedArrayType(EltTy, QualType(), NumElts, + ASM, EltTypeQuals); + + DependentSizedArrayTypes.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, ASM, EltTypeQuals); + + 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(getCanonicalType(EltTy), + 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!"); NewIP = NewIP; + } + + IncompleteArrayType *New = new (*this,8) 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>(getCanonicalType(vecType).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(getCanonicalType(vecType), 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!"); NewIP = NewIP; + } + VectorType *New = new (*this,8) VectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getExtVectorType - Return the unique reference to an extended vector type of +/// the specified element type and size. VectorType must be a built-in type. +QualType ASTContext::getExtVectorType(QualType vecType, unsigned NumElts) { + BuiltinType *baseType; + + baseType = dyn_cast<BuiltinType>(getCanonicalType(vecType).getTypePtr()); + assert(baseType != 0 && "getExtVectorType(): 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::ExtVector); + 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 = getExtVectorType(getCanonicalType(vecType), 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!"); NewIP = NewIP; + } + ExtVectorType *New = new (*this,8) ExtVectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. +/// +QualType ASTContext::getFunctionNoProtoType(QualType ResultTy) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionNoProtoType::Profile(ID, ResultTy); + + void *InsertPos = 0; + if (FunctionNoProtoType *FT = + FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FT, 0); + + QualType Canonical; + if (!ResultTy->isCanonical()) { + Canonical = getFunctionNoProtoType(getCanonicalType(ResultTy)); + + // Get the new insert position for the node we care about. + FunctionNoProtoType *NewIP = + FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + + FunctionNoProtoType *New =new(*this,8)FunctionNoProtoType(ResultTy,Canonical); + Types.push_back(New); + FunctionNoProtoTypes.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,const QualType *ArgArray, + unsigned NumArgs, bool isVariadic, + unsigned TypeQuals, bool hasExceptionSpec, + bool hasAnyExceptionSpec, unsigned NumExs, + const QualType *ExArray) { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, isVariadic, + TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, + NumExs, ExArray); + + void *InsertPos = 0; + if (FunctionProtoType *FTP = + FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FTP, 0); + + // Determine whether the type being created is already canonical or not. + bool isCanonical = ResultTy->isCanonical(); + if (hasExceptionSpec) + isCanonical = false; + 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. + // The exception spec is not part of the canonical type. + QualType Canonical; + if (!isCanonical) { + llvm::SmallVector<QualType, 16> CanonicalArgs; + CanonicalArgs.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + CanonicalArgs.push_back(getCanonicalType(ArgArray[i])); + + Canonical = getFunctionType(getCanonicalType(ResultTy), + CanonicalArgs.data(), NumArgs, + isVariadic, TypeQuals); + + // Get the new insert position for the node we care about. + FunctionProtoType *NewIP = + FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(NewIP == 0 && "Shouldn't be in the map!"); NewIP = NewIP; + } + + // FunctionProtoType objects are allocated with extra bytes after them + // for two variable size arrays (for parameter and exception types) at the + // end of them. + FunctionProtoType *FTP = + (FunctionProtoType*)Allocate(sizeof(FunctionProtoType) + + NumArgs*sizeof(QualType) + + NumExs*sizeof(QualType), 8); + new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, isVariadic, + TypeQuals, hasExceptionSpec, hasAnyExceptionSpec, + ExArray, NumExs, Canonical); + Types.push_back(FTP); + FunctionProtoTypes.InsertNode(FTP, InsertPos); + return QualType(FTP, 0); +} + +/// getTypeDeclType - Return the unique reference to the type for the +/// specified type declaration. +QualType ASTContext::getTypeDeclType(TypeDecl *Decl, TypeDecl* PrevDecl) { + assert(Decl && "Passed null for Decl param"); + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (TypedefDecl *Typedef = dyn_cast<TypedefDecl>(Decl)) + return getTypedefType(Typedef); + else if (isa<TemplateTypeParmDecl>(Decl)) { + assert(false && "Template type parameter types are always available."); + } else if (ObjCInterfaceDecl *ObjCInterface = dyn_cast<ObjCInterfaceDecl>(Decl)) + return getObjCInterfaceType(ObjCInterface); + + if (RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { + if (PrevDecl) + Decl->TypeForDecl = PrevDecl->TypeForDecl; + else + Decl->TypeForDecl = new (*this,8) RecordType(Record); + } + else if (EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + if (PrevDecl) + Decl->TypeForDecl = PrevDecl->TypeForDecl; + else + Decl->TypeForDecl = new (*this,8) EnumType(Enum); + } + else + assert(false && "TypeDecl without a type?"); + + if (!PrevDecl) Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 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 = getCanonicalType(Decl->getUnderlyingType()); + Decl->TypeForDecl = new(*this,8) TypedefType(Type::Typedef, 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(const ObjCInterfaceDecl *Decl) { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + ObjCInterfaceDecl *OID = const_cast<ObjCInterfaceDecl*>(Decl); + Decl->TypeForDecl = new(*this,8) ObjCInterfaceType(Type::ObjCInterface, OID); + Types.push_back(Decl->TypeForDecl); + return QualType(Decl->TypeForDecl, 0); +} + +/// \brief Retrieve the template type parameter type for a template +/// parameter with the given depth, index, and (optionally) name. +QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, + IdentifierInfo *Name) { + llvm::FoldingSetNodeID ID; + TemplateTypeParmType::Profile(ID, Depth, Index, Name); + void *InsertPos = 0; + TemplateTypeParmType *TypeParm + = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (TypeParm) + return QualType(TypeParm, 0); + + if (Name) + TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index, Name, + getTemplateTypeParmType(Depth, Index)); + else + TypeParm = new (*this, 8) TemplateTypeParmType(Depth, Index); + + Types.push_back(TypeParm); + TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos); + + return QualType(TypeParm, 0); +} + +QualType +ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Canon) { + if (!Canon.isNull()) + Canon = getCanonicalType(Canon); + + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, Template, Args, NumArgs); + + void *InsertPos = 0; + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (Spec) + return QualType(Spec, 0); + + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + 8); + Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, Canon); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + + return QualType(Spec, 0); +} + +QualType +ASTContext::getQualifiedNameType(NestedNameSpecifier *NNS, + QualType NamedType) { + llvm::FoldingSetNodeID ID; + QualifiedNameType::Profile(ID, NNS, NamedType); + + void *InsertPos = 0; + QualifiedNameType *T + = QualifiedNameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + T = new (*this) QualifiedNameType(NNS, NamedType, + getCanonicalType(NamedType)); + Types.push_back(T); + QualifiedNameTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon) { + assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + + if (Canon.isNull()) { + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + if (CanonNNS != NNS) + Canon = getTypenameType(CanonNNS, Name); + } + + llvm::FoldingSetNodeID ID; + TypenameType::Profile(ID, NNS, Name); + + void *InsertPos = 0; + TypenameType *T + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + T = new (*this) TypenameType(NNS, Name, Canon); + Types.push_back(T); + TypenameTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType +ASTContext::getTypenameType(NestedNameSpecifier *NNS, + const TemplateSpecializationType *TemplateId, + QualType Canon) { + assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + + if (Canon.isNull()) { + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + QualType CanonType = getCanonicalType(QualType(TemplateId, 0)); + if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) { + const TemplateSpecializationType *CanonTemplateId + = CanonType->getAsTemplateSpecializationType(); + assert(CanonTemplateId && + "Canonical type must also be a template specialization type"); + Canon = getTypenameType(CanonNNS, CanonTemplateId); + } + } + + llvm::FoldingSetNodeID ID; + TypenameType::Profile(ID, NNS, TemplateId); + + void *InsertPos = 0; + TypenameType *T + = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + T = new (*this) TypenameType(NNS, TemplateId, Canon); + Types.push_back(T); + TypenameTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +/// CmpProtocolNames - Comparison predicate for sorting protocols +/// alphabetically. +static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, + const ObjCProtocolDecl *RHS) { + return LHS->getDeclName() < RHS->getDeclName(); +} + +static void SortAndUniqueProtocols(ObjCProtocolDecl **&Protocols, + unsigned &NumProtocols) { + ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; + + // Sort protocols, keyed by name. + std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames); + + // Remove duplicates. + ProtocolsEnd = std::unique(Protocols, ProtocolsEnd); + NumProtocols = ProtocolsEnd-Protocols; +} + + +/// getObjCQualifiedInterfaceType - Return a ObjCQualifiedInterfaceType type for +/// the given interface decl and the conforming protocol list. +QualType ASTContext::getObjCQualifiedInterfaceType(ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **Protocols, unsigned NumProtocols) { + // Sort the protocol list alphabetically to canonicalize it. + SortAndUniqueProtocols(Protocols, NumProtocols); + + llvm::FoldingSetNodeID ID; + ObjCQualifiedInterfaceType::Profile(ID, Decl, Protocols, NumProtocols); + + void *InsertPos = 0; + if (ObjCQualifiedInterfaceType *QT = + ObjCQualifiedInterfaceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // No Match; + ObjCQualifiedInterfaceType *QType = + new (*this,8) ObjCQualifiedInterfaceType(Decl, Protocols, NumProtocols); + + Types.push_back(QType); + ObjCQualifiedInterfaceTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getObjCQualifiedIdType - Return an ObjCQualifiedIdType for the 'id' decl +/// and the conforming protocol list. +QualType ASTContext::getObjCQualifiedIdType(ObjCProtocolDecl **Protocols, + unsigned NumProtocols) { + // Sort the protocol list alphabetically to canonicalize it. + SortAndUniqueProtocols(Protocols, 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; + ObjCQualifiedIdType *QType = + new (*this,8) ObjCQualifiedIdType(Protocols, NumProtocols); + Types.push_back(QType); + ObjCQualifiedIdTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getTypeOfExprType - Unlike many "get<Type>" functions, we can't unique +/// TypeOfExprType 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::getTypeOfExprType(Expr *tofExpr) { + QualType Canonical = getCanonicalType(tofExpr->getType()); + TypeOfExprType *toe = new (*this,8) TypeOfExprType(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 = getCanonicalType(tofType); + TypeOfType *tot = new (*this,8) 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); + return getTypeDeclType(Decl); +} + +/// 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 { + return getFromTargetType(Target.getSizeType()); +} + +/// getSignedWCharType - Return the type of "signed wchar_t". +/// Used when in C++, as a GCC extension. +QualType ASTContext::getSignedWCharType() const { + // FIXME: derive from "Target" ? + return WCharTy; +} + +/// getUnsignedWCharType - Return the type of "unsigned wchar_t". +/// Used when in C++, as a GCC extension. +QualType ASTContext::getUnsignedWCharType() const { + // FIXME: derive from "Target" ? + return UnsignedIntTy; +} + +/// 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 { + return getFromTargetType(Target.getPtrDiffType(0)); +} + +//===----------------------------------------------------------------------===// +// Type Operators +//===----------------------------------------------------------------------===// + +/// getCanonicalType - Return the canonical (structural) type corresponding to +/// the specified potentially non-canonical type. The non-canonical version +/// of a type may have many "decorated" versions of types. Decorators can +/// include typedefs, 'typeof' operators, etc. The returned type is guaranteed +/// to be free of any of these, allowing two canonical types to be compared +/// for exact equality with a simple pointer comparison. +QualType ASTContext::getCanonicalType(QualType T) { + QualType CanType = T.getTypePtr()->getCanonicalTypeInternal(); + + // If the result has type qualifiers, make sure to canonicalize them as well. + unsigned TypeQuals = T.getCVRQualifiers() | CanType.getCVRQualifiers(); + if (TypeQuals == 0) return CanType; + + // If the type qualifiers are on an array type, get the canonical type of the + // array with the qualifiers applied to the element type. + ArrayType *AT = dyn_cast<ArrayType>(CanType); + if (!AT) + return CanType.getQualifiedType(TypeQuals); + + // Get the canonical version of the element with the extra qualifiers on it. + // This can recursively sink qualifiers through multiple levels of arrays. + QualType NewEltTy=AT->getElementType().getWithAdditionalQualifiers(TypeQuals); + NewEltTy = getCanonicalType(NewEltTy); + + if (ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + return getConstantArrayType(NewEltTy, CAT->getSize(),CAT->getSizeModifier(), + CAT->getIndexTypeQualifier()); + if (IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) + return getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), + IAT->getIndexTypeQualifier()); + + if (DependentSizedArrayType *DSAT = dyn_cast<DependentSizedArrayType>(AT)) + return getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), + DSAT->getSizeModifier(), + DSAT->getIndexTypeQualifier()); + + VariableArrayType *VAT = cast<VariableArrayType>(AT); + return getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeQualifier()); +} + +Decl *ASTContext::getCanonicalDecl(Decl *D) { + if (!D) + return 0; + + if (TagDecl *Tag = dyn_cast<TagDecl>(D)) { + QualType T = getTagDeclType(Tag); + return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType) + ->getDecl()); + } + + if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) { + while (Template->getPreviousDeclaration()) + Template = Template->getPreviousDeclaration(); + return Template; + } + + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + while (Function->getPreviousDeclaration()) + Function = Function->getPreviousDeclaration(); + return const_cast<FunctionDecl *>(Function); + } + + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + while (Var->getPreviousDeclaration()) + Var = Var->getPreviousDeclaration(); + return const_cast<VarDecl *>(Var); + } + + return D; +} + +TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { + // If this template name refers to a template, the canonical + // template name merely stores the template itself. + if (TemplateDecl *Template = Name.getAsTemplateDecl()) + return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template))); + + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + assert(DTN && "Non-dependent template names must refer to template decls."); + return DTN->CanonicalTemplateName; +} + +NestedNameSpecifier * +ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { + if (!NNS) + return 0; + + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + // Canonicalize the prefix but keep the identifier the same. + return NestedNameSpecifier::Create(*this, + getCanonicalNestedNameSpecifier(NNS->getPrefix()), + NNS->getAsIdentifier()); + + case NestedNameSpecifier::Namespace: + // A namespace is canonical; build a nested-name-specifier with + // this namespace and no prefix. + return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace()); + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); + NestedNameSpecifier *Prefix = 0; + + // FIXME: This isn't the right check! + if (T->isDependentType()) + Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix()); + + return NestedNameSpecifier::Create(*this, Prefix, + NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, + T.getTypePtr()); + } + + case NestedNameSpecifier::Global: + // The global specifier is canonical and unique. + return NNS; + } + + // Required to silence a GCC warning + return 0; +} + + +const ArrayType *ASTContext::getAsArrayType(QualType T) { + // Handle the non-qualified case efficiently. + if (T.getCVRQualifiers() == 0) { + // Handle the common positive case fast. + if (const ArrayType *AT = dyn_cast<ArrayType>(T)) + return AT; + } + + // Handle the common negative case fast, ignoring CVR qualifiers. + QualType CType = T->getCanonicalTypeInternal(); + + // Make sure to look through type qualifiers (like ExtQuals) for the negative + // test. + if (!isa<ArrayType>(CType) && + !isa<ArrayType>(CType.getUnqualifiedType())) + return 0; + + // Apply any CVR qualifiers from the array type to the element type. This + // implements C99 6.7.3p8: "If the specification of an array type includes + // any type qualifiers, the element type is so qualified, not the array type." + + // If we get here, we either have type qualifiers on the type, or we have + // sugar such as a typedef in the way. If we have type qualifiers on the type + // we must propagate them down into the elemeng type. + unsigned CVRQuals = T.getCVRQualifiers(); + unsigned AddrSpace = 0; + Type *Ty = T.getTypePtr(); + + // Rip through ExtQualType's and typedefs to get to a concrete type. + while (1) { + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(Ty)) { + AddrSpace = EXTQT->getAddressSpace(); + Ty = EXTQT->getBaseType(); + } else { + T = Ty->getDesugaredType(); + if (T.getTypePtr() == Ty && T.getCVRQualifiers() == 0) + break; + CVRQuals |= T.getCVRQualifiers(); + Ty = T.getTypePtr(); + } + } + + // If we have a simple case, just return now. + const ArrayType *ATy = dyn_cast<ArrayType>(Ty); + if (ATy == 0 || (AddrSpace == 0 && CVRQuals == 0)) + return ATy; + + // Otherwise, we have an array and we have qualifiers on it. Push the + // qualifiers into the array element type and return a new array type. + // Get the canonical version of the element with the extra qualifiers on it. + // This can recursively sink qualifiers through multiple levels of arrays. + QualType NewEltTy = ATy->getElementType(); + if (AddrSpace) + NewEltTy = getAddrSpaceQualType(NewEltTy, AddrSpace); + NewEltTy = NewEltTy.getWithAdditionalQualifiers(CVRQuals); + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) + return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), + CAT->getSizeModifier(), + CAT->getIndexTypeQualifier())); + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy)) + return cast<ArrayType>(getIncompleteArrayType(NewEltTy, + IAT->getSizeModifier(), + IAT->getIndexTypeQualifier())); + + if (const DependentSizedArrayType *DSAT + = dyn_cast<DependentSizedArrayType>(ATy)) + return cast<ArrayType>( + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr(), + DSAT->getSizeModifier(), + DSAT->getIndexTypeQualifier())); + + const VariableArrayType *VAT = cast<VariableArrayType>(ATy); + return cast<ArrayType>(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeQualifier())); +} + + +/// getArrayDecayedType - Return the properly qualified result of decaying the +/// specified array type to a pointer. This operation is non-trivial when +/// handling typedefs etc. The canonical type of "T" must be an array type, +/// this returns a pointer to a properly qualified element of the array. +/// +/// See C99 6.7.5.3p7 and C99 6.3.2.1p3. +QualType ASTContext::getArrayDecayedType(QualType Ty) { + // Get the element type with 'getAsArrayType' so that we don't lose any + // typedefs in the element type of the array. This also handles propagation + // of type qualifiers from the array type into the element type if present + // (C99 6.7.3p8). + const ArrayType *PrettyArrayType = getAsArrayType(Ty); + assert(PrettyArrayType && "Not an array type!"); + + QualType PtrTy = getPointerType(PrettyArrayType->getElementType()); + + // int x[restrict 4] -> int *restrict + return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); +} + +QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) { + QualType ElemTy = VAT->getElementType(); + + if (const VariableArrayType *VAT = getAsVariableArrayType(ElemTy)) + return getBaseElementType(VAT); + + return ElemTy; +} + +/// 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 FloatingRank getFloatingRank(QualType T) { + if (const ComplexType *CT = T->getAsComplexType()) + return getFloatingRank(CT->getElementType()); + + assert(T->getAsBuiltinType() && "getFloatingRank(): not a floating type"); + 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 Size, + QualType Domain) const { + FloatingRank EltRank = getFloatingRank(Size); + if (Domain->isComplexType()) { + switch (EltRank) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatComplexTy; + case DoubleRank: return DoubleComplexTy; + case LongDoubleRank: return LongDoubleComplexTy; + } + } + + assert(Domain->isRealFloatingType() && "Unknown domain!"); + switch (EltRank) { + default: assert(0 && "getFloatingRank(): illegal value for rank"); + case FloatRank: return FloatTy; + case DoubleRank: return DoubleTy; + case LongDoubleRank: return LongDoubleTy; + } +} + +/// getFloatingTypeOrder - Compare the rank of the two specified floating +/// point types, ignoring the domain of the type (i.e. 'double' == +/// '_Complex double'). If LHS > RHS, return 1. If LHS == RHS, return 0. If +/// LHS < RHS, return -1. +int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) { + FloatingRank LHSR = getFloatingRank(LHS); + FloatingRank RHSR = getFloatingRank(RHS); + + if (LHSR == RHSR) + return 0; + if (LHSR > RHSR) + return 1; + return -1; +} + +/// 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, +/// or if it is not canonicalized. +unsigned ASTContext::getIntegerRank(Type *T) { + assert(T->isCanonical() && "T should be canonicalized"); + if (EnumType* ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType().getTypePtr(); + + // There are two things which impact the integer rank: the width, and + // the ordering of builtins. The builtin ordering is encoded in the + // bottom three bits; the width is encoded in the bits above that. + if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + return FWIT->getWidth() << 3; + } + + switch (cast<BuiltinType>(T)->getKind()) { + default: assert(0 && "getIntegerRank(): not a built-in integer"); + case BuiltinType::Bool: + return 1 + (getIntWidth(BoolTy) << 3); + case BuiltinType::Char_S: + case BuiltinType::Char_U: + case BuiltinType::SChar: + case BuiltinType::UChar: + return 2 + (getIntWidth(CharTy) << 3); + case BuiltinType::Short: + case BuiltinType::UShort: + return 3 + (getIntWidth(ShortTy) << 3); + case BuiltinType::Int: + case BuiltinType::UInt: + return 4 + (getIntWidth(IntTy) << 3); + case BuiltinType::Long: + case BuiltinType::ULong: + return 5 + (getIntWidth(LongTy) << 3); + case BuiltinType::LongLong: + case BuiltinType::ULongLong: + return 6 + (getIntWidth(LongLongTy) << 3); + case BuiltinType::Int128: + case BuiltinType::UInt128: + return 7 + (getIntWidth(Int128Ty) << 3); + } +} + +/// getIntegerTypeOrder - Returns the highest ranked integer type: +/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If +/// LHS < RHS, return -1. +int ASTContext::getIntegerTypeOrder(QualType LHS, QualType RHS) { + Type *LHSC = getCanonicalType(LHS).getTypePtr(); + Type *RHSC = getCanonicalType(RHS).getTypePtr(); + if (LHSC == RHSC) return 0; + + bool LHSUnsigned = LHSC->isUnsignedIntegerType(); + bool RHSUnsigned = RHSC->isUnsignedIntegerType(); + + unsigned LHSRank = getIntegerRank(LHSC); + unsigned RHSRank = getIntegerRank(RHSC); + + if (LHSUnsigned == RHSUnsigned) { // Both signed or both unsigned. + if (LHSRank == RHSRank) return 0; + return LHSRank > RHSRank ? 1 : -1; + } + + // Otherwise, the LHS is signed and the RHS is unsigned or visa versa. + if (LHSUnsigned) { + // If the unsigned [LHS] type is larger, return it. + if (LHSRank >= RHSRank) + return 1; + + // If the signed type can represent all values of the unsigned type, it + // wins. Because we are dealing with 2's complement and types that are + // powers of two larger than each other, this is always safe. + return -1; + } + + // If the unsigned [RHS] type is larger, return it. + if (RHSRank >= LHSRank) + return -1; + + // If the signed type can represent all values of the unsigned type, it + // wins. Because we are dealing with 2's complement and types that are + // powers of two larger than each other, this is always safe. + return 1; +} + +// getCFConstantStringType - Return the type used for constant CFStrings. +QualType ASTContext::getCFConstantStringType() { + if (!CFConstantStringTypeDecl) { + CFConstantStringTypeDecl = + RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("NSConstantString")); + 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 + for (unsigned i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*BitWidth=*/0, + /*Mutable=*/false); + CFConstantStringTypeDecl->addDecl(*this, Field); + } + + CFConstantStringTypeDecl->completeDefinition(*this); + } + + return getTagDeclType(CFConstantStringTypeDecl); +} + +void ASTContext::setCFConstantStringType(QualType T) { + const RecordType *Rec = T->getAsRecordType(); + assert(Rec && "Invalid CFConstantStringType"); + CFConstantStringTypeDecl = Rec->getDecl(); +} + +QualType ASTContext::getObjCFastEnumerationStateType() +{ + if (!ObjCFastEnumerationStateTypeDecl) { + ObjCFastEnumerationStateTypeDecl = + RecordDecl::Create(*this, TagDecl::TK_struct, TUDecl, SourceLocation(), + &Idents.get("__objcFastEnumerationState")); + + QualType FieldTypes[] = { + UnsignedLongTy, + getPointerType(ObjCIdType), + getPointerType(UnsignedLongTy), + getConstantArrayType(UnsignedLongTy, + llvm::APInt(32, 5), ArrayType::Normal, 0) + }; + + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, + ObjCFastEnumerationStateTypeDecl, + SourceLocation(), 0, + FieldTypes[i], /*BitWidth=*/0, + /*Mutable=*/false); + ObjCFastEnumerationStateTypeDecl->addDecl(*this, Field); + } + + ObjCFastEnumerationStateTypeDecl->completeDefinition(*this); + } + + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); +} + +void ASTContext::setObjCFastEnumerationStateType(QualType T) { + const RecordType *Rec = T->getAsRecordType(); + assert(Rec && "Invalid ObjCFAstEnumerationStateType"); + ObjCFastEnumerationStateTypeDecl = Rec->getDecl(); +} + +// 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)) + if (IdentifierInfo *II = TT->getDecl()->getIdentifier()) + return II->isStr("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(const ObjCMethodDecl *Decl, + std::string& S) { + // FIXME: This is not very efficient. + // Encode type qualifer, 'in', 'inout', etc. for the return type. + getObjCEncodingForTypeQualifier(Decl->getObjCDeclQualifier(), S); + // Encode result type. + getObjCEncodingForType(Decl->getResultType(), S); + // 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; + for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + QualType PType = (*PI)->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 (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + ParmVarDecl *PVDecl = *PI; + QualType PType = PVDecl->getOriginalType(); + if (const ArrayType *AT = + dyn_cast<ArrayType>(PType->getCanonicalTypeInternal())) { + // Use array's original type only if it has known number of + // elements. + if (!isa<ConstantArrayType>(AT)) + PType = PVDecl->getType(); + } else if (PType->isFunctionType()) + PType = PVDecl->getType(); + // Process argument qualifiers for user supplied arguments; such as, + // 'in', 'inout', etc. + getObjCEncodingForTypeQualifier(PVDecl->getObjCDeclQualifier(), S); + getObjCEncodingForType(PType, S); + S += llvm::utostr(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } +} + +/// getObjCEncodingForPropertyDecl - Return the encoded type for this +/// property declaration. If non-NULL, Container must be either an +/// ObjCCategoryImplDecl or ObjCImplementationDecl; it should only be +/// NULL when getting encodings for protocol properties. +/// Property attributes are stored as a comma-delimited C string. The simple +/// attributes readonly and bycopy are encoded as single characters. The +/// parametrized attributes, getter=name, setter=name, and ivar=name, are +/// encoded as single characters, followed by an identifier. Property types +/// are also encoded as a parametrized attribute. The characters used to encode +/// these attributes are defined by the following enumeration: +/// @code +/// enum PropertyAttributes { +/// kPropertyReadOnly = 'R', // property is read-only. +/// kPropertyBycopy = 'C', // property is a copy of the value last assigned +/// kPropertyByref = '&', // property is a reference to the value last assigned +/// kPropertyDynamic = 'D', // property is dynamic +/// kPropertyGetter = 'G', // followed by getter selector name +/// kPropertySetter = 'S', // followed by setter selector name +/// kPropertyInstanceVariable = 'V' // followed by instance variable name +/// kPropertyType = 't' // followed by old-style type encoding. +/// kPropertyWeak = 'W' // 'weak' property +/// kPropertyStrong = 'P' // property GC'able +/// kPropertyNonAtomic = 'N' // property non-atomic +/// }; +/// @endcode +void ASTContext::getObjCEncodingForPropertyDecl(const ObjCPropertyDecl *PD, + const Decl *Container, + std::string& S) { + // Collect information from the property implementation decl(s). + bool Dynamic = false; + ObjCPropertyImplDecl *SynthesizePID = 0; + + // FIXME: Duplicated code due to poor abstraction. + if (Container) { + if (const ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(Container)) { + for (ObjCCategoryImplDecl::propimpl_iterator + i = CID->propimpl_begin(*this), e = CID->propimpl_end(*this); + i != e; ++i) { + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyDecl() == PD) { + if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) { + Dynamic = true; + } else { + SynthesizePID = PID; + } + } + } + } else { + const ObjCImplementationDecl *OID=cast<ObjCImplementationDecl>(Container); + for (ObjCCategoryImplDecl::propimpl_iterator + i = OID->propimpl_begin(*this), e = OID->propimpl_end(*this); + i != e; ++i) { + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyDecl() == PD) { + if (PID->getPropertyImplementation()==ObjCPropertyImplDecl::Dynamic) { + Dynamic = true; + } else { + SynthesizePID = PID; + } + } + } + } + } + + // FIXME: This is not very efficient. + S = "T"; + + // Encode result type. + // GCC has some special rules regarding encoding of properties which + // closely resembles encoding of ivars. + getObjCEncodingForTypeImpl(PD->getType(), S, true, true, 0, + true /* outermost type */, + true /* encoding for property */); + + if (PD->isReadOnly()) { + S += ",R"; + } else { + switch (PD->getSetterKind()) { + case ObjCPropertyDecl::Assign: break; + case ObjCPropertyDecl::Copy: S += ",C"; break; + case ObjCPropertyDecl::Retain: S += ",&"; break; + } + } + + // It really isn't clear at all what this means, since properties + // are "dynamic by default". + if (Dynamic) + S += ",D"; + + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) + S += ",N"; + + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { + S += ",G"; + S += PD->getGetterName().getAsString(); + } + + if (PD->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { + S += ",S"; + S += PD->getSetterName().getAsString(); + } + + if (SynthesizePID) { + const ObjCIvarDecl *OID = SynthesizePID->getPropertyIvarDecl(); + S += ",V"; + S += OID->getNameAsString(); + } + + // FIXME: OBJCGC: weak & strong +} + +/// getLegacyIntegralTypeEncoding - +/// Another legacy compatibility encoding: 32-bit longs are encoded as +/// 'l' or 'L' , but not always. For typedefs, we need to use +/// 'i' or 'I' instead if encoding a struct field, or a pointer! +/// +void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { + if (dyn_cast<TypedefType>(PointeeTy.getTypePtr())) { + if (const BuiltinType *BT = PointeeTy->getAsBuiltinType()) { + if (BT->getKind() == BuiltinType::ULong && + ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) + PointeeTy = UnsignedIntTy; + else + if (BT->getKind() == BuiltinType::Long && + ((const_cast<ASTContext *>(this))->getIntWidth(PointeeTy) == 32)) + PointeeTy = IntTy; + } + } +} + +void ASTContext::getObjCEncodingForType(QualType T, std::string& S, + const FieldDecl *Field) { + // We follow the behavior of gcc, expanding structures which are + // directly pointed to, and expanding embedded structures. Note that + // these rules are sufficient to prevent recursive encoding of the + // same type. + getObjCEncodingForTypeImpl(T, S, true, true, Field, + true /* outermost type */); +} + +static void EncodeBitField(const ASTContext *Context, std::string& S, + const FieldDecl *FD) { + const Expr *E = FD->getBitWidth(); + assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); + ASTContext *Ctx = const_cast<ASTContext*>(Context); + unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue(); + S += 'b'; + S += llvm::utostr(N); +} + +void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, + bool ExpandPointedToStructures, + bool ExpandStructures, + const FieldDecl *FD, + bool OutermostType, + bool EncodingProperty) { + if (const BuiltinType *BT = T->getAsBuiltinType()) { + if (FD && FD->isBitField()) { + EncodeBitField(this, S, FD); + } + else { + char encoding; + switch (BT->getKind()) { + default: assert(0 && "Unhandled builtin type kind"); + case BuiltinType::Void: encoding = 'v'; break; + case BuiltinType::Bool: encoding = 'B'; break; + case BuiltinType::Char_U: + case BuiltinType::UChar: encoding = 'C'; break; + case BuiltinType::UShort: encoding = 'S'; break; + case BuiltinType::UInt: encoding = 'I'; break; + case BuiltinType::ULong: + encoding = + (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'L' : 'Q'; + break; + case BuiltinType::UInt128: encoding = 'T'; 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 = + (const_cast<ASTContext *>(this))->getIntWidth(T) == 32 ? 'l' : 'q'; + break; + case BuiltinType::LongLong: encoding = 'q'; break; + case BuiltinType::Int128: encoding = 't'; break; + case BuiltinType::Float: encoding = 'f'; break; + case BuiltinType::Double: encoding = 'd'; break; + case BuiltinType::LongDouble: encoding = 'd'; break; + } + + S += encoding; + } + } else if (const ComplexType *CT = T->getAsComplexType()) { + S += 'j'; + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, + false); + } else if (T->isObjCQualifiedIdType()) { + getObjCEncodingForTypeImpl(getObjCIdType(), S, + ExpandPointedToStructures, + ExpandStructures, FD); + if (FD || EncodingProperty) { + // Note that we do extended encoding of protocol qualifer list + // Only when doing ivar or property encoding. + const ObjCQualifiedIdType *QIDT = T->getAsObjCQualifiedIdType(); + S += '"'; + for (ObjCQualifiedIdType::qual_iterator I = QIDT->qual_begin(), + E = QIDT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + else if (const PointerType *PT = T->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + bool isReadOnly = false; + // For historical/compatibility reasons, the read-only qualifier of the + // pointee gets emitted _before_ the '^'. The read-only qualifier of + // the pointer itself gets ignored, _unless_ we are looking at a typedef! + // Also, do not emit the 'r' for anything but the outermost type! + if (dyn_cast<TypedefType>(T.getTypePtr())) { + if (OutermostType && T.isConstQualified()) { + isReadOnly = true; + S += 'r'; + } + } + else if (OutermostType) { + QualType P = PointeeTy; + while (P->getAsPointerType()) + P = P->getAsPointerType()->getPointeeType(); + if (P.isConstQualified()) { + isReadOnly = true; + S += 'r'; + } + } + if (isReadOnly) { + // Another legacy compatibility encoding. Some ObjC qualifier and type + // combinations need to be rearranged. + // Rewrite "in const" from "nr" to "rn" + const char * s = S.c_str(); + int len = S.length(); + if (len >= 2 && s[len-2] == 'n' && s[len-1] == 'r') { + std::string replace = "rn"; + S.replace(S.end()-2, S.end(), replace); + } + } + if (isObjCIdStructType(PointeeTy)) { + S += '@'; + return; + } + else if (PointeeTy->isObjCInterfaceType()) { + if (!EncodingProperty && + isa<TypedefType>(PointeeTy.getTypePtr())) { + // Another historical/compatibility reason. + // We encode the underlying type which comes out as + // {...}; + S += '^'; + getObjCEncodingForTypeImpl(PointeeTy, S, + false, ExpandPointedToStructures, + NULL); + return; + } + S += '@'; + if (FD || EncodingProperty) { + const ObjCInterfaceType *OIT = + PointeeTy.getUnqualifiedType()->getAsObjCInterfaceType(); + ObjCInterfaceDecl *OI = OIT->getDecl(); + S += '"'; + S += OI->getNameAsCString(); + for (ObjCInterfaceType::qual_iterator I = OIT->qual_begin(), + E = OIT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } else if (isObjCClassStructType(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 += '^'; + getLegacyIntegralTypeEncoding(PointeeTy); + + getObjCEncodingForTypeImpl(PointeeTy, S, + false, ExpandPointedToStructures, + NULL); + } else if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { + if (isa<IncompleteArrayType>(AT)) { + // Incomplete arrays are encoded as a pointer to the array element. + S += '^'; + + getObjCEncodingForTypeImpl(AT->getElementType(), S, + false, ExpandStructures, FD); + } else { + S += '['; + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) + S += llvm::utostr(CAT->getSize().getZExtValue()); + else { + //Variable length arrays are encoded as a regular array with 0 elements. + assert(isa<VariableArrayType>(AT) && "Unknown array type!"); + S += '0'; + } + + getObjCEncodingForTypeImpl(AT->getElementType(), S, + false, ExpandStructures, FD); + S += ']'; + } + } else if (T->getAsFunctionType()) { + S += '?'; + } else if (const RecordType *RTy = T->getAsRecordType()) { + RecordDecl *RDecl = RTy->getDecl(); + S += RDecl->isUnion() ? '(' : '{'; + // Anonymous structures print as '?' + if (const IdentifierInfo *II = RDecl->getIdentifier()) { + S += II->getName(); + } else { + S += '?'; + } + if (ExpandStructures) { + S += '='; + for (RecordDecl::field_iterator Field = RDecl->field_begin(*this), + FieldEnd = RDecl->field_end(*this); + Field != FieldEnd; ++Field) { + if (FD) { + S += '"'; + S += Field->getNameAsString(); + S += '"'; + } + + // Special case bit-fields. + if (Field->isBitField()) { + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, + (*Field)); + } else { + QualType qt = Field->getType(); + getLegacyIntegralTypeEncoding(qt); + getObjCEncodingForTypeImpl(qt, S, false, true, + FD); + } + } + } + S += RDecl->isUnion() ? ')' : '}'; + } else if (T->isEnumeralType()) { + if (FD && FD->isBitField()) + EncodeBitField(this, S, FD); + else + S += 'i'; + } else if (T->isBlockPointerType()) { + S += "@?"; // Unlike a pointer-to-function, which is "^?". + } else if (T->isObjCInterfaceType()) { + // @encode(class_name) + ObjCInterfaceDecl *OI = T->getAsObjCInterfaceType()->getDecl(); + S += '{'; + const IdentifierInfo *II = OI->getIdentifier(); + S += II->getName(); + S += '='; + llvm::SmallVector<FieldDecl*, 32> RecFields; + CollectObjCIvars(OI, RecFields); + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + if (RecFields[i]->isBitField()) + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + RecFields[i]); + else + getObjCEncodingForTypeImpl(RecFields[i]->getType(), S, false, true, + FD); + } + S += '}'; + } + else + assert(0 && "@encode for type not implemented!"); +} + +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(QualType T) +{ + ObjCIdType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + + TypedefDecl *TD = TT->getDecl(); + + // typedef struct objc_object *id; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + // User error - caller will issue diagnostics. + if (!ptr) + return; + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + // User error - caller will issue diagnostics. + if (!rec) + return; + IdStructType = rec; +} + +void ASTContext::setObjCSelType(QualType T) +{ + ObjCSelType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + TypedefDecl *TD = TT->getDecl(); + + // typedef struct objc_selector *SEL; + const PointerType *ptr = TD->getUnderlyingType()->getAsPointerType(); + if (!ptr) + return; + const RecordType *rec = ptr->getPointeeType()->getAsStructureType(); + if (!rec) + return; + SelStructType = rec; +} + +void ASTContext::setObjCProtoType(QualType QT) +{ + ObjCProtoType = QT; +} + +void ASTContext::setObjCClassType(QualType T) +{ + ObjCClassType = T; + + const TypedefType *TT = T->getAsTypedefType(); + if (!TT) + return; + TypedefDecl *TD = TT->getDecl(); + + // 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); +} + +/// \brief Retrieve the template name that represents a qualified +/// template name such as \c std::vector. +TemplateName ASTContext::getQualifiedTemplateName(NestedNameSpecifier *NNS, + bool TemplateKeyword, + TemplateDecl *Template) { + llvm::FoldingSetNodeID ID; + QualifiedTemplateName::Profile(ID, NNS, TemplateKeyword, Template); + + void *InsertPos = 0; + QualifiedTemplateName *QTN = + QualifiedTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + if (!QTN) { + QTN = new (*this,4) QualifiedTemplateName(NNS, TemplateKeyword, Template); + QualifiedTemplateNames.InsertNode(QTN, InsertPos); + } + + return TemplateName(QTN); +} + +/// \brief Retrieve the template name that represents a dependent +/// template name such as \c MetaFun::template apply. +TemplateName ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + const IdentifierInfo *Name) { + assert(NNS->isDependent() && "Nested name specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateName::Profile(ID, NNS, Name); + + void *InsertPos = 0; + DependentTemplateName *QTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + + if (QTN) + return TemplateName(QTN); + + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + if (CanonNNS == NNS) { + QTN = new (*this,4) DependentTemplateName(NNS, Name); + } else { + TemplateName Canon = getDependentTemplateName(CanonNNS, Name); + QTN = new (*this,4) DependentTemplateName(NNS, Name, Canon); + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + +/// getFromTargetType - Given one of the integer types provided by +/// TargetInfo, produce the corresponding type. The unsigned @p Type +/// is actually a value of type @c TargetInfo::IntType. +QualType ASTContext::getFromTargetType(unsigned Type) const { + switch (Type) { + case TargetInfo::NoInt: return QualType(); + case TargetInfo::SignedShort: return ShortTy; + case TargetInfo::UnsignedShort: return UnsignedShortTy; + case TargetInfo::SignedInt: return IntTy; + case TargetInfo::UnsignedInt: return UnsignedIntTy; + case TargetInfo::SignedLong: return LongTy; + case TargetInfo::UnsignedLong: return UnsignedLongTy; + case TargetInfo::SignedLongLong: return LongLongTy; + case TargetInfo::UnsignedLongLong: return UnsignedLongLongTy; + } + + assert(false && "Unhandled TargetInfo::IntType value"); + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Type Predicates. +//===----------------------------------------------------------------------===// + +/// isObjCNSObjectType - Return true if this is an NSObject object using +/// NSObject attribute on a c-style pointer type. +/// FIXME - Make it work directly on types. +/// +bool ASTContext::isObjCNSObjectType(QualType Ty) const { + if (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { + if (TypedefDecl *TD = TDT->getDecl()) + if (TD->getAttr<ObjCNSObjectAttr>()) + return true; + } + return false; +} + +/// isObjCObjectPointerType - Returns true if type is an Objective-C pointer +/// to an object type. This includes "id" and "Class" (two 'special' pointers +/// to struct), Interface* (pointer to ObjCInterfaceType) and id<P> (qualified +/// ID type). +bool ASTContext::isObjCObjectPointerType(QualType Ty) const { + if (Ty->isObjCQualifiedIdType()) + return true; + + // Blocks are objects. + if (Ty->isBlockPointerType()) + return true; + + // All other object types are pointers. + const PointerType *PT = Ty->getAsPointerType(); + if (PT == 0) + return false; + + // If this a pointer to an interface (e.g. NSString*), it is ok. + if (PT->getPointeeType()->isObjCInterfaceType() || + // If is has NSObject attribute, OK as well. + isObjCNSObjectType(Ty)) + return true; + + // Check to see if this is 'id' or 'Class', both of which are typedefs for + // pointer types. This looks for the typedef specifically, not for the + // underlying type. Iteratively strip off typedefs so that we can handle + // typedefs of typedefs. + while (TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { + if (Ty.getUnqualifiedType() == getObjCIdType() || + Ty.getUnqualifiedType() == getObjCClassType()) + return true; + + Ty = TDT->getDecl()->getUnderlyingType(); + } + + return false; +} + +/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's +/// garbage collection attribute. +/// +QualType::GCAttrTypes ASTContext::getObjCGCAttrKind(const QualType &Ty) const { + QualType::GCAttrTypes GCAttrs = QualType::GCNone; + if (getLangOptions().ObjC1 && + getLangOptions().getGCMode() != LangOptions::NonGC) { + GCAttrs = Ty.getObjCGCAttr(); + // Default behavious under objective-c's gc is for objective-c pointers + // (or pointers to them) be treated as though they were declared + // as __strong. + if (GCAttrs == QualType::GCNone) { + if (isObjCObjectPointerType(Ty)) + GCAttrs = QualType::Strong; + else if (Ty->isPointerType()) + return getObjCGCAttrKind(Ty->getAsPointerType()->getPointeeType()); + } + // Non-pointers have none gc'able attribute regardless of the attribute + // set on them. + else if (!isObjCObjectPointerType(Ty) && !Ty->isPointerType()) + return QualType::GCNone; + } + return GCAttrs; +} + +//===----------------------------------------------------------------------===// +// Type Compatibility Testing +//===----------------------------------------------------------------------===// + +/// typesAreBlockCompatible - This routine is called when comparing two +/// block types. Types must be strictly compatible here. For example, +/// C unfortunately doesn't produce an error for the following: +/// +/// int (*emptyArgFunc)(); +/// int (*intArgList)(int) = emptyArgFunc; +/// +/// For blocks, we will produce an error for the following (similar to C++): +/// +/// int (^emptyArgBlock)(); +/// int (^intArgBlock)(int) = emptyArgBlock; +/// +/// FIXME: When the dust settles on this integration, fold this into mergeTypes. +/// +bool ASTContext::typesAreBlockCompatible(QualType lhs, QualType rhs) { + const FunctionType *lbase = lhs->getAsFunctionType(); + const FunctionType *rbase = rhs->getAsFunctionType(); + const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); + const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase); + if (lproto && rproto == 0) + return false; + return !mergeTypes(lhs, rhs).isNull(); +} + +/// areCompatVectorTypes - Return true if the two specified vector types are +/// compatible. +static bool areCompatVectorTypes(const VectorType *LHS, + const VectorType *RHS) { + assert(LHS->isCanonical() && RHS->isCanonical()); + return LHS->getElementType() == RHS->getElementType() && + LHS->getNumElements() == RHS->getNumElements(); +} + +/// canAssignObjCInterfaces - Return true if the two interface types are +/// compatible for assignment from RHS to LHS. This handles validation of any +/// protocol qualifiers on the LHS or RHS. +/// +bool ASTContext::canAssignObjCInterfaces(const ObjCInterfaceType *LHS, + const ObjCInterfaceType *RHS) { + // Verify that the base decls are compatible: the RHS must be a subclass of + // the LHS. + if (!LHS->getDecl()->isSuperClassOf(RHS->getDecl())) + return false; + + // RHS must have a superset of the protocols in the LHS. If the LHS is not + // protocol qualified at all, then we are good. + if (!isa<ObjCQualifiedInterfaceType>(LHS)) + return true; + + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, then it + // isn't a superset. + if (!isa<ObjCQualifiedInterfaceType>(RHS)) + return true; // FIXME: should return false! + + // Finally, we must have two protocol-qualified interfaces. + const ObjCQualifiedInterfaceType *LHSP =cast<ObjCQualifiedInterfaceType>(LHS); + const ObjCQualifiedInterfaceType *RHSP =cast<ObjCQualifiedInterfaceType>(RHS); + + // All LHS protocols must have a presence on the RHS. + assert(LHSP->qual_begin() != LHSP->qual_end() && "Empty LHS protocol list?"); + + for (ObjCQualifiedInterfaceType::qual_iterator LHSPI = LHSP->qual_begin(), + LHSPE = LHSP->qual_end(); + LHSPI != LHSPE; LHSPI++) { + bool RHSImplementsProtocol = false; + + // If the RHS doesn't implement the protocol on the left, the types + // are incompatible. + for (ObjCQualifiedInterfaceType::qual_iterator RHSPI = RHSP->qual_begin(), + RHSPE = RHSP->qual_end(); + !RHSImplementsProtocol && (RHSPI != RHSPE); RHSPI++) { + if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) + RHSImplementsProtocol = true; + } + // FIXME: For better diagnostics, consider passing back the protocol name. + if (!RHSImplementsProtocol) + return false; + } + // The RHS implements all protocols listed on the LHS. + return true; +} + +bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { + // get the "pointed to" types + const PointerType *LHSPT = LHS->getAsPointerType(); + const PointerType *RHSPT = RHS->getAsPointerType(); + + if (!LHSPT || !RHSPT) + return false; + + QualType lhptee = LHSPT->getPointeeType(); + QualType rhptee = RHSPT->getPointeeType(); + const ObjCInterfaceType* LHSIface = lhptee->getAsObjCInterfaceType(); + const ObjCInterfaceType* RHSIface = rhptee->getAsObjCInterfaceType(); + // ID acts sort of like void* for ObjC interfaces + if (LHSIface && isObjCIdStructType(rhptee)) + return true; + if (RHSIface && isObjCIdStructType(lhptee)) + return true; + if (!LHSIface || !RHSIface) + return false; + return canAssignObjCInterfaces(LHSIface, RHSIface) || + canAssignObjCInterfaces(RHSIface, LHSIface); +} + +/// 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) { + return !mergeTypes(LHS, RHS).isNull(); +} + +QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs) { + const FunctionType *lbase = lhs->getAsFunctionType(); + const FunctionType *rbase = rhs->getAsFunctionType(); + const FunctionProtoType *lproto = dyn_cast<FunctionProtoType>(lbase); + const FunctionProtoType *rproto = dyn_cast<FunctionProtoType>(rbase); + bool allLTypes = true; + bool allRTypes = true; + + // Check return type + QualType retType = mergeTypes(lbase->getResultType(), rbase->getResultType()); + if (retType.isNull()) return QualType(); + if (getCanonicalType(retType) != getCanonicalType(lbase->getResultType())) + allLTypes = false; + if (getCanonicalType(retType) != getCanonicalType(rbase->getResultType())) + allRTypes = false; + + if (lproto && rproto) { // two C99 style function prototypes + assert(!lproto->hasExceptionSpec() && !rproto->hasExceptionSpec() && + "C++ shouldn't be here"); + unsigned lproto_nargs = lproto->getNumArgs(); + unsigned rproto_nargs = rproto->getNumArgs(); + + // Compatible functions must have the same number of arguments + if (lproto_nargs != rproto_nargs) + return QualType(); + + // Variadic and non-variadic functions aren't compatible + if (lproto->isVariadic() != rproto->isVariadic()) + return QualType(); + + if (lproto->getTypeQuals() != rproto->getTypeQuals()) + return QualType(); + + // Check argument compatibility + llvm::SmallVector<QualType, 10> types; + for (unsigned i = 0; i < lproto_nargs; i++) { + QualType largtype = lproto->getArgType(i).getUnqualifiedType(); + QualType rargtype = rproto->getArgType(i).getUnqualifiedType(); + QualType argtype = mergeTypes(largtype, rargtype); + if (argtype.isNull()) return QualType(); + types.push_back(argtype); + if (getCanonicalType(argtype) != getCanonicalType(largtype)) + allLTypes = false; + if (getCanonicalType(argtype) != getCanonicalType(rargtype)) + allRTypes = false; + } + if (allLTypes) return lhs; + if (allRTypes) return rhs; + return getFunctionType(retType, types.begin(), types.size(), + lproto->isVariadic(), lproto->getTypeQuals()); + } + + if (lproto) allRTypes = false; + if (rproto) allLTypes = false; + + const FunctionProtoType *proto = lproto ? lproto : rproto; + if (proto) { + assert(!proto->hasExceptionSpec() && "C++ shouldn't be here"); + if (proto->isVariadic()) return QualType(); + // Check that the types are compatible with the types that + // would result from default argument promotions (C99 6.7.5.3p15). + // The only types actually affected are promotable integer + // types and floats, which would be passed as a different + // type depending on whether the prototype is visible. + unsigned proto_nargs = proto->getNumArgs(); + for (unsigned i = 0; i < proto_nargs; ++i) { + QualType argTy = proto->getArgType(i); + if (argTy->isPromotableIntegerType() || + getCanonicalType(argTy).getUnqualifiedType() == FloatTy) + return QualType(); + } + + if (allLTypes) return lhs; + if (allRTypes) return rhs; + return getFunctionType(retType, proto->arg_type_begin(), + proto->getNumArgs(), lproto->isVariadic(), + lproto->getTypeQuals()); + } + + if (allLTypes) return lhs; + if (allRTypes) return rhs; + return getFunctionNoProtoType(retType); +} + +QualType ASTContext::mergeTypes(QualType LHS, QualType RHS) { + // 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 unless the reference is an rvalue reference and + // the expression is a function call (possibly inside parentheses). + // FIXME: C++ shouldn't be going through here! The rules are different + // enough that they should be handled separately. + // FIXME: Merging of lvalue and rvalue references is incorrect. C++ *really* + // shouldn't be going through here! + if (const ReferenceType *RT = LHS->getAsReferenceType()) + LHS = RT->getPointeeType(); + if (const ReferenceType *RT = RHS->getAsReferenceType()) + RHS = RT->getPointeeType(); + + QualType LHSCan = getCanonicalType(LHS), + RHSCan = getCanonicalType(RHS); + + // If two types are identical, they are compatible. + if (LHSCan == RHSCan) + return LHS; + + // If the qualifiers are different, the types aren't compatible + // Note that we handle extended qualifiers later, in the + // case for ExtQualType. + if (LHSCan.getCVRQualifiers() != RHSCan.getCVRQualifiers()) + return QualType(); + + Type::TypeClass LHSClass = LHSCan->getTypeClass(); + Type::TypeClass RHSClass = RHSCan->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; + + // Strip off objc_gc attributes off the top level so they can be merged. + // This is a complete mess, but the attribute itself doesn't make much sense. + if (RHSClass == Type::ExtQual) { + QualType::GCAttrTypes GCAttr = RHSCan.getObjCGCAttr(); + if (GCAttr != QualType::GCNone) { + RHS = QualType(cast<ExtQualType>(RHS.getDesugaredType())->getBaseType(), + RHS.getCVRQualifiers()); + QualType Result = mergeTypes(LHS, RHS); + if (Result.getObjCGCAttr() == QualType::GCNone) + Result = getObjCGCQualType(Result, GCAttr); + else if (Result.getObjCGCAttr() != GCAttr) + Result = QualType(); + return Result; + } + } + if (LHSClass == Type::ExtQual) { + QualType::GCAttrTypes GCAttr = LHSCan.getObjCGCAttr(); + if (GCAttr != QualType::GCNone) { + LHS = QualType(cast<ExtQualType>(LHS.getDesugaredType())->getBaseType(), + LHS.getCVRQualifiers()); + QualType Result = mergeTypes(LHS, RHS); + if (Result.getObjCGCAttr() == QualType::GCNone) + Result = getObjCGCQualType(Result, GCAttr); + else if (Result.getObjCGCAttr() != GCAttr) + Result = QualType(); + return Result; + } + } + + // Same as above for arrays + if (LHSClass == Type::VariableArray || LHSClass == Type::IncompleteArray) + LHSClass = Type::ConstantArray; + if (RHSClass == Type::VariableArray || RHSClass == Type::IncompleteArray) + RHSClass = Type::ConstantArray; + + // Canonicalize ExtVector -> Vector. + if (LHSClass == Type::ExtVector) LHSClass = Type::Vector; + if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; + + // Consider qualified interfaces and interfaces the same. + if (LHSClass == Type::ObjCQualifiedInterface) LHSClass = Type::ObjCInterface; + if (RHSClass == Type::ObjCQualifiedInterface) RHSClass = Type::ObjCInterface; + + // If the canonical type classes don't match. + if (LHSClass != RHSClass) { + const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); + const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); + + // 'id' and 'Class' act sort of like void* for ObjC interfaces + if (LHSIface && (isObjCIdStructType(RHS) || isObjCClassStructType(RHS))) + return LHS; + if (RHSIface && (isObjCIdStructType(LHS) || isObjCClassStructType(LHS))) + return RHS; + + // ID is compatible with all qualified id types. + if (LHS->isObjCQualifiedIdType()) { + if (const PointerType *PT = RHS->getAsPointerType()) { + QualType pType = PT->getPointeeType(); + if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) + return LHS; + // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). + // Unfortunately, this API is part of Sema (which we don't have access + // to. Need to refactor. The following check is insufficient, since we + // need to make sure the class implements the protocol. + if (pType->isObjCInterfaceType()) + return LHS; + } + } + if (RHS->isObjCQualifiedIdType()) { + if (const PointerType *PT = LHS->getAsPointerType()) { + QualType pType = PT->getPointeeType(); + if (isObjCIdStructType(pType) || isObjCClassStructType(pType)) + return RHS; + // FIXME: need to use ObjCQualifiedIdTypesAreCompatible(LHS, RHS, true). + // Unfortunately, this API is part of Sema (which we don't have access + // to. Need to refactor. The following check is insufficient, since we + // need to make sure the class implements the protocol. + if (pType->isObjCInterfaceType()) + return RHS; + } + } + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + if (const EnumType* ETy = LHS->getAsEnumType()) { + if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) + return RHS; + } + if (const EnumType* ETy = RHS->getAsEnumType()) { + if (ETy->getDecl()->getIntegerType() == LHSCan.getUnqualifiedType()) + return LHS; + } + + return QualType(); + } + + // The canonical type classes match. + switch (LHSClass) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#define DEPENDENT_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + assert(false && "Non-canonical and dependent types shouldn't get here"); + return QualType(); + + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + assert(false && "C++ should never be in mergeTypes"); + return QualType(); + + case Type::IncompleteArray: + case Type::VariableArray: + case Type::FunctionProto: + case Type::ExtVector: + case Type::ObjCQualifiedInterface: + assert(false && "Types are eliminated above"); + return QualType(); + + case Type::Pointer: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSPointee = LHS->getAsPointerType()->getPointeeType(); + QualType RHSPointee = RHS->getAsPointerType()->getPointeeType(); + QualType ResultType = mergeTypes(LHSPointee, RHSPointee); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType)) + return RHS; + return getPointerType(ResultType); + } + case Type::BlockPointer: + { + // Merge two block pointer types, while trying to preserve typedef info + QualType LHSPointee = LHS->getAsBlockPointerType()->getPointeeType(); + QualType RHSPointee = RHS->getAsBlockPointerType()->getPointeeType(); + QualType ResultType = mergeTypes(LHSPointee, RHSPointee); + if (ResultType.isNull()) return QualType(); + if (getCanonicalType(LHSPointee) == getCanonicalType(ResultType)) + return LHS; + if (getCanonicalType(RHSPointee) == getCanonicalType(ResultType)) + return RHS; + return getBlockPointerType(ResultType); + } + case Type::ConstantArray: + { + const ConstantArrayType* LCAT = getAsConstantArrayType(LHS); + const ConstantArrayType* RCAT = getAsConstantArrayType(RHS); + if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize()) + return QualType(); + + QualType LHSElem = getAsArrayType(LHS)->getElementType(); + QualType RHSElem = getAsArrayType(RHS)->getElementType(); + QualType ResultType = mergeTypes(LHSElem, RHSElem); + if (ResultType.isNull()) return QualType(); + if (LCAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) + return LHS; + if (RCAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) + return RHS; + if (LCAT) return getConstantArrayType(ResultType, LCAT->getSize(), + ArrayType::ArraySizeModifier(), 0); + if (RCAT) return getConstantArrayType(ResultType, RCAT->getSize(), + ArrayType::ArraySizeModifier(), 0); + const VariableArrayType* LVAT = getAsVariableArrayType(LHS); + const VariableArrayType* RVAT = getAsVariableArrayType(RHS); + if (LVAT && getCanonicalType(LHSElem) == getCanonicalType(ResultType)) + return LHS; + if (RVAT && getCanonicalType(RHSElem) == getCanonicalType(ResultType)) + return RHS; + if (LVAT) { + // FIXME: This isn't correct! But tricky to implement because + // the array's size has to be the size of LHS, but the type + // has to be different. + return LHS; + } + if (RVAT) { + // FIXME: This isn't correct! But tricky to implement because + // the array's size has to be the size of RHS, but the type + // has to be different. + return RHS; + } + if (getCanonicalType(LHSElem) == getCanonicalType(ResultType)) return LHS; + if (getCanonicalType(RHSElem) == getCanonicalType(ResultType)) return RHS; + return getIncompleteArrayType(ResultType, ArrayType::ArraySizeModifier(),0); + } + case Type::FunctionNoProto: + return mergeFunctionTypes(LHS, RHS); + case Type::Record: + case Type::Enum: + // FIXME: Why are these compatible? + if (isObjCIdStructType(LHS) && isObjCClassStructType(RHS)) return LHS; + if (isObjCClassStructType(LHS) && isObjCIdStructType(RHS)) return LHS; + return QualType(); + case Type::Builtin: + // Only exactly equal builtin types are compatible, which is tested above. + return QualType(); + case Type::Complex: + // Distinct complex types are incompatible. + return QualType(); + case Type::Vector: + // FIXME: The merged type should be an ExtVector! + if (areCompatVectorTypes(LHS->getAsVectorType(), RHS->getAsVectorType())) + return LHS; + return QualType(); + case Type::ObjCInterface: { + // Check if the interfaces are assignment compatible. + // FIXME: This should be type compatibility, e.g. whether + // "LHS x; RHS x;" at global scope is legal. + const ObjCInterfaceType* LHSIface = LHS->getAsObjCInterfaceType(); + const ObjCInterfaceType* RHSIface = RHS->getAsObjCInterfaceType(); + if (LHSIface && RHSIface && + canAssignObjCInterfaces(LHSIface, RHSIface)) + return LHS; + + return QualType(); + } + case Type::ObjCQualifiedId: + // Distinct qualified id's are not compatible. + return QualType(); + case Type::FixedWidthInt: + // Distinct fixed-width integers are not compatible. + return QualType(); + case Type::ExtQual: + // FIXME: ExtQual types can be compatible even if they're not + // identical! + return QualType(); + // First attempt at an implementation, but I'm not really sure it's + // right... +#if 0 + ExtQualType* LQual = cast<ExtQualType>(LHSCan); + ExtQualType* RQual = cast<ExtQualType>(RHSCan); + if (LQual->getAddressSpace() != RQual->getAddressSpace() || + LQual->getObjCGCAttr() != RQual->getObjCGCAttr()) + return QualType(); + QualType LHSBase, RHSBase, ResultType, ResCanUnqual; + LHSBase = QualType(LQual->getBaseType(), 0); + RHSBase = QualType(RQual->getBaseType(), 0); + ResultType = mergeTypes(LHSBase, RHSBase); + if (ResultType.isNull()) return QualType(); + ResCanUnqual = getCanonicalType(ResultType).getUnqualifiedType(); + if (LHSCan.getUnqualifiedType() == ResCanUnqual) + return LHS; + if (RHSCan.getUnqualifiedType() == ResCanUnqual) + return RHS; + ResultType = getAddrSpaceQualType(ResultType, LQual->getAddressSpace()); + ResultType = getObjCGCQualType(ResultType, LQual->getObjCGCAttr()); + ResultType.setCVRQualifiers(LHSCan.getCVRQualifiers()); + return ResultType; +#endif + + case Type::TemplateSpecialization: + assert(false && "Dependent types have no size"); + break; + } + + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Integer Predicates +//===----------------------------------------------------------------------===// + +unsigned ASTContext::getIntWidth(QualType T) { + if (T == BoolTy) + return 1; + if (FixedWidthIntType* FWIT = dyn_cast<FixedWidthIntType>(T)) { + return FWIT->getWidth(); + } + // For builtin types, just use the standard type sizing method + return (unsigned)getTypeSize(T); +} + +QualType ASTContext::getCorrespondingUnsignedType(QualType T) { + assert(T->isSignedIntegerType() && "Unexpected type"); + if (const EnumType* ETy = T->getAsEnumType()) + T = ETy->getDecl()->getIntegerType(); + const BuiltinType* BTy = T->getAsBuiltinType(); + assert (BTy && "Unexpected signed integer type"); + switch (BTy->getKind()) { + case BuiltinType::Char_S: + case BuiltinType::SChar: + return UnsignedCharTy; + case BuiltinType::Short: + return UnsignedShortTy; + case BuiltinType::Int: + return UnsignedIntTy; + case BuiltinType::Long: + return UnsignedLongTy; + case BuiltinType::LongLong: + return UnsignedLongLongTy; + case BuiltinType::Int128: + return UnsignedInt128Ty; + default: + assert(0 && "Unexpected signed integer type"); + return QualType(); + } +} + +ExternalASTSource::~ExternalASTSource() { } + +void ExternalASTSource::PrintStats() { } diff --git a/lib/AST/Builtins.cpp b/lib/AST/Builtins.cpp new file mode 100644 index 0000000..8368feb --- /dev/null +++ b/lib/AST/Builtins.cpp @@ -0,0 +1,290 @@ +//===--- 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/AST/Decl.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, 0, false }, +#define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, false }, +#define LIBBUILTIN(ID, TYPE, ATTRS, HEADER) { #ID, TYPE, ATTRS, HEADER, false }, +#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]; +} + +/// \brief Load all of the target builtins. This must be called +/// prior to initializing the builtin identifiers. +void Builtin::Context::InitializeTargetBuiltins(const TargetInfo &Target) { + Target.getTargetBuiltins(TSRecords, NumTSRecords); +} + +/// 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, + bool NoBuiltins) { + // Step #1: mark all target-independent builtins with their ID's. + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Table.get(BuiltinInfo[i].Name).setBuiltinID(i); + + // Step #2: Register target-specific builtins. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Table.get(TSRecords[i].Name).setBuiltinID(i+Builtin::FirstTSBuiltin); +} + +void +Builtin::Context::GetBuiltinNames(llvm::SmallVectorImpl<const char *> &Names, + bool NoBuiltins) { + // Final all target-independent names + for (unsigned i = Builtin::NotBuiltin+1; i != Builtin::FirstTSBuiltin; ++i) + if (!BuiltinInfo[i].Suppressed && + (!NoBuiltins || !strchr(BuiltinInfo[i].Attributes, 'f'))) + Names.push_back(BuiltinInfo[i].Name); + + // Find target-specific names. + for (unsigned i = 0, e = NumTSRecords; i != e; ++i) + if (!TSRecords[i].Suppressed && + (!NoBuiltins || + (TSRecords[i].Attributes && + !strchr(TSRecords[i].Attributes, 'f')))) + Names.push_back(TSRecords[i].Name); +} + +bool +Builtin::Context::isPrintfLike(unsigned ID, unsigned &FormatIdx, + bool &HasVAListArg) { + const char *Printf = strpbrk(GetRecord(ID).Attributes, "pP"); + if (!Printf) + return false; + + HasVAListArg = (*Printf == 'P'); + + ++Printf; + assert(*Printf == ':' && "p or P specifier must have be followed by a ':'"); + ++Printf; + + assert(strchr(Printf, ':') && "printf specifier must end with a ':'"); + FormatIdx = strtol(Printf, 0, 10); + return true; +} + +/// 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, + Builtin::Context::GetBuiltinTypeError &Error, + bool AllowTypeModifiers = true) { + // Modifiers. + int HowLong = 0; + bool 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(HowLong <= 2 && "Can't have LLLL modifier"); + ++HowLong; + break; + } + } + + QualType Type; + + // Read the base type. + switch (*Str++) { + default: assert(0 && "Unknown builtin type letter!"); + case 'v': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'v'!"); + Type = Context.VoidTy; + break; + case 'f': + assert(HowLong == 0 && !Signed && !Unsigned && + "Bad modifiers used with 'f'!"); + Type = Context.FloatTy; + break; + case 'd': + assert(HowLong < 2 && !Signed && !Unsigned && + "Bad modifiers used with 'd'!"); + if (HowLong) + Type = Context.LongDoubleTy; + else + Type = Context.DoubleTy; + break; + case 's': + assert(HowLong == 0 && "Bad modifiers used with 's'!"); + if (Unsigned) + Type = Context.UnsignedShortTy; + else + Type = Context.ShortTy; + break; + case 'i': + if (HowLong == 3) + Type = Unsigned ? Context.UnsignedInt128Ty : Context.Int128Ty; + else if (HowLong == 2) + Type = Unsigned ? Context.UnsignedLongLongTy : Context.LongLongTy; + else if (HowLong == 1) + Type = Unsigned ? Context.UnsignedLongTy : Context.LongTy; + else + Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy; + break; + case 'c': + assert(HowLong == 0 && "Bad modifiers used with 'c'!"); + if (Signed) + Type = Context.SignedCharTy; + else if (Unsigned) + Type = Context.UnsignedCharTy; + else + Type = Context.CharTy; + break; + case 'b': // boolean + assert(HowLong == 0 && !Signed && !Unsigned && "Bad modifiers for 'b'!"); + Type = Context.BoolTy; + break; + case 'z': // size_t. + assert(HowLong == 0 && !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 'A': + // This is a "reference" to a va_list; however, what exactly + // this means depends on how va_list is defined. There are two + // different kinds of va_list: ones passed by value, and ones + // passed by reference. An example of a by-value va_list is + // x86, where va_list is a char*. An example of by-ref va_list + // is x86-64, where va_list is a __va_list_tag[1]. For x86, + // we want this argument to be a char*&; for x86-64, we want + // it to be a __va_list_tag*. + Type = Context.getBuiltinVaListType(); + assert(!Type.isNull() && "builtin va list type not initialized!"); + if (Type->isArrayType()) { + Type = Context.getArrayDecayedType(Type); + } else { + Type = Context.getLValueReferenceType(Type); + } + break; + case 'V': { + char *End; + + unsigned NumElements = strtoul(Str, &End, 10); + assert(End != Str && "Missing vector size"); + + Str = End; + + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, false); + Type = Context.getVectorType(ElementType, NumElements); + break; + } + case 'P': { + IdentifierInfo *II = &Context.Idents.get("FILE"); + DeclContext::lookup_result Lookup + = Context.getTranslationUnitDecl()->lookup(Context, II); + if (Lookup.first != Lookup.second && isa<TypeDecl>(*Lookup.first)) { + Type = Context.getTypeDeclType(cast<TypeDecl>(*Lookup.first)); + break; + } + else { + Error = Builtin::Context::GE_Missing_FILE; + return QualType(); + } + } + } + + if (!AllowTypeModifiers) + return Type; + + Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case '*': + Type = Context.getPointerType(Type); + break; + case '&': + Type = Context.getLValueReferenceType(Type); + break; + // FIXME: There's no way to have a built-in with an rvalue ref arg. + 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, + GetBuiltinTypeError &Error) const { + const char *TypeStr = GetRecord(id).Type; + + llvm::SmallVector<QualType, 8> ArgTypes; + + Error = GE_None; + QualType ResType = DecodeTypeFromStr(TypeStr, Context, Error); + if (Error != GE_None) + return QualType(); + while (TypeStr[0] && TypeStr[0] != '.') { + QualType Ty = DecodeTypeFromStr(TypeStr, Context, Error); + if (Error != GE_None) + return QualType(); + + // Do array -> pointer decay. The builtin should use the decayed type. + if (Ty->isArrayType()) + Ty = Context.getArrayDecayedType(Ty); + + ArgTypes.push_back(Ty); + } + + 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.getFunctionNoProtoType(ResType); + return Context.getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), + TypeStr[0] == '.', 0); +} diff --git a/lib/AST/CFG.cpp b/lib/AST/CFG.cpp new file mode 100644 index 0000000..9f2f207 --- /dev/null +++ b/lib/AST/CFG.cpp @@ -0,0 +1,1913 @@ +//===--- 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/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 <llvm/Support/Allocator.h> +#include <llvm/Support/Format.h> +#include <iomanip> +#include <algorithm> +#include <sstream> + +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; +}; + +static SourceLocation GetEndLoc(Decl* D) { + if (VarDecl* VD = dyn_cast<VarDecl>(D)) + if (Expr* Ex = VD->getInit()) + return Ex->getSourceRange().getEnd(); + + return D->getLocation(); +} + +/// CFGBuilder - This class 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* VisitBreakStmt(BreakStmt* B); + CFGBlock* VisitCaseStmt(CaseStmt* Terminator); + CFGBlock* VisitCompoundStmt(CompoundStmt* C); + CFGBlock* VisitContinueStmt(ContinueStmt* C); + CFGBlock* VisitDefaultStmt(DefaultStmt* D); + CFGBlock* VisitDoStmt(DoStmt* D); + CFGBlock* VisitForStmt(ForStmt* F); + CFGBlock* VisitGotoStmt(GotoStmt* G); + CFGBlock* VisitIfStmt(IfStmt* I); + CFGBlock* VisitIndirectGotoStmt(IndirectGotoStmt* I); + CFGBlock* VisitLabelStmt(LabelStmt* L); + CFGBlock* VisitNullStmt(NullStmt* Statement); + CFGBlock* VisitObjCForCollectionStmt(ObjCForCollectionStmt* S); + CFGBlock* VisitReturnStmt(ReturnStmt* R); + CFGBlock* VisitStmt(Stmt* Statement); + CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator); + CFGBlock* VisitWhileStmt(WhileStmt* W); + + // FIXME: Add support for ObjC-specific control-flow structures. + + // NYS == Not Yet Supported + CFGBlock* NYS() { + badCFG = true; + return Block; + } + + CFGBlock* VisitObjCAtTryStmt(ObjCAtTryStmt* S); + CFGBlock* VisitObjCAtCatchStmt(ObjCAtCatchStmt* S) { + // FIXME: For now we pretend that @catch and the code it contains + // does not exit. + return Block; + } + + // FIXME: This is not completely supported. We basically @throw like + // a 'return'. + CFGBlock* VisitObjCAtThrowStmt(ObjCAtThrowStmt* S); + + CFGBlock* VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S); + + // Blocks. + CFGBlock* VisitBlockExpr(BlockExpr* E) { return NYS(); } + CFGBlock* VisitBlockDeclRefExpr(BlockDeclRefExpr* E) { return NYS(); } + +private: + CFGBlock* createBlock(bool add_successor = true); + CFGBlock* addStmt(Stmt* Terminator); + CFGBlock* WalkAST(Stmt* Terminator, bool AlwaysAddStmt); + CFGBlock* WalkAST_VisitChildren(Stmt* Terminator); + CFGBlock* WalkAST_VisitDeclSubExpr(Decl* D); + CFGBlock* WalkAST_VisitStmtExpr(StmtExpr* Terminator); + bool FinishBlock(CFGBlock* B); + + bool badCFG; +}; + +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template? +static 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 0; +} + +/// 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. +bool CFGBuilder::FinishBlock(CFGBlock* B) { + if (badCFG) + return false; + + assert (B); + B->reverseStmts(); + return true; +} + +/// 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* Terminator) { + if (!Block) Block = createBlock(); + return WalkAST(Terminator,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* Terminator, bool AlwaysAddStmt = false) { + switch (Terminator->getStmtClass()) { + case Stmt::ConditionalOperatorClass: { + ConditionalOperator* C = cast<ConditionalOperator>(Terminator); + + // Create the confluence block that will "merge" the results + // of the ternary expression. + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + if (!FinishBlock(ConfluenceBlock)) + return 0; + + // 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()); + if (!FinishBlock(LHSBlock)) + return 0; + Block = NULL; + } + + // Create the block for the RHS expression. + Succ = ConfluenceBlock; + CFGBlock* RHSBlock = Visit(C->getRHS()); + if (!FinishBlock(RHSBlock)) + return 0; + + // 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>(Terminator); + + CFGBlock* ConfluenceBlock = Block ? Block : createBlock(); + ConfluenceBlock->appendStmt(C); + if (!FinishBlock(ConfluenceBlock)) + return 0; + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* LHSBlock = Visit(C->getLHS()); + if (!FinishBlock(LHSBlock)) + return 0; + + Succ = ConfluenceBlock; + Block = NULL; + CFGBlock* RHSBlock = Visit(C->getRHS()); + if (!FinishBlock(RHSBlock)) + return 0; + + Block = createBlock(false); + Block->addSuccessor(LHSBlock); + Block->addSuccessor(RHSBlock); + Block->setTerminator(C); + return addStmt(C->getCond()); + } + + case Stmt::DeclStmtClass: { + DeclStmt *DS = cast<DeclStmt>(Terminator); + if (DS->isSingleDecl()) { + Block->appendStmt(Terminator); + return WalkAST_VisitDeclSubExpr(DS->getSingleDecl()); + } + + CFGBlock* B = 0; + + // FIXME: Add a reverse iterator for DeclStmt to avoid this + // extra copy. + typedef llvm::SmallVector<Decl*,10> BufTy; + BufTy Buf(DS->decl_begin(), DS->decl_end()); + + for (BufTy::reverse_iterator I=Buf.rbegin(), E=Buf.rend(); I!=E; ++I) { + // Get the alignment of the new DeclStmt, padding out to >=8 bytes. + unsigned A = llvm::AlignOf<DeclStmt>::Alignment < 8 + ? 8 : llvm::AlignOf<DeclStmt>::Alignment; + + // Allocate the DeclStmt using the BumpPtrAllocator. It will + // get automatically freed with the CFG. + DeclGroupRef DG(*I); + Decl* D = *I; + void* Mem = cfg->getAllocator().Allocate(sizeof(DeclStmt), A); + + DeclStmt* DS = new (Mem) DeclStmt(DG, D->getLocation(), GetEndLoc(D)); + + // Append the fake DeclStmt to block. + Block->appendStmt(DS); + B = WalkAST_VisitDeclSubExpr(D); + } + return B; + } + + case Stmt::AddrLabelExprClass: { + AddrLabelExpr* A = cast<AddrLabelExpr>(Terminator); + AddressTakenLabels.insert(A->getLabel()); + + if (AlwaysAddStmt) Block->appendStmt(Terminator); + return Block; + } + + case Stmt::StmtExprClass: + return WalkAST_VisitStmtExpr(cast<StmtExpr>(Terminator)); + + case Stmt::SizeOfAlignOfExprClass: { + SizeOfAlignOfExpr* E = cast<SizeOfAlignOfExpr>(Terminator); + + // VLA types have expressions that must be evaluated. + if (E->isArgumentType()) { + for (VariableArrayType* VA = FindVA(E->getArgumentType().getTypePtr()); + VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) + addStmt(VA->getSizeExpr()); + } + // Expressions in sizeof/alignof are not evaluated and thus have no + // control flow. + else + Block->appendStmt(Terminator); + + return Block; + } + + case Stmt::BinaryOperatorClass: { + BinaryOperator* B = cast<BinaryOperator>(Terminator); + + if (B->isLogicalOp()) { // && or || + CFGBlock* ConfluenceBlock = (Block) ? Block : createBlock(); + ConfluenceBlock->appendStmt(B); + if (!FinishBlock(ConfluenceBlock)) + return 0; + + // 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()); + if (!FinishBlock(RHSBlock)) + return 0; + + // 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; + } + + // Blocks: No support for blocks ... yet + case Stmt::BlockExprClass: + case Stmt::BlockDeclRefExprClass: + return NYS(); + + case Stmt::ParenExprClass: + return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt); + + default: + break; + }; + + if (AlwaysAddStmt) Block->appendStmt(Terminator); + return WalkAST_VisitChildren(Terminator); +} + +/// WalkAST_VisitDeclSubExpr - Utility method to add block-level expressions +/// for initializers in Decls. +CFGBlock* CFGBuilder::WalkAST_VisitDeclSubExpr(Decl* D) { + VarDecl* VD = dyn_cast<VarDecl>(D); + + if (!VD) + return Block; + + Expr* Init = VD->getInit(); + + if (Init) { + // Optimization: Don't create separate block-level statements for literals. + switch (Init->getStmtClass()) { + case Stmt::IntegerLiteralClass: + case Stmt::CharacterLiteralClass: + case Stmt::StringLiteralClass: + break; + default: + Block = addStmt(Init); + } + } + + // If the type of VD is a VLA, then we must process its size expressions. + for (VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); VA != 0; + VA = FindVA(VA->getElementType().getTypePtr())) + Block = addStmt(VA->getSizeExpr()); + + return Block; +} + +/// WalkAST_VisitChildren - Utility method to call WalkAST on the +/// children of a Stmt. +CFGBlock* CFGBuilder::WalkAST_VisitChildren(Stmt* Terminator) { + CFGBlock* B = Block; + for (Stmt::child_iterator I = Terminator->child_begin(), + E = Terminator->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* Terminator) { + Block->appendStmt(Terminator); + return VisitCompoundStmt(Terminator->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) { + + CFGBlock* LastBlock = NULL; + + for (CompoundStmt::reverse_body_iterator I=C->body_rbegin(), E=C->body_rend(); + I != E; ++I ) { + LastBlock = Visit(*I); + } + + return LastBlock; +} + +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; + if (!FinishBlock(Block)) + return 0; + } + + // 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) { + if (!FinishBlock(ElseBlock)) + return 0; + } + } + + // 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) { + // We can reach here if the "then" body has all NullStmts. + // Create an empty block so we can distinguish between true and false + // branches in path-sensitive analyses. + ThenBlock = createBlock(false); + ThenBlock->addSuccessor(sv.get()); + } + else if (Block) { + if (!FinishBlock(ThenBlock)) + return 0; + } + } + + // 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); + if (!FinishBlock(LabelBlock)) + return 0; + + // 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) { + if (!FinishBlock(Block)) + return 0; + 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) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // 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); + + // Create a new block to contain the (bottom) of the loop body. + Block = NULL; + + if (Stmt* I = F->getInc()) { + // Generate increment code in its own basic block. This is the target + // of continue statements. + Succ = Visit(I); + } + else { + // No increment code. Create a special, empty, block that is used as + // the target block for "looping back" to the start of the loop. + assert(Succ == EntryConditionBlock); + Succ = createBlock(); + } + + // Finish up the increment (or empty) block if it hasn't been already. + if (Block) { + assert(Block == Succ); + if (!FinishBlock(Block)) + return 0; + Block = 0; + } + + ContinueTargetBlock = Succ; + + // The starting block for the loop increment is the block that should + // represent the 'loop target' for looping back to the start of the loop. + ContinueTargetBlock->setLoopTarget(F); + + // All breaks should go to the code following the loop. + BreakTargetBlock = LoopSuccessor; + + // 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) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // 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::VisitObjCForCollectionStmt(ObjCForCollectionStmt* S) { + // Objective-C fast enumeration 'for' statements: + // http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC + // + // for ( Type newVariable in collection_expression ) { statements } + // + // becomes: + // + // prologue: + // 1. collection_expression + // T. jump to loop_entry + // loop_entry: + // 1. side-effects of element expression + // 1. ObjCForCollectionStmt [performs binding to newVariable] + // T. ObjCForCollectionStmt TB, FB [jumps to TB if newVariable != nil] + // TB: + // statements + // T. jump to loop_entry + // FB: + // what comes after + // + // and + // + // Type existingItem; + // for ( existingItem in expression ) { statements } + // + // becomes: + // + // the same with newVariable replaced with existingItem; the binding + // works the same except that for one ObjCForCollectionStmt::getElement() + // returns a DeclStmt and the other returns a DeclRefExpr. + // + + CFGBlock* LoopSuccessor = 0; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + LoopSuccessor = Block; + Block = 0; + } + else LoopSuccessor = Succ; + + // Build the condition blocks. + CFGBlock* ExitConditionBlock = createBlock(false); + CFGBlock* EntryConditionBlock = ExitConditionBlock; + + // Set the terminator for the "exit" condition block. + ExitConditionBlock->setTerminator(S); + + // The last statement in the block should be the ObjCForCollectionStmt, + // which performs the actual binding to 'element' and determines if there + // are any more items in the collection. + ExitConditionBlock->appendStmt(S); + Block = ExitConditionBlock; + + // Walk the 'element' expression to see if there are any side-effects. We + // generate new blocks as necesary. We DON'T add the statement by default + // to the CFG unless it contains control-flow. + EntryConditionBlock = WalkAST(S->getElement(), false); + if (Block) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + Block = 0; + } + + // The condition block is the implicit successor for the loop body as + // well as any code above the loop. + Succ = EntryConditionBlock; + + // Now create the true branch. + { + // Save the current values for Succ, continue and break targets. + SaveAndRestore<CFGBlock*> save_Succ(Succ), + save_continue(ContinueTargetBlock), save_break(BreakTargetBlock); + + BreakTargetBlock = LoopSuccessor; + ContinueTargetBlock = EntryConditionBlock; + + CFGBlock* BodyBlock = Visit(S->getBody()); + + if (!BodyBlock) + BodyBlock = EntryConditionBlock; // can happen for "for (X in Y) ;" + else if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // 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); + + // Now create a prologue block to contain the collection expression. + Block = createBlock(); + return addStmt(S->getCollection()); +} + +CFGBlock* CFGBuilder::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt* S) { + // FIXME: Add locking 'primitives' to CFG for @synchronized. + + // Inline the body. + CFGBlock *SyncBlock = Visit(S->getSynchBody()); + + // The sync body starts its own basic block. This makes it a little easier + // for diagnostic clients. + if (SyncBlock) { + if (!FinishBlock(SyncBlock)) + return 0; + + Block = 0; + } + + Succ = SyncBlock; + + // Inline the sync expression. + return Visit(S->getSynchExpr()); +} + +CFGBlock* CFGBuilder::VisitObjCAtTryStmt(ObjCAtTryStmt* S) { + return NYS(); +} + +CFGBlock* CFGBuilder::VisitWhileStmt(WhileStmt* W) { + // "while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + 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) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // 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); + + // Create an empty block to represent the transition block for looping + // back to the head of the loop. + Block = 0; + assert(Succ == EntryConditionBlock); + Succ = createBlock(); + Succ->setLoopTarget(W); + ContinueTargetBlock = Succ; + + // 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) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // 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::VisitObjCAtThrowStmt(ObjCAtThrowStmt* S) { + // FIXME: This isn't complete. We basically treat @throw like a return + // statement. + + // If we were in the middle of a block we stop processing that block + // and reverse its statements. + if (Block) { + if (!FinishBlock(Block)) + return 0; + } + + // Create the new block. + Block = createBlock(false); + + // The Exit block is the only successor. + Block->addSuccessor(&cfg->getExit()); + + // Add the statement to the block. This may create new blocks + // if S contains control-flow (short-circuit operations). + return addStmt(S); +} + +CFGBlock* CFGBuilder::VisitDoStmt(DoStmt* D) { + // "do...while" is a control-flow statement. Thus we stop processing the + // current block. + + CFGBlock* LoopSuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + 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) { + if (!FinishBlock(EntryConditionBlock)) + return 0; + } + } + + // 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) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // Add an intermediate block between the BodyBlock and the + // ExitConditionBlock to represent the "loop back" transition. + // Create an empty block to represent the transition block for looping + // back to the head of the loop. + // FIXME: Can we do this more efficiently without adding another block? + Block = NULL; + Succ = BodyBlock; + CFGBlock *LoopBackBlock = createBlock(); + LoopBackBlock->setLoopTarget(D); + + // Add the loop body entry as a successor to the condition. + ExitConditionBlock->addSuccessor(LoopBackBlock); + } + + // 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) { + if (!FinishBlock(Block)) + return 0; + } + + // 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. This means the CFG cannot be constructed. + if (ContinueTargetBlock) + Block->addSuccessor(ContinueTargetBlock); + else + badCFG = true; + + return Block; +} + +CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) { + // "break" is a control-flow statement. Thus we stop processing the + // current block. + if (Block) { + if (!FinishBlock(Block)) + return 0; + } + + // 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. This means that the CFG cannot be constructed. + if (BreakTargetBlock) + Block->addSuccessor(BreakTargetBlock); + else + badCFG = true; + + + return Block; +} + +CFGBlock* CFGBuilder::VisitSwitchStmt(SwitchStmt* Terminator) { + // "switch" is a control-flow statement. Thus we stop processing the + // current block. + CFGBlock* SwitchSuccessor = NULL; + + if (Block) { + if (!FinishBlock(Block)) + return 0; + 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 (Terminator->getBody() && "switch must contain a non-NULL body"); + Block = NULL; + CFGBlock *BodyBlock = Visit(Terminator->getBody()); + if (Block) { + if (!FinishBlock(BodyBlock)) + return 0; + } + + // 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(Terminator); + assert (Terminator->getCond() && "switch condition must be non-NULL"); + Block = SwitchTerminatedBlock; + + return addStmt(Terminator->getCond()); +} + +CFGBlock* CFGBuilder::VisitCaseStmt(CaseStmt* Terminator) { + // CaseStmts are essentially labels, so they are the + // first statement in a block. + + if (Terminator->getSubStmt()) Visit(Terminator->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(Terminator); + if (!FinishBlock(CaseBlock)) + return 0; + + // 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* Terminator) { + if (Terminator->getSubStmt()) Visit(Terminator->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(Terminator); + if (!FinishBlock(DefaultCaseBlock)) + return 0; + + // 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) { + if (!FinishBlock(Block)) + return 0; + } + 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* Terminator, llvm::SmallPtrSet<Expr*,50>& Set) { + if (!Terminator) + return; + + for (Stmt::child_iterator I=Terminator->child_begin(), E=Terminator->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 *possibly* register as a block-level + // expression. Basically, if an assignment occurs both in a subexpression + // and at the block-level, it is 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); + + for (CFG::iterator I=cfg.begin(), E=cfg.end(); I != E; ++I) { + + // Iterate over the statements again on identify the Expr* and Stmt* at + // the block-level that are block-level expressions. + + for (CFGBlock::iterator BI=I->begin(), EI=I->end(); BI != EI; ++BI) + if (Expr* Exp = dyn_cast<Expr>(*BI)) { + + if (BinaryOperator* B = dyn_cast<BinaryOperator>(Exp)) { + // 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(Exp)) + continue; + } + else if (const StmtExpr* Terminator = dyn_cast<StmtExpr>(Exp)) { + // Special handling for statement expressions. The last statement + // in the statement expression is also a block-level expr. + const CompoundStmt* C = Terminator->getSubStmt(); + if (!C->body_empty()) { + unsigned x = M->size(); + (*M)[C->body_back()] = x; + } + } + + unsigned x = M->size(); + (*M)[Exp] = x; + } + + // Look at terminators. The condition is a block-level expression. + + Stmt* S = I->getTerminatorCondition(); + + if (S && M->find(S) == M->end()) { + unsigned x = M->size(); + (*M)[S] = 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(); + } +} + +//===----------------------------------------------------------------------===// +// Cleanup: CFG dstor. +//===----------------------------------------------------------------------===// + +CFG::~CFG() { + delete reinterpret_cast<const BlkExprMapTy*>(BlkExprMap); +} + +//===----------------------------------------------------------------------===// +// 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* Terminator, llvm::raw_ostream& OS) { + + StmtMapTy::iterator I = StmtMap.find(Terminator); + + 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> { + + llvm::raw_ostream& OS; + StmtPrinterHelper* Helper; + PrintingPolicy Policy; + +public: + CFGBlockTerminatorPrint(llvm::raw_ostream& os, StmtPrinterHelper* helper, + const PrintingPolicy &Policy = PrintingPolicy()) + : OS(os), Helper(helper), Policy(Policy) {} + + void VisitIfStmt(IfStmt* I) { + OS << "if "; + I->getCond()->printPretty(OS,Helper,Policy); + } + + // Default case. + void VisitStmt(Stmt* Terminator) { Terminator->printPretty(OS, Helper, Policy); } + + void VisitForStmt(ForStmt* F) { + OS << "for (" ; + if (F->getInit()) OS << "..."; + OS << "; "; + if (Stmt* C = F->getCond()) C->printPretty(OS, Helper, Policy); + OS << "; "; + if (F->getInc()) OS << "..."; + OS << ")"; + } + + void VisitWhileStmt(WhileStmt* W) { + OS << "while " ; + if (Stmt* C = W->getCond()) C->printPretty(OS, Helper, Policy); + } + + void VisitDoStmt(DoStmt* D) { + OS << "do ... while "; + if (Stmt* C = D->getCond()) C->printPretty(OS, Helper, Policy); + } + + void VisitSwitchStmt(SwitchStmt* Terminator) { + OS << "switch "; + Terminator->getCond()->printPretty(OS, Helper, Policy); + } + + void VisitConditionalOperator(ConditionalOperator* C) { + C->getCond()->printPretty(OS, Helper, Policy); + OS << " ? ... : ..."; + } + + void VisitChooseExpr(ChooseExpr* C) { + OS << "__builtin_choose_expr( "; + C->getCond()->printPretty(OS, Helper, Policy); + OS << " )"; + } + + void VisitIndirectGotoStmt(IndirectGotoStmt* I) { + OS << "goto *"; + I->getTarget()->printPretty(OS, Helper, Policy); + } + + void VisitBinaryOperator(BinaryOperator* B) { + if (!B->isLogicalOp()) { + VisitExpr(B); + return; + } + + B->getLHS()->printPretty(OS, Helper, Policy); + + 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, Policy); + } +}; + + +void print_stmt(llvm::raw_ostream&OS, StmtPrinterHelper* Helper, Stmt* Terminator) { + if (Helper) { + // special printing for statement-expressions. + if (StmtExpr* SE = dyn_cast<StmtExpr>(Terminator)) { + 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>(Terminator)) { + if (B->getOpcode() == BinaryOperator::Comma) { + OS << "... , "; + Helper->handledStmt(B->getRHS(),OS); + OS << '\n'; + return; + } + } + } + + Terminator->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy()); + + // Expressions need a newline. + if (isa<Expr>(Terminator)) OS << '\n'; +} + +void print_block(llvm::raw_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* Terminator = const_cast<Stmt*>(B.getLabel())) { + + if (print_edges) + OS << " "; + + if (LabelStmt* L = dyn_cast<LabelStmt>(Terminator)) + OS << L->getName(); + else if (CaseStmt* C = dyn_cast<CaseStmt>(Terminator)) { + OS << "case "; + C->getLHS()->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy()); + if (C->getRHS()) { + OS << " ... "; + C->getRHS()->printPretty(OS, Helper, /*FIXME:*/PrintingPolicy()); + } + } + else if (isa<DefaultStmt>(Terminator)) + 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 << llvm::format("%3d", 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, /*FIXME*/PrintingPolicy()); + 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::errs()); } + +/// print - A simple pretty printer of a CFG that outputs to an ostream. +void CFG::print(llvm::raw_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); + OS.flush(); +} + +/// dump - A simply pretty printer of a CFGBlock that outputs to stderr. +void CFGBlock::dump(const CFG* cfg) const { print(llvm::errs(), 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(llvm::raw_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(llvm::raw_ostream& OS) const { + CFGBlockTerminatorPrint TPrinter(OS,NULL); + TPrinter.Visit(const_cast<Stmt*>(getTerminator())); +} + +Stmt* CFGBlock::getTerminatorCondition() { + + if (!Terminator) + return NULL; + + Expr* E = NULL; + + switch (Terminator->getStmtClass()) { + default: + break; + + case Stmt::ForStmtClass: + E = cast<ForStmt>(Terminator)->getCond(); + break; + + case Stmt::WhileStmtClass: + E = cast<WhileStmt>(Terminator)->getCond(); + break; + + case Stmt::DoStmtClass: + E = cast<DoStmt>(Terminator)->getCond(); + break; + + case Stmt::IfStmtClass: + E = cast<IfStmt>(Terminator)->getCond(); + break; + + case Stmt::ChooseExprClass: + E = cast<ChooseExpr>(Terminator)->getCond(); + break; + + case Stmt::IndirectGotoStmtClass: + E = cast<IndirectGotoStmt>(Terminator)->getTarget(); + break; + + case Stmt::SwitchStmtClass: + E = cast<SwitchStmt>(Terminator)->getCond(); + break; + + case Stmt::ConditionalOperatorClass: + E = cast<ConditionalOperator>(Terminator)->getCond(); + break; + + case Stmt::BinaryOperatorClass: // '&&' and '||' + E = cast<BinaryOperator>(Terminator)->getLHS(); + break; + + case Stmt::ObjCForCollectionStmtClass: + return Terminator; + } + + return E ? E->IgnoreParens() : NULL; +} + +bool CFGBlock::hasBinaryBranchTerminator() const { + + if (!Terminator) + return false; + + Expr* E = NULL; + + switch (Terminator->getStmtClass()) { + default: + return false; + + case Stmt::ForStmtClass: + case Stmt::WhileStmtClass: + case Stmt::DoStmtClass: + case Stmt::IfStmtClass: + case Stmt::ChooseExprClass: + case Stmt::ConditionalOperatorClass: + case Stmt::BinaryOperatorClass: + return true; + } + + return E ? E->IgnoreParens() : NULL; +} + + +//===----------------------------------------------------------------------===// +// 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; +#endif +} + +namespace llvm { +template<> +struct DOTGraphTraits<const CFG*> : public DefaultDOTGraphTraits { + static std::string getNodeLabel(const CFGBlock* Node, const CFG* Graph) { + +#ifndef NDEBUG + std::string OutSStr; + llvm::raw_string_ostream Out(OutSStr); + 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/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt new file mode 100644 index 0000000..19ab9f6 --- /dev/null +++ b/lib/AST/CMakeLists.txt @@ -0,0 +1,32 @@ +set(LLVM_NO_RTTI 1) + +add_clang_library(clangAST + APValue.cpp + ASTConsumer.cpp + ASTContext.cpp + Builtins.cpp + CFG.cpp + DeclarationName.cpp + DeclBase.cpp + Decl.cpp + DeclCXX.cpp + DeclGroup.cpp + DeclObjC.cpp + DeclPrinter.cpp + DeclTemplate.cpp + ExprConstant.cpp + Expr.cpp + ExprCXX.cpp + InheritViz.cpp + NestedNameSpecifier.cpp + ParentMap.cpp + Stmt.cpp + StmtDumper.cpp + StmtIterator.cpp + StmtPrinter.cpp + StmtViz.cpp + TemplateName.cpp + Type.cpp + ) + +add_dependencies(clangAST ClangDiagnosticAST) diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp new file mode 100644 index 0000000..cb3ec1f --- /dev/null +++ b/lib/AST/Decl.cpp @@ -0,0 +1,630 @@ +//===--- 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 subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/IdentifierTable.h" +#include <vector> + +using namespace clang; + +void Attr::Destroy(ASTContext &C) { + if (Next) { + Next->Destroy(C); + Next = 0; + } + this->~Attr(); + C.Deallocate((void*)this); +} + + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + + +TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { + return new (C) TranslationUnitDecl(); +} + +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, L, Id); +} + +void NamespaceDecl::Destroy(ASTContext& C) { + // NamespaceDecl uses "NextDeclarator" to chain namespace declarations + // together. They are all top-level Decls. + + this->~NamespaceDecl(); + C.Deallocate((void *)this); +} + + +ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, QualType T) { + return new (C) ImplicitParamDecl(ImplicitParam, DC, L, Id, T); +} + +const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { + switch (SC) { + case VarDecl::None: break; + case VarDecl::Auto: return "auto"; break; + case VarDecl::Extern: return "extern"; break; + case VarDecl::PrivateExtern: return "__private_extern__"; break; + case VarDecl::Register: return "register"; break; + case VarDecl::Static: return "static"; break; + } + + assert(0 && "Invalid storage class"); + return 0; +} + +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, StorageClass S, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, L, Id, T, S, DefArg); +} + +QualType ParmVarDecl::getOriginalType() const { + if (const OriginalParmVarDecl *PVD = + dyn_cast<OriginalParmVarDecl>(this)) + return PVD->OriginalType; + return getType(); +} + +void VarDecl::setInit(ASTContext &C, Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); + } + + Init = I; + } + +bool VarDecl::isExternC(ASTContext &Context) const { + if (!Context.getLangOptions().CPlusPlus) + return (getDeclContext()->isTranslationUnit() && + getStorageClass() != Static) || + (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static; + + break; + } + + if (DC->isFunctionOrMethod()) + return false; + } + + return false; +} + +OriginalParmVarDecl *OriginalParmVarDecl::Create( + ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, QualType OT, StorageClass S, + Expr *DefArg) { + return new (C) OriginalParmVarDecl(DC, L, Id, T, OT, S, DefArg); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName N, QualType T, + StorageClass S, bool isInline, + bool hasWrittenPrototype, + SourceLocation TypeSpecStartLoc) { + FunctionDecl *New + = new (C) FunctionDecl(Function, DC, L, N, T, S, isInline, + TypeSpecStartLoc); + New->HasWrittenPrototype = hasWrittenPrototype; + return New; +} + +BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) BlockDecl(DC, L); +} + +FieldDecl *FieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW, + bool Mutable) { + return new (C) FieldDecl(Decl::Field, DC, L, Id, T, BW, Mutable); +} + +bool FieldDecl::isAnonymousStructOrUnion() const { + if (!isImplicit() || getDeclName()) + return false; + + if (const RecordType *Record = getType()->getAsRecordType()) + return Record->getDecl()->isAnonymousStructOrUnion(); + + return false; +} + +EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, + SourceLocation L, + IdentifierInfo *Id, QualType T, + Expr *E, const llvm::APSInt &V) { + return new (C) EnumConstantDecl(CD, L, Id, T, E, V); +} + +void EnumConstantDecl::Destroy(ASTContext& C) { + if (Init) Init->Destroy(C); + Decl::Destroy(C); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, QualType T) { + return new (C) TypedefDecl(DC, L, Id, T); +} + +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, + EnumDecl *PrevDecl) { + EnumDecl *Enum = new (C) EnumDecl(DC, L, Id); + C.getTypeDeclType(Enum, PrevDecl); + return Enum; +} + +void EnumDecl::Destroy(ASTContext& C) { + Decl::Destroy(C); +} + +void EnumDecl::completeDefinition(ASTContext &C, QualType NewType) { + assert(!isDefinition() && "Cannot redefine enums!"); + IntegerType = NewType; + TagDecl::completeDefinition(); +} + +FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + StringLiteral *Str) { + return new (C) FileScopeAsmDecl(DC, L, Str); +} + +//===----------------------------------------------------------------------===// +// NamedDecl Implementation +//===----------------------------------------------------------------------===// + +std::string NamedDecl::getQualifiedNameAsString() const { + std::vector<std::string> Names; + std::string QualName; + const DeclContext *Ctx = getDeclContext(); + + if (Ctx->isFunctionOrMethod()) + return getNameAsString(); + + while (Ctx) { + if (Ctx->isFunctionOrMethod()) + // FIXME: That probably will happen, when D was member of local + // scope class/struct/union. How do we handle this case? + break; + + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Ctx)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + PrintingPolicy Policy; + Policy.CPlusPlus = true; + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + Names.push_back(Spec->getIdentifier()->getName() + TemplateArgsStr); + } else if (const NamedDecl *ND = dyn_cast<NamedDecl>(Ctx)) + Names.push_back(ND->getNameAsString()); + else + break; + + Ctx = Ctx->getParent(); + } + + std::vector<std::string>::reverse_iterator + I = Names.rbegin(), + End = Names.rend(); + + for (; I!=End; ++I) + QualName += *I + "::"; + + QualName += getNameAsString(); + + return QualName; +} + + +bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { + assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); + + // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. + // We want to keep it, unless it nominates same namespace. + if (getKind() == Decl::UsingDirective) { + return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() == + cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace(); + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) + // For function declarations, we keep track of redeclarations. + return FD->getPreviousDeclaration() == OldD; + + // For method declarations, we keep track of redeclarations. + if (isa<ObjCMethodDecl>(this)) + return false; + + // For non-function declarations, if the declarations are of the + // same kind then this must be a redeclaration, or semantic analysis + // would not have given us the new declaration. + return this->getKind() == OldD->getKind(); +} + +bool NamedDecl::hasLinkage() const { + if (const VarDecl *VD = dyn_cast<VarDecl>(this)) + return VD->hasExternalStorage() || VD->isFileVarDecl(); + + if (isa<FunctionDecl>(this) && !isa<CXXMethodDecl>(this)) + return true; + + return false; +} + +//===----------------------------------------------------------------------===// +// VarDecl Implementation +//===----------------------------------------------------------------------===// + +VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, StorageClass S, + SourceLocation TypeSpecStartLoc) { + return new (C) VarDecl(Var, DC, L, Id, T, S, TypeSpecStartLoc); +} + +void VarDecl::Destroy(ASTContext& C) { + Expr *Init = getInit(); + if (Init) { + Init->Destroy(C); + if (EvaluatedStmt *Eval = this->Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + C.Deallocate(Eval); + } + } + this->~VarDecl(); + C.Deallocate((void *)this); +} + +VarDecl::~VarDecl() { +} + +bool VarDecl::isTentativeDefinition(ASTContext &Context) const { + if (!isFileVarDecl() || Context.getLangOptions().CPlusPlus) + return false; + + const VarDecl *Def = 0; + return (!getDefinition(Def) && + (getStorageClass() == None || getStorageClass() == Static)); +} + +const Expr *VarDecl::getDefinition(const VarDecl *&Def) const { + Def = this; + while (Def && !Def->getInit()) + Def = Def->getPreviousDeclaration(); + + return Def? Def->getInit() : 0; +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Implementation +//===----------------------------------------------------------------------===// + +void FunctionDecl::Destroy(ASTContext& C) { + if (Body && Body.isOffset()) + Body.get(C.getExternalSource())->Destroy(C); + + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) + (*I)->Destroy(C); + + C.Deallocate(ParamInfo); + + Decl::Destroy(C); +} + + +Stmt *FunctionDecl::getBody(ASTContext &Context, + const FunctionDecl *&Definition) const { + for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { + if (FD->Body) { + Definition = FD; + return FD->Body.get(Context.getExternalSource()); + } + } + + return 0; +} + +Stmt *FunctionDecl::getBodyIfAvailable() const { + for (const FunctionDecl *FD = this; FD != 0; FD = FD->PreviousDeclaration) { + if (FD->Body && !FD->Body.isOffset()) { + return FD->Body.get(0); + } + } + + return 0; +} + +bool FunctionDecl::isMain() const { + return getDeclContext()->getLookupContext()->isTranslationUnit() && + getIdentifier() && getIdentifier()->isStr("main"); +} + +bool FunctionDecl::isExternC(ASTContext &Context) const { + // In C, any non-static, non-overloadable function has external + // linkage. + if (!Context.getLangOptions().CPlusPlus) + return getStorageClass() != Static && !getAttr<OverloadableAttr>(); + + for (const DeclContext *DC = getDeclContext(); !DC->isTranslationUnit(); + DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != Static && !getAttr<OverloadableAttr>(); + + break; + } + } + + return false; +} + +bool FunctionDecl::isGlobal() const { + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) + return Method->isStatic(); + + if (getStorageClass() == Static) + return false; + + for (const DeclContext *DC = getDeclContext(); + DC->isNamespace(); + DC = DC->getParent()) { + if (const NamespaceDecl *Namespace = cast<NamespaceDecl>(DC)) { + if (!Namespace->getDeclName()) + return false; + break; + } + } + + return true; +} + +/// \brief Returns a value indicating whether this function +/// corresponds to a builtin function. +/// +/// The function corresponds to a built-in function if it is +/// declared at translation scope or within an extern "C" block and +/// its name matches with the name of a builtin. The returned value +/// will be 0 for functions that do not correspond to a builtin, a +/// value of type \c Builtin::ID if in the target-independent range +/// \c [1,Builtin::First), or a target-specific builtin value. +unsigned FunctionDecl::getBuiltinID(ASTContext &Context) const { + if (!getIdentifier() || !getIdentifier()->getBuiltinID()) + return 0; + + unsigned BuiltinID = getIdentifier()->getBuiltinID(); + if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) + return BuiltinID; + + // This function has the name of a known C library + // function. Determine whether it actually refers to the C library + // function or whether it just has the same name. + + // If this is a static function, it's not a builtin. + if (getStorageClass() == Static) + return 0; + + // If this function is at translation-unit scope and we're not in + // C++, it refers to the C library function. + if (!Context.getLangOptions().CPlusPlus && + getDeclContext()->isTranslationUnit()) + return BuiltinID; + + // If the function is in an extern "C" linkage specification and is + // not marked "overloadable", it's the real function. + if (isa<LinkageSpecDecl>(getDeclContext()) && + cast<LinkageSpecDecl>(getDeclContext())->getLanguage() + == LinkageSpecDecl::lang_c && + !getAttr<OverloadableAttr>()) + return BuiltinID; + + // Not a builtin + return 0; +} + + +/// getNumParams - Return the number of parameters this function must have +/// based on its FunctionType. This is the length of the PararmInfo array +/// after it has been created. +unsigned FunctionDecl::getNumParams() const { + const FunctionType *FT = getType()->getAsFunctionType(); + if (isa<FunctionNoProtoType>(FT)) + return 0; + return cast<FunctionProtoType>(FT)->getNumArgs(); + +} + +void FunctionDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, + unsigned NumParams) { + assert(ParamInfo == 0 && "Already has param info!"); + assert(NumParams == getNumParams() && "Parameter count mismatch!"); + + // Zero params -> null pointer. + if (NumParams) { + void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + ParamInfo = new (Mem) ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + +/// getMinRequiredArguments - Returns the minimum number of arguments +/// needed to call this function. This may be fewer than the number of +/// function parameters, if some of the parameters have default +/// arguments (in C++). +unsigned FunctionDecl::getMinRequiredArguments() const { + unsigned NumRequiredArgs = getNumParams(); + while (NumRequiredArgs > 0 + && getParamDecl(NumRequiredArgs-1)->getDefaultArg()) + --NumRequiredArgs; + + return NumRequiredArgs; +} + +bool FunctionDecl::hasActiveGNUInlineAttribute() const { + if (!isInline() || !hasAttr<GNUInlineAttr>()) + return false; + + for (const FunctionDecl *FD = getPreviousDeclaration(); FD; + FD = FD->getPreviousDeclaration()) { + if (FD->isInline() && !FD->hasAttr<GNUInlineAttr>()) + return false; + } + + return true; +} + +bool FunctionDecl::isExternGNUInline() const { + if (!hasActiveGNUInlineAttribute()) + return false; + + for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDeclaration()) + if (FD->getStorageClass() == Extern && FD->hasAttr<GNUInlineAttr>()) + return true; + + return false; +} + +/// getOverloadedOperator - Which C++ overloaded operator this +/// function represents, if any. +OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { + if (getDeclName().getNameKind() == DeclarationName::CXXOperatorName) + return getDeclName().getCXXOverloadedOperator(); + else + return OO_None; +} + +//===----------------------------------------------------------------------===// +// TagDecl Implementation +//===----------------------------------------------------------------------===// + +void TagDecl::startDefinition() { + TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->getAsTagType()->decl.setInt(1); +} + +void TagDecl::completeDefinition() { + assert((!TypeForDecl || + TypeForDecl->getAsTagType()->decl.getPointer() == this) && + "Attempt to redefine a tag definition?"); + IsDefinition = true; + TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->decl.setInt(0); +} + +TagDecl* TagDecl::getDefinition(ASTContext& C) const { + QualType T = C.getTypeDeclType(const_cast<TagDecl*>(this)); + TagDecl* D = cast<TagDecl>(T->getAsTagType()->getDecl()); + return D->isDefinition() ? D : 0; +} + +//===----------------------------------------------------------------------===// +// RecordDecl Implementation +//===----------------------------------------------------------------------===// + +RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id) + : TagDecl(DK, TK, DC, L, Id) { + HasFlexibleArrayMember = false; + AnonymousStructOrUnion = false; + assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); +} + +RecordDecl *RecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + RecordDecl* PrevDecl) { + + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, L, Id); + C.getTypeDeclType(R, PrevDecl); + return R; +} + +RecordDecl::~RecordDecl() { +} + +void RecordDecl::Destroy(ASTContext& C) { + TagDecl::Destroy(C); +} + +bool RecordDecl::isInjectedClassName() const { + return isImplicit() && getDeclName() && getDeclContext()->isRecord() && + cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); +} + +/// completeDefinition - Notes that the definition of this type is now +/// complete. +void RecordDecl::completeDefinition(ASTContext& C) { + assert(!isDefinition() && "Cannot redefine record!"); + TagDecl::completeDefinition(); +} + +//===----------------------------------------------------------------------===// +// BlockDecl Implementation +//===----------------------------------------------------------------------===// + +BlockDecl::~BlockDecl() { +} + +void BlockDecl::Destroy(ASTContext& C) { + if (Body) + Body->Destroy(C); + + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) + (*I)->Destroy(C); + + C.Deallocate(ParamInfo); + Decl::Destroy(C); +} + +void BlockDecl::setParams(ASTContext& C, ParmVarDecl **NewParamInfo, + unsigned NParms) { + assert(ParamInfo == 0 && "Already has param info!"); + + // Zero params -> null pointer. + if (NParms) { + NumParams = NParms; + void *Mem = C.Allocate(sizeof(ParmVarDecl*)*NumParams); + ParamInfo = new (Mem) ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + +unsigned BlockDecl::getNumParams() const { + return NumParams; +} diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp new file mode 100644 index 0000000..fd7de71 --- /dev/null +++ b/lib/AST/DeclBase.cpp @@ -0,0 +1,756 @@ +//===--- DeclBase.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 and DeclContext classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclContextInternals.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdio> +#include <vector> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Statistics +//===----------------------------------------------------------------------===// + +#define DECL(Derived, Base) static int n##Derived##s = 0; +#include "clang/AST/DeclNodes.def" + +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 && "Declaration not in DeclNodes.def!"); +#define DECL(Derived, Base) case Derived: return #Derived; +#include "clang/AST/DeclNodes.def" + } +} + +const char *DeclContext::getDeclKindName() const { + switch (DeclKind) { + default: assert(0 && "Declaration context not in DeclNodes.def!"); +#define DECL(Derived, Base) case Decl::Derived: return #Derived; +#include "clang/AST/DeclNodes.def" + } +} + +bool Decl::CollectingStats(bool Enable) { + if (Enable) + StatSwitch = true; + return StatSwitch; +} + +void Decl::PrintStats() { + fprintf(stderr, "*** Decl Stats:\n"); + + int totalDecls = 0; +#define DECL(Derived, Base) totalDecls += n##Derived##s; +#include "clang/AST/DeclNodes.def" + fprintf(stderr, " %d decls total.\n", totalDecls); + + int totalBytes = 0; +#define DECL(Derived, Base) \ + if (n##Derived##s > 0) { \ + totalBytes += (int)(n##Derived##s * sizeof(Derived##Decl)); \ + fprintf(stderr, " %d " #Derived " decls, %d each (%d bytes)\n", \ + n##Derived##s, (int)sizeof(Derived##Decl), \ + (int)(n##Derived##s * sizeof(Derived##Decl))); \ + } +#include "clang/AST/DeclNodes.def" + + fprintf(stderr, "Total bytes = %d\n", totalBytes); +} + +void Decl::addDeclKind(Kind k) { + switch (k) { + default: assert(0 && "Declaration not in DeclNodes.def!"); +#define DECL(Derived, Base) case Derived: ++n##Derived##s; break; +#include "clang/AST/DeclNodes.def" + } +} + +//===----------------------------------------------------------------------===// +// PrettyStackTraceDecl Implementation +//===----------------------------------------------------------------------===// + +void PrettyStackTraceDecl::print(llvm::raw_ostream &OS) const { + SourceLocation TheLoc = Loc; + if (TheLoc.isInvalid() && TheDecl) + TheLoc = TheDecl->getLocation(); + + if (TheLoc.isValid()) { + TheLoc.print(OS, SM); + OS << ": "; + } + + OS << Message; + + if (NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) + OS << " '" << DN->getQualifiedNameAsString() << '\''; + OS << '\n'; +} + +//===----------------------------------------------------------------------===// +// Decl Implementation +//===----------------------------------------------------------------------===// + +// Out-of-line virtual method providing a home for Decl. +Decl::~Decl() { + if (isOutOfSemaDC()) + delete getMultipleDC(); + + assert(!HasAttrs && "attributes should have been freed by Destroy"); +} + +void Decl::setDeclContext(DeclContext *DC) { + if (isOutOfSemaDC()) + delete getMultipleDC(); + + DeclCtx = DC; +} + +void Decl::setLexicalDeclContext(DeclContext *DC) { + if (DC == getLexicalDeclContext()) + return; + + if (isInSemaDC()) { + MultipleDC *MDC = new MultipleDC(); + MDC->SemanticDC = getDeclContext(); + MDC->LexicalDC = DC; + DeclCtx = MDC; + } else { + getMultipleDC()->LexicalDC = DC; + } +} + +unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { + switch (DeclKind) { + default: + if (DeclKind >= FunctionFirst && DeclKind <= FunctionLast) + return IDNS_Ordinary; + assert(0 && "Unknown decl kind!"); + case OverloadedFunction: + case Typedef: + case EnumConstant: + case Var: + case ImplicitParam: + case ParmVar: + case OriginalParmVar: + case NonTypeTemplateParm: + case ObjCMethod: + case ObjCContainer: + case ObjCCategory: + case ObjCInterface: + case ObjCProperty: + case ObjCCompatibleAlias: + return IDNS_Ordinary; + + case ObjCProtocol: + return IDNS_ObjCProtocol; + + case ObjCImplementation: + return IDNS_ObjCImplementation; + + case ObjCCategoryImpl: + return IDNS_ObjCCategoryImpl; + + case Field: + case ObjCAtDefsField: + case ObjCIvar: + return IDNS_Member; + + case Record: + case CXXRecord: + case Enum: + case TemplateTypeParm: + return IDNS_Tag; + + case Namespace: + case Template: + case FunctionTemplate: + case ClassTemplate: + case TemplateTemplateParm: + case NamespaceAlias: + return IDNS_Tag | IDNS_Ordinary; + + // Never have names. + case LinkageSpec: + case FileScopeAsm: + case StaticAssert: + case ObjCClass: + case ObjCPropertyImpl: + case ObjCForwardProtocol: + case Block: + case TranslationUnit: + + // Aren't looked up? + case UsingDirective: + case ClassTemplateSpecialization: + case ClassTemplatePartialSpecialization: + return 0; + } +} + +void Decl::addAttr(Attr *NewAttr) { + if (!DeclAttrs) + DeclAttrs = new DeclAttrMapTy(); + + Attr *&ExistingAttr = (*DeclAttrs)[this]; + + NewAttr->setNext(ExistingAttr); + ExistingAttr = NewAttr; + + HasAttrs = true; +} + +void Decl::invalidateAttrs() { + if (!HasAttrs) return; + + HasAttrs = false; + (*DeclAttrs)[this] = 0; + DeclAttrs->erase(this); + + if (DeclAttrs->empty()) { + delete DeclAttrs; + DeclAttrs = 0; + } +} + +const Attr *Decl::getAttrsImpl() const { + assert(HasAttrs && "getAttrs() should verify this!"); + return (*DeclAttrs)[this]; +} + +void Decl::swapAttrs(Decl *RHS) { + bool HasLHSAttr = this->HasAttrs; + bool HasRHSAttr = RHS->HasAttrs; + + // Usually, neither decl has attrs, nothing to do. + if (!HasLHSAttr && !HasRHSAttr) return; + + // If 'this' has no attrs, swap the other way. + if (!HasLHSAttr) + return RHS->swapAttrs(this); + + // Handle the case when both decls have attrs. + if (HasRHSAttr) { + std::swap((*DeclAttrs)[this], (*DeclAttrs)[RHS]); + return; + } + + // Otherwise, LHS has an attr and RHS doesn't. + (*DeclAttrs)[RHS] = (*DeclAttrs)[this]; + (*DeclAttrs).erase(this); + this->HasAttrs = false; + RHS->HasAttrs = true; +} + + +void Decl::Destroy(ASTContext &C) { + // Free attributes for this decl. + if (HasAttrs) { + DeclAttrMapTy::iterator it = DeclAttrs->find(this); + assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); + + // release attributes. + it->second->Destroy(C); + invalidateAttrs(); + HasAttrs = false; + } + +#if 0 + // FIXME: Once ownership is fully understood, we can enable this code + if (DeclContext *DC = dyn_cast<DeclContext>(this)) + DC->decls_begin()->Destroy(C); + + // Observe the unrolled recursion. By setting N->NextDeclInContext = 0x0 + // within the loop, only the Destroy method for the first Decl + // will deallocate all of the Decls in a chain. + + Decl* N = getNextDeclInContext(); + + while (N) { + Decl* Tmp = N->getNextDeclInContext(); + N->NextDeclInContext = 0; + N->Destroy(C); + N = Tmp; + } + + this->~Decl(); + C.Deallocate((void *)this); +#endif +} + +Decl *Decl::castFromDeclContext (const DeclContext *D) { + Decl::Kind DK = D->getDeclKind(); + switch(DK) { +#define DECL_CONTEXT(Name) \ + case Decl::Name: \ + return static_cast<Name##Decl*>(const_cast<DeclContext*>(D)); +#define DECL_CONTEXT_BASE(Name) +#include "clang/AST/DeclNodes.def" + default: +#define DECL_CONTEXT_BASE(Name) \ + if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \ + return static_cast<Name##Decl*>(const_cast<DeclContext*>(D)); +#include "clang/AST/DeclNodes.def" + assert(false && "a decl that inherits DeclContext isn't handled"); + return 0; + } +} + +DeclContext *Decl::castToDeclContext(const Decl *D) { + Decl::Kind DK = D->getKind(); + switch(DK) { +#define DECL_CONTEXT(Name) \ + case Decl::Name: \ + return static_cast<Name##Decl*>(const_cast<Decl*>(D)); +#define DECL_CONTEXT_BASE(Name) +#include "clang/AST/DeclNodes.def" + default: +#define DECL_CONTEXT_BASE(Name) \ + if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \ + return static_cast<Name##Decl*>(const_cast<Decl*>(D)); +#include "clang/AST/DeclNodes.def" + assert(false && "a decl that inherits DeclContext isn't handled"); + return 0; + } +} + +CompoundStmt* Decl::getCompoundBody(ASTContext &Context) const { + return dyn_cast_or_null<CompoundStmt>(getBody(Context)); +} + +SourceLocation Decl::getBodyRBrace(ASTContext &Context) const { + Stmt *Body = getBody(Context); + if (!Body) + return SourceLocation(); + if (CompoundStmt *CS = dyn_cast<CompoundStmt>(Body)) + return CS->getRBracLoc(); + assert(isa<CXXTryStmt>(Body) && + "Body can only be CompoundStmt or CXXTryStmt"); + return cast<CXXTryStmt>(Body)->getSourceRange().getEnd(); +} + +#ifndef NDEBUG +void Decl::CheckAccessDeclContext() const { + assert((Access != AS_none || isa<TranslationUnitDecl>(this) || + !isa<CXXRecordDecl>(getDeclContext())) && + "Access specifier is AS_none inside a record decl"); +} + +#endif + +//===----------------------------------------------------------------------===// +// DeclContext Implementation +//===----------------------------------------------------------------------===// + +bool DeclContext::classof(const Decl *D) { + switch (D->getKind()) { +#define DECL_CONTEXT(Name) case Decl::Name: +#define DECL_CONTEXT_BASE(Name) +#include "clang/AST/DeclNodes.def" + return true; + default: +#define DECL_CONTEXT_BASE(Name) \ + if (D->getKind() >= Decl::Name##First && \ + D->getKind() <= Decl::Name##Last) \ + return true; +#include "clang/AST/DeclNodes.def" + return false; + } +} + +DeclContext::~DeclContext() { + delete static_cast<StoredDeclsMap*>(LookupPtr); +} + +void DeclContext::DestroyDecls(ASTContext &C) { + for (decl_iterator D = decls_begin(C); D != decls_end(C); ) + (*D++)->Destroy(C); +} + +bool DeclContext::isDependentContext() const { + if (isFileContext()) + return false; + + if (isa<ClassTemplatePartialSpecializationDecl>(this)) + return true; + + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) + if (Record->getDescribedClassTemplate()) + return true; + + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) + if (Function->getDescribedFunctionTemplate()) + return true; + + return getParent() && getParent()->isDependentContext(); +} + +bool DeclContext::isTransparentContext() const { + if (DeclKind == Decl::Enum) + return true; // FIXME: Check for C++0x scoped enums + else if (DeclKind == Decl::LinkageSpec) + return true; + else if (DeclKind >= Decl::RecordFirst && DeclKind <= Decl::RecordLast) + return cast<RecordDecl>(this)->isAnonymousStructOrUnion(); + else if (DeclKind == Decl::Namespace) + return false; // FIXME: Check for C++0x inline namespaces + + return false; +} + +DeclContext *DeclContext::getPrimaryContext() { + switch (DeclKind) { + case Decl::TranslationUnit: + case Decl::LinkageSpec: + case Decl::Block: + // There is only one DeclContext for these entities. + return this; + + case Decl::Namespace: + // The original namespace is our primary context. + return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); + + case Decl::ObjCMethod: + return this; + + case Decl::ObjCInterface: + case Decl::ObjCProtocol: + case Decl::ObjCCategory: + // FIXME: Can Objective-C interfaces be forward-declared? + return this; + + case Decl::ObjCImplementation: + case Decl::ObjCCategoryImpl: + return this; + + default: + if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { + // If this is a tag type that has a definition or is currently + // being defined, that definition is our primary context. + if (const TagType *TagT =cast<TagDecl>(this)->TypeForDecl->getAsTagType()) + if (TagT->isBeingDefined() || + (TagT->getDecl() && TagT->getDecl()->isDefinition())) + return TagT->getDecl(); + return this; + } + + assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast && + "Unknown DeclContext kind"); + return this; + } +} + +DeclContext *DeclContext::getNextContext() { + switch (DeclKind) { + case Decl::Namespace: + // Return the next namespace + return static_cast<NamespaceDecl*>(this)->getNextNamespace(); + + default: + return 0; + } +} + +/// \brief Load the declarations within this lexical storage from an +/// external source. +void +DeclContext::LoadLexicalDeclsFromExternalStorage(ASTContext &Context) const { + ExternalASTSource *Source = Context.getExternalSource(); + assert(hasExternalLexicalStorage() && Source && "No external storage?"); + + llvm::SmallVector<uint32_t, 64> Decls; + if (Source->ReadDeclsLexicallyInContext(const_cast<DeclContext *>(this), + Decls)) + return; + + // There is no longer any lexical storage in this context + ExternalLexicalStorage = false; + + if (Decls.empty()) + return; + + // Resolve all of the declaration IDs into declarations, building up + // a chain of declarations via the Decl::NextDeclInContext field. + Decl *FirstNewDecl = 0; + Decl *PrevDecl = 0; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + Decl *D = Source->GetDecl(Decls[I]); + if (PrevDecl) + PrevDecl->NextDeclInContext = D; + else + FirstNewDecl = D; + + PrevDecl = D; + } + + // Splice the newly-read declarations into the beginning of the list + // of declarations. + PrevDecl->NextDeclInContext = FirstDecl; + FirstDecl = FirstNewDecl; + if (!LastDecl) + LastDecl = PrevDecl; +} + +void +DeclContext::LoadVisibleDeclsFromExternalStorage(ASTContext &Context) const { + DeclContext *This = const_cast<DeclContext *>(this); + ExternalASTSource *Source = Context.getExternalSource(); + assert(hasExternalVisibleStorage() && Source && "No external storage?"); + + llvm::SmallVector<VisibleDeclaration, 64> Decls; + if (Source->ReadDeclsVisibleInContext(This, Decls)) + return; + + // There is no longer any visible storage in this context + ExternalVisibleStorage = false; + + // Load the declaration IDs for all of the names visible in this + // context. + assert(!LookupPtr && "Have a lookup map before de-serialization?"); + StoredDeclsMap *Map = new StoredDeclsMap; + LookupPtr = Map; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + (*Map)[Decls[I].Name].setFromDeclIDs(Decls[I].Declarations); + } +} + +DeclContext::decl_iterator DeclContext::decls_begin(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + + // FIXME: Check whether we need to load some declarations from + // external storage. + return decl_iterator(FirstDecl); +} + +DeclContext::decl_iterator DeclContext::decls_end(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + + return decl_iterator(); +} + +bool DeclContext::decls_empty(ASTContext &Context) const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(Context); + + return !FirstDecl; +} + +void DeclContext::addDecl(ASTContext &Context, Decl *D) { + assert(D->getLexicalDeclContext() == this && + "Decl inserted into wrong lexical context"); + assert(!D->getNextDeclInContext() && D != LastDecl && + "Decl already inserted into a DeclContext"); + + if (FirstDecl) { + LastDecl->NextDeclInContext = D; + LastDecl = D; + } else { + FirstDecl = LastDecl = D; + } + + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + ND->getDeclContext()->makeDeclVisibleInContext(Context, ND); +} + +/// buildLookup - Build the lookup data structure with all of the +/// declarations in DCtx (and any other contexts linked to it or +/// transparent contexts nested within it). +void DeclContext::buildLookup(ASTContext &Context, DeclContext *DCtx) { + for (; DCtx; DCtx = DCtx->getNextContext()) { + for (decl_iterator D = DCtx->decls_begin(Context), + DEnd = DCtx->decls_end(Context); + D != DEnd; ++D) { + // Insert this declaration into the lookup structure + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + makeDeclVisibleInContextImpl(Context, ND); + + // If this declaration is itself a transparent declaration context, + // add its members (recursively). + if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) + if (InnerCtx->isTransparentContext()) + buildLookup(Context, InnerCtx->getPrimaryContext()); + } + } +} + +DeclContext::lookup_result +DeclContext::lookup(ASTContext &Context, DeclarationName Name) { + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) + return PrimaryContext->lookup(Context, Name); + + if (hasExternalVisibleStorage()) + LoadVisibleDeclsFromExternalStorage(Context); + + /// If there is no lookup data structure, build one now by walking + /// all of the linked DeclContexts (in declaration order!) and + /// inserting their values. + if (!LookupPtr) { + buildLookup(Context, this); + + if (!LookupPtr) + return lookup_result(0, 0); + } + + StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr); + StoredDeclsMap::iterator Pos = Map->find(Name); + if (Pos == Map->end()) + return lookup_result(0, 0); + return Pos->second.getLookupResult(Context); +} + +DeclContext::lookup_const_result +DeclContext::lookup(ASTContext &Context, DeclarationName Name) const { + return const_cast<DeclContext*>(this)->lookup(Context, Name); +} + +DeclContext *DeclContext::getLookupContext() { + DeclContext *Ctx = this; + // Skip through transparent contexts. + while (Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + return Ctx; +} + +DeclContext *DeclContext::getEnclosingNamespaceContext() { + DeclContext *Ctx = this; + // Skip through non-namespace, non-translation-unit contexts. + while (!Ctx->isFileContext() || Ctx->isTransparentContext()) + Ctx = Ctx->getParent(); + return Ctx->getPrimaryContext(); +} + +void DeclContext::makeDeclVisibleInContext(ASTContext &Context, NamedDecl *D) { + // FIXME: This feels like a hack. Should DeclarationName support + // template-ids, or is there a better way to keep specializations + // from being visible? + if (isa<ClassTemplateSpecializationDecl>(D)) + return; + + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) { + PrimaryContext->makeDeclVisibleInContext(Context, D); + return; + } + + // If we already have a lookup data structure, perform the insertion + // into it. Otherwise, be lazy and don't build that structure until + // someone asks for it. + if (LookupPtr) + makeDeclVisibleInContextImpl(Context, D); + + // If we are a transparent context, insert into our parent context, + // too. This operation is recursive. + if (isTransparentContext()) + getParent()->makeDeclVisibleInContext(Context, D); +} + +void DeclContext::makeDeclVisibleInContextImpl(ASTContext &Context, + NamedDecl *D) { + // Skip unnamed declarations. + if (!D->getDeclName()) + return; + + // FIXME: This feels like a hack. Should DeclarationName support + // template-ids, or is there a better way to keep specializations + // from being visible? + if (isa<ClassTemplateSpecializationDecl>(D)) + return; + + if (!LookupPtr) + LookupPtr = new StoredDeclsMap; + + // Insert this declaration into the map. + StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr); + StoredDeclsList &DeclNameEntries = Map[D->getDeclName()]; + if (DeclNameEntries.isNull()) { + DeclNameEntries.setOnlyValue(D); + return; + } + + // If it is possible that this is a redeclaration, check to see if there is + // already a decl for which declarationReplaces returns true. If there is + // one, just replace it and return. + if (DeclNameEntries.HandleRedeclaration(Context, D)) + return; + + // Put this declaration into the appropriate slot. + DeclNameEntries.AddSubsequentDecl(D); +} + +/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within +/// this context. +DeclContext::udir_iterator_range +DeclContext::getUsingDirectives(ASTContext &Context) const { + lookup_const_result Result = lookup(Context, UsingDirectiveDecl::getName()); + return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), + reinterpret_cast<udir_iterator>(Result.second)); +} + +void StoredDeclsList::materializeDecls(ASTContext &Context) { + if (isNull()) + return; + + switch ((DataKind)(Data & 0x03)) { + case DK_Decl: + case DK_Decl_Vector: + break; + + case DK_DeclID: { + // Resolve this declaration ID to an actual declaration by + // querying the external AST source. + unsigned DeclID = Data >> 2; + + ExternalASTSource *Source = Context.getExternalSource(); + assert(Source && "No external AST source available!"); + + Data = reinterpret_cast<uintptr_t>(Source->GetDecl(DeclID)); + break; + } + + case DK_ID_Vector: { + // We have a vector of declaration IDs. Resolve all of them to + // actual declarations. + VectorTy &Vector = *getAsVector(); + ExternalASTSource *Source = Context.getExternalSource(); + assert(Source && "No external AST source available!"); + + for (unsigned I = 0, N = Vector.size(); I != N; ++I) + Vector[I] = reinterpret_cast<uintptr_t>(Source->GetDecl(Vector[I])); + + Data = (Data & ~0x03) | DK_Decl_Vector; + break; + } + } +} diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp new file mode 100644 index 0000000..19f8958 --- /dev/null +++ b/lib/AST/DeclCXX.cpp @@ -0,0 +1,462 @@ +//===--- DeclCXX.cpp - C++ 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 C++ related Decl classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id) + : RecordDecl(K, TK, DC, L, Id), + UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), + UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), + Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false), + HasTrivialConstructor(true), HasTrivialDestructor(true), + Bases(0), NumBases(0), Conversions(DC, DeclarationName()), + TemplateOrInstantiation() { } + +CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + CXXRecordDecl* PrevDecl, + bool DelayTypeCreation) { + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id); + if (!DelayTypeCreation) + C.getTypeDeclType(R, PrevDecl); + return R; +} + +CXXRecordDecl::~CXXRecordDecl() { + delete [] Bases; +} + +void +CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, + unsigned NumBases) { + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with [...] + // no base classes [...]. + Aggregate = false; + + if (this->Bases) + delete [] this->Bases; + + // FIXME: allocate using the ASTContext + this->Bases = new CXXBaseSpecifier[NumBases]; + this->NumBases = NumBases; + for (unsigned i = 0; i < NumBases; ++i) + this->Bases[i] = *Bases[i]; +} + +bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { + QualType ClassType + = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType)); + unsigned TypeQuals; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName); + Con != ConEnd; ++Con) { + if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) && + (TypeQuals & QualType::Const) != 0) + return true; + } + + return false; +} + +bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast<CXXRecordDecl*>(this))); + DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); + + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName); + Op != OpEnd; ++Op) { + // C++ [class.copy]p9: + // A user-declared copy assignment operator is a non-static non-template + // member function of class X with exactly one parameter of type X, X&, + // const X&, volatile X& or const volatile X&. + const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); + if (Method->isStatic()) + continue; + // TODO: Skip templates? Or is this implicitly done due to parameter types? + const FunctionProtoType *FnType = + Method->getType()->getAsFunctionProtoType(); + assert(FnType && "Overloaded operator has no prototype."); + // Don't assert on this; an invalid decl might have been left in the AST. + if (FnType->getNumArgs() != 1 || FnType->isVariadic()) + continue; + bool AcceptsConst = true; + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) { + ArgType = Ref->getPointeeType(); + // Is it a non-const lvalue reference? + if (!ArgType.isConstQualified()) + AcceptsConst = false; + } + if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) + continue; + + // We have a single argument of type cv X or cv X&, i.e. we've found the + // copy assignment operator. Return whether it accepts const arguments. + return AcceptsConst; + } + assert(isInvalidDecl() && + "No copy assignment operator declared in valid code."); + return false; +} + +void +CXXRecordDecl::addedConstructor(ASTContext &Context, + CXXConstructorDecl *ConDecl) { + if (!ConDecl->isImplicit()) { + // Note that we have a user-declared constructor. + UserDeclaredConstructor = true; + + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with no + // user-declared constructors (12.1) [...]. + Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + PlainOldData = false; + + // C++ [class.ctor]p5: + // A constructor is trivial if it is an implicitly-declared default + // constructor. + HasTrivialConstructor = false; + + // Note when we have a user-declared copy constructor, which will + // suppress the implicit declaration of a copy constructor. + if (ConDecl->isCopyConstructor(Context)) + UserDeclaredCopyConstructor = true; + } +} + +void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, + CXXMethodDecl *OpDecl) { + // We're interested specifically in copy assignment operators. + // Unlike addedConstructor, this method is not called for implicit + // declarations. + const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); + assert(FnType && "Overloaded operator has no proto function type."); + assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); + QualType ArgType = FnType->getArgType(0); + if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) + ArgType = Ref->getPointeeType(); + + ArgType = ArgType.getUnqualifiedType(); + QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( + const_cast<CXXRecordDecl*>(this))); + + if (ClassType != Context.getCanonicalType(ArgType)) + return; + + // This is a copy assignment operator. + // Suppress the implicit declaration of a copy constructor. + UserDeclaredCopyAssignment = true; + + // C++ [class]p4: + // A POD-struct is an aggregate class that [...] has no user-defined copy + // assignment operator [...]. + PlainOldData = false; +} + +void CXXRecordDecl::addConversionFunction(ASTContext &Context, + CXXConversionDecl *ConvDecl) { + Conversions.addOverload(ConvDecl); +} + +const CXXDestructorDecl * +CXXRecordDecl::getDestructor(ASTContext &Context) { + QualType ClassType = Context.getTypeDeclType(this); + + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName(ClassType); + + DeclContext::lookup_iterator I, E; + llvm::tie(I, E) = lookup(Context, Name); + assert(I != E && "Did not find a destructor!"); + + const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); + assert(++I == E && "Found more than one destructor!"); + + return Dtor; +} + +CXXMethodDecl * +CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isStatic, bool isInline) { + return new (C) CXXMethodDecl(CXXMethod, RD, L, N, T, isStatic, isInline); +} + + +typedef llvm::DenseMap<const CXXMethodDecl*, + std::vector<const CXXMethodDecl *> *> + OverriddenMethodsMapTy; + +static OverriddenMethodsMapTy *OverriddenMethods = 0; + +void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { + // FIXME: The CXXMethodDecl dtor needs to remove and free the entry. + + if (!OverriddenMethods) + OverriddenMethods = new OverriddenMethodsMapTy(); + + std::vector<const CXXMethodDecl *> *&Methods = (*OverriddenMethods)[this]; + if (!Methods) + Methods = new std::vector<const CXXMethodDecl *>; + + Methods->push_back(MD); +} + +CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { + if (!OverriddenMethods) + return 0; + + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); + if (it == OverriddenMethods->end()) + return 0; + return &(*it->second)[0]; +} + +CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { + if (!OverriddenMethods) + return 0; + + OverriddenMethodsMapTy::iterator it = OverriddenMethods->find(this); + if (it == OverriddenMethods->end()) + return 0; + + return &(*it->second)[it->second->size()]; +} + +QualType CXXMethodDecl::getThisType(ASTContext &C) const { + // C++ 9.3.2p1: The type of this in a member function of a class X is X*. + // If the member function is declared const, the type of this is const X*, + // if the member function is declared volatile, the type of this is + // volatile X*, and if the member function is declared const volatile, + // the type of this is const volatile X*. + + assert(isInstance() && "No 'this' for static methods!"); + QualType ClassTy = C.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); + ClassTy = ClassTy.getWithAdditionalQualifiers(getTypeQualifiers()); + return C.getPointerType(ClassTy).withConst(); +} + +CXXBaseOrMemberInitializer:: +CXXBaseOrMemberInitializer(QualType BaseType, Expr **Args, unsigned NumArgs) + : Args(0), NumArgs(0) { + BaseOrMember = reinterpret_cast<uintptr_t>(BaseType.getTypePtr()); + assert((BaseOrMember & 0x01) == 0 && "Invalid base class type pointer"); + BaseOrMember |= 0x01; + + if (NumArgs > 0) { + this->NumArgs = NumArgs; + this->Args = new Expr*[NumArgs]; + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + this->Args[Idx] = Args[Idx]; + } +} + +CXXBaseOrMemberInitializer:: +CXXBaseOrMemberInitializer(FieldDecl *Member, Expr **Args, unsigned NumArgs) + : Args(0), NumArgs(0) { + BaseOrMember = reinterpret_cast<uintptr_t>(Member); + assert((BaseOrMember & 0x01) == 0 && "Invalid member pointer"); + + if (NumArgs > 0) { + this->NumArgs = NumArgs; + this->Args = new Expr*[NumArgs]; + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + this->Args[Idx] = Args[Idx]; + } +} + +CXXBaseOrMemberInitializer::~CXXBaseOrMemberInitializer() { + delete [] Args; +} + +CXXConstructorDecl * +CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isExplicit, + bool isInline, bool isImplicitlyDeclared) { + assert(N.getNameKind() == DeclarationName::CXXConstructorName && + "Name must refer to a constructor"); + return new (C) CXXConstructorDecl(RD, L, N, T, isExplicit, isInline, + isImplicitlyDeclared); +} + +bool CXXConstructorDecl::isDefaultConstructor() const { + // C++ [class.ctor]p5: + // A default constructor for a class X is a constructor of class + // X that can be called without an argument. + return (getNumParams() == 0) || + (getNumParams() > 0 && getParamDecl(0)->getDefaultArg() != 0); +} + +bool +CXXConstructorDecl::isCopyConstructor(ASTContext &Context, + unsigned &TypeQuals) const { + // C++ [class.copy]p2: + // A non-template constructor for class X is a copy constructor + // if its first parameter is of type X&, const X&, volatile X& or + // const volatile X&, and either there are no other parameters + // or else all other parameters have default arguments (8.3.6). + if ((getNumParams() < 1) || + (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0)) + return false; + + const ParmVarDecl *Param = getParamDecl(0); + + // Do we have a reference type? Rvalue references don't count. + const LValueReferenceType *ParamRefType = + Param->getType()->getAsLValueReferenceType(); + if (!ParamRefType) + return false; + + // Is it a reference to our class type? + QualType PointeeType + = Context.getCanonicalType(ParamRefType->getPointeeType()); + QualType ClassTy + = Context.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); + if (PointeeType.getUnqualifiedType() != ClassTy) + return false; + + // We have a copy constructor. + TypeQuals = PointeeType.getCVRQualifiers(); + return true; +} + +bool CXXConstructorDecl::isConvertingConstructor() const { + // C++ [class.conv.ctor]p1: + // A constructor declared without the function-specifier explicit + // that can be called with a single parameter specifies a + // conversion from the type of its first parameter to the type of + // its class. Such a constructor is called a converting + // constructor. + if (isExplicit()) + return false; + + return (getNumParams() == 0 && + getType()->getAsFunctionProtoType()->isVariadic()) || + (getNumParams() == 1) || + (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() != 0); +} + +CXXDestructorDecl * +CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isInline, + bool isImplicitlyDeclared) { + assert(N.getNameKind() == DeclarationName::CXXDestructorName && + "Name must refer to a destructor"); + return new (C) CXXDestructorDecl(RD, L, N, T, isInline, + isImplicitlyDeclared); +} + +CXXConversionDecl * +CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation L, DeclarationName N, + QualType T, bool isInline, bool isExplicit) { + assert(N.getNameKind() == DeclarationName::CXXConversionFunctionName && + "Name must refer to a conversion function"); + return new (C) CXXConversionDecl(RD, L, N, T, isInline, isExplicit); +} + +OverloadedFunctionDecl * +OverloadedFunctionDecl::Create(ASTContext &C, DeclContext *DC, + DeclarationName N) { + return new (C) OverloadedFunctionDecl(DC, N); +} + +LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + LanguageIDs Lang, bool Braces) { + return new (C) LinkageSpecDecl(DC, L, Lang, Braces); +} + +UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamespaceDecl *Used, + DeclContext *CommonAncestor) { + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierRange, + Qualifier, IdentLoc, Used, CommonAncestor); +} + +NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + SourceRange QualifierRange, + NestedNameSpecifier *Qualifier, + SourceLocation IdentLoc, + NamedDecl *Namespace) { + return new (C) NamespaceAliasDecl(DC, L, AliasLoc, Alias, QualifierRange, + Qualifier, IdentLoc, Namespace); +} + +StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, Expr *AssertExpr, + StringLiteral *Message) { + return new (C) StaticAssertDecl(DC, L, AssertExpr, Message); +} + +void StaticAssertDecl::Destroy(ASTContext& C) { + AssertExpr->Destroy(C); + Message->Destroy(C); + this->~StaticAssertDecl(); + C.Deallocate((void *)this); +} + +StaticAssertDecl::~StaticAssertDecl() { +} + +static const char *getAccessName(AccessSpecifier AS) { + switch (AS) { + default: + case AS_none: + assert("Invalid access specifier!"); + return 0; + case AS_public: + return "public"; + case AS_private: + return "private"; + case AS_protected: + return "protected"; + } +} + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + AccessSpecifier AS) { + return DB << getAccessName(AS); +} + + diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp new file mode 100644 index 0000000..5bdc881 --- /dev/null +++ b/lib/AST/DeclGroup.cpp @@ -0,0 +1,37 @@ +//===--- DeclGroup.cpp - Classes for representing groups 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 the DeclGroup and DeclGroupRef classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclGroup.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ASTContext.h" +#include "llvm/Support/Allocator.h" +using namespace clang; + +DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { + assert(NumDecls > 1 && "Invalid DeclGroup"); + unsigned Size = sizeof(DeclGroup) + sizeof(Decl*) * NumDecls; + void* Mem = C.Allocate(Size, llvm::AlignOf<DeclGroup>::Alignment); + new (Mem) DeclGroup(NumDecls, Decls); + return static_cast<DeclGroup*>(Mem); +} + +DeclGroup::DeclGroup(unsigned numdecls, Decl** decls) : NumDecls(numdecls) { + assert(numdecls > 0); + assert(decls); + memcpy(this+1, decls, numdecls * sizeof(*decls)); +} + +void DeclGroup::Destroy(ASTContext& C) { + this->~DeclGroup(); + C.Deallocate((void*) this); +} diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp new file mode 100644 index 0000000..f4bb895 --- /dev/null +++ b/lib/AST/DeclObjC.cpp @@ -0,0 +1,693 @@ +//===--- DeclObjC.cpp - ObjC 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 Objective-C related Decl classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclObjC.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Stmt.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// ObjCListBase +//===----------------------------------------------------------------------===// + +void ObjCListBase::Destroy(ASTContext &Ctx) { + Ctx.Deallocate(List); + NumElts = 0; + List = 0; +} + +void ObjCListBase::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { + assert(List == 0 && "Elements already set!"); + if (Elts == 0) return; // Setting to an empty list is a noop. + + + List = new (Ctx) void*[Elts]; + NumElts = Elts; + memcpy(List, InList, sizeof(void*)*Elts); +} + + +//===----------------------------------------------------------------------===// +// ObjCInterfaceDecl +//===----------------------------------------------------------------------===// + +// Get the local instance method declared in this interface. +ObjCMethodDecl * +ObjCContainerDecl::getInstanceMethod(ASTContext &Context, Selector Sel) const { + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod()) + return MD; + } + return 0; +} + +// Get the local class method declared in this interface. +ObjCMethodDecl * +ObjCContainerDecl::getClassMethod(ASTContext &Context, Selector Sel) const { + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isClassMethod()) + return MD; + } + return 0; +} + +/// FindPropertyDeclaration - Finds declaration of the property given its name +/// in 'PropertyId' and returns it. It returns 0, if not found. +/// FIXME: Convert to DeclContext lookup... +/// +ObjCPropertyDecl * +ObjCContainerDecl::FindPropertyDeclaration(ASTContext &Context, + IdentifierInfo *PropertyId) const { + for (prop_iterator I = prop_begin(Context), E = prop_end(Context); + I != E; ++I) + if ((*I)->getIdentifier() == PropertyId) + return *I; + + const ObjCProtocolDecl *PID = dyn_cast<ObjCProtocolDecl>(this); + if (PID) { + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context, + PropertyId)) + return P; + } + + if (const ObjCInterfaceDecl *OID = dyn_cast<ObjCInterfaceDecl>(this)) { + // Look through categories. + for (ObjCCategoryDecl *Category = OID->getCategoryList(); + Category; Category = Category->getNextClassCategory()) { + if (ObjCPropertyDecl *P = Category->FindPropertyDeclaration(Context, + PropertyId)) + return P; + } + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = OID->protocol_begin(), + E = OID->protocol_end(); I != E; ++I) { + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context, + PropertyId)) + return P; + } + if (OID->getSuperClass()) + return OID->getSuperClass()->FindPropertyDeclaration(Context, + PropertyId); + } else if (const ObjCCategoryDecl *OCD = dyn_cast<ObjCCategoryDecl>(this)) { + // Look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = OCD->protocol_begin(), + E = OCD->protocol_end(); I != E; ++I) { + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(Context, + PropertyId)) + return P; + } + } + return 0; +} + +ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable( + ASTContext &Context, 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; + } + } + // look into properties. + for (ObjCInterfaceDecl::prop_iterator I = ClassDecl->prop_begin(Context), + E = ClassDecl->prop_end(Context); I != E; ++I) { + ObjCPropertyDecl *PDecl = (*I); + if (ObjCIvarDecl *IV = PDecl->getPropertyIvarDecl()) + if (IV->getIdentifier() == ID) { + clsDeclared = ClassDecl; + return IV; + } + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +/// lookupInheritedClass - This method returns ObjCInterfaceDecl * of the super +/// class whose name is passed as argument. If it is not one of the super classes +/// the it returns NULL. +ObjCInterfaceDecl *ObjCInterfaceDecl::lookupInheritedClass( + const IdentifierInfo*ICName) { + ObjCInterfaceDecl* ClassDecl = this; + while (ClassDecl != NULL) { + if (ClassDecl->getIdentifier() == ICName) + return ClassDecl; + 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(ASTContext &Context, + Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getInstanceMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + const ObjCList<ObjCProtocolDecl> &Protocols = + ClassDecl->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupInstanceMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getInstanceMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + const ObjCList<ObjCProtocolDecl> &Protocols = + CatDecl->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupInstanceMethod(Context, 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(ASTContext &Context, + Selector Sel) { + ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getClassMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + for (ObjCInterfaceDecl::protocol_iterator I = ClassDecl->protocol_begin(), + E = ClassDecl->protocol_end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getClassMethod(Context, Sel))) + return MethodDecl; + + // Didn't find one yet - look through protocols. + const ObjCList<ObjCProtocolDecl> &Protocols = + CatDecl->getReferencedProtocols(); + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + + + +//===----------------------------------------------------------------------===// +// ObjCMethodDecl +//===----------------------------------------------------------------------===// + +ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, + SourceLocation beginLoc, + SourceLocation endLoc, + Selector SelInfo, QualType T, + DeclContext *contextDecl, + bool isInstance, + bool isVariadic, + bool isSynthesized, + ImplementationControl impControl) { + return new (C) ObjCMethodDecl(beginLoc, endLoc, + SelInfo, T, contextDecl, + isInstance, + isVariadic, isSynthesized, impControl); +} + +void ObjCMethodDecl::Destroy(ASTContext &C) { + if (Body) Body->Destroy(C); + if (SelfDecl) SelfDecl->Destroy(C); + + for (param_iterator I=param_begin(), E=param_end(); I!=E; ++I) + if (*I) (*I)->Destroy(C); + + ParamInfo.Destroy(C); + + Decl::Destroy(C); +} + +void ObjCMethodDecl::createImplicitParams(ASTContext &Context, + const ObjCInterfaceDecl *OID) { + QualType selfTy; + if (isInstanceMethod()) { + // There may be no interface context due to error in declaration + // of the interface (which has been reported). Recover gracefully. + if (OID) { + selfTy = Context.getObjCInterfaceType(OID); + selfTy = Context.getPointerType(selfTy); + } else { + selfTy = Context.getObjCIdType(); + } + } else // we have a factory method. + selfTy = Context.getObjCClassType(); + + setSelfDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("self"), selfTy)); + + setCmdDecl(ImplicitParamDecl::Create(Context, this, SourceLocation(), + &Context.Idents.get("_cmd"), + Context.getObjCSelType())); +} + + + +/// 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 += getClassInterface()->getNameAsString().size()+1; // extra for _ + if (const ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(getDeclContext())) + length += CID->getNameAsString().size()+1; + length += getSelector().getAsString().size(); // selector name + return length; +} + +ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext())) + return ID; + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext())) + return CD->getClassInterface(); + if (ObjCImplementationDecl *IMD = + dyn_cast<ObjCImplementationDecl>(getDeclContext())) + return IMD->getClassInterface(); + if (ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(getDeclContext())) + return CID->getClassInterface(); + assert(false && "unknown method context"); + return 0; +} + +//===----------------------------------------------------------------------===// +// ObjCInterfaceDecl +//===----------------------------------------------------------------------===// + +ObjCInterfaceDecl *ObjCInterfaceDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation atLoc, + IdentifierInfo *Id, + SourceLocation ClassLoc, + bool ForwardDecl, bool isInternal){ + return new (C) ObjCInterfaceDecl(DC, atLoc, Id, ClassLoc, ForwardDecl, + isInternal); +} + +ObjCInterfaceDecl:: +ObjCInterfaceDecl(DeclContext *DC, SourceLocation atLoc, IdentifierInfo *Id, + SourceLocation CLoc, bool FD, bool isInternal) + : ObjCContainerDecl(ObjCInterface, DC, atLoc, Id), + TypeForDecl(0), SuperClass(0), + CategoryList(0), ForwardDecl(FD), InternalInterface(isInternal), + ClassLoc(CLoc) { +} + +void ObjCInterfaceDecl::Destroy(ASTContext &C) { + for (ivar_iterator I = ivar_begin(), E = ivar_end(); I != E; ++I) + if (*I) (*I)->Destroy(C); + + IVars.Destroy(C); + // FIXME: CategoryList? + + // FIXME: Because there is no clear ownership + // role between ObjCInterfaceDecls and the ObjCPropertyDecls that they + // reference, we destroy ObjCPropertyDecls in ~TranslationUnit. + Decl::Destroy(C); +} + + +/// FindCategoryDeclaration - Finds category declaration in the list of +/// categories for this class and returns it. Name of the category is passed +/// in 'CategoryId'. If category not found, return 0; +/// +ObjCCategoryDecl * +ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (Category->getIdentifier() == CategoryId) + return Category; + return 0; +} + +//===----------------------------------------------------------------------===// +// ObjCIvarDecl +//===----------------------------------------------------------------------===// + +ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, IdentifierInfo *Id, + QualType T, AccessControl ac, Expr *BW) { + return new (C) ObjCIvarDecl(DC, L, Id, T, ac, BW); +} + + + +//===----------------------------------------------------------------------===// +// ObjCAtDefsFieldDecl +//===----------------------------------------------------------------------===// + +ObjCAtDefsFieldDecl +*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, Expr *BW) { + return new (C) ObjCAtDefsFieldDecl(DC, L, Id, T, BW); +} + +void ObjCAtDefsFieldDecl::Destroy(ASTContext& C) { + this->~ObjCAtDefsFieldDecl(); + C.Deallocate((void *)this); +} + +//===----------------------------------------------------------------------===// +// ObjCProtocolDecl +//===----------------------------------------------------------------------===// + +ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id) { + return new (C) ObjCProtocolDecl(DC, L, Id); +} + +void ObjCProtocolDecl::Destroy(ASTContext &C) { + ReferencedProtocols.Destroy(C); + ObjCContainerDecl::Destroy(C); +} + +ObjCProtocolDecl *ObjCProtocolDecl::lookupProtocolNamed(IdentifierInfo *Name) { + ObjCProtocolDecl *PDecl = this; + + if (Name == getIdentifier()) + return PDecl; + + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) + if ((PDecl = (*I)->lookupProtocolNamed(Name))) + return PDecl; + + return NULL; +} + +// lookupInstanceMethod - Lookup a instance method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupInstanceMethod(ASTContext &Context, + Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getInstanceMethod(Context, Sel))) + return MethodDecl; + + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupInstanceMethod(Context, Sel))) + return MethodDecl; + return NULL; +} + +// lookupInstanceMethod - Lookup a class method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupClassMethod(ASTContext &Context, + Selector Sel) { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getClassMethod(Context, Sel))) + return MethodDecl; + + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupClassMethod(Context, Sel))) + return MethodDecl; + return NULL; +} + +//===----------------------------------------------------------------------===// +// ObjCClassDecl +//===----------------------------------------------------------------------===// + +ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *const *Elts, unsigned nElts, + ASTContext &C) + : Decl(ObjCClass, DC, L) { + ForwardDecls.set(Elts, nElts, C); +} + + +ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCInterfaceDecl *const *Elts, + unsigned nElts) { + return new (C) ObjCClassDecl(DC, L, Elts, nElts, C); +} + +void ObjCClassDecl::Destroy(ASTContext &C) { + + // FIXME: There is no clear ownership policy now for referenced + // ObjCInterfaceDecls. Some of them can be forward declarations that + // are never later defined (in which case the ObjCClassDecl owns them) + // or the ObjCInterfaceDecl later becomes a real definition later. Ideally + // we should have separate objects for forward declarations and definitions, + // obviating this problem. Because of this situation, referenced + // ObjCInterfaceDecls are destroyed in ~TranslationUnit. + + ForwardDecls.Destroy(C); + Decl::Destroy(C); +} + +//===----------------------------------------------------------------------===// +// ObjCForwardProtocolDecl +//===----------------------------------------------------------------------===// + +ObjCForwardProtocolDecl:: +ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, + ObjCProtocolDecl *const *Elts, unsigned nElts, + ASTContext &C) +: Decl(ObjCForwardProtocol, DC, L) { + ReferencedProtocols.set(Elts, nElts, C); +} + + +ObjCForwardProtocolDecl * +ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCProtocolDecl *const *Elts, + unsigned NumElts) { + return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, C); +} + +void ObjCForwardProtocolDecl::Destroy(ASTContext &C) { + ReferencedProtocols.Destroy(C); + Decl::Destroy(C); +} + +//===----------------------------------------------------------------------===// +// ObjCCategoryDecl +//===----------------------------------------------------------------------===// + +ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id) { + return new (C) ObjCCategoryDecl(DC, L, Id); +} + +//===----------------------------------------------------------------------===// +// ObjCCategoryImplDecl +//===----------------------------------------------------------------------===// + +ObjCCategoryImplDecl * +ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L,IdentifierInfo *Id, + ObjCInterfaceDecl *ClassInterface) { + return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); +} + + +void ObjCImplDecl::addPropertyImplementation(ASTContext &Context, + ObjCPropertyImplDecl *property) { + // FIXME: The context should be correct before we get here. + property->setLexicalDeclContext(this); + addDecl(Context, property); +} + +/// FindPropertyImplIvarDecl - This method lookup the ivar in the list of +/// properties implemented in this category @implementation block and returns +/// the implemented property that uses it. +/// +ObjCPropertyImplDecl *ObjCImplDecl:: +FindPropertyImplIvarDecl(ASTContext &Context, IdentifierInfo *ivarId) const { + for (propimpl_iterator i = propimpl_begin(Context), e = propimpl_end(Context); + i != e; ++i){ + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyIvarDecl() && + PID->getPropertyIvarDecl()->getIdentifier() == ivarId) + return PID; + } + return 0; +} + +/// FindPropertyImplDecl - This method looks up a previous ObjCPropertyImplDecl +/// added to the list of those properties @synthesized/@dynamic in this +/// category @implementation block. +/// +ObjCPropertyImplDecl *ObjCImplDecl:: +FindPropertyImplDecl(ASTContext &Context, IdentifierInfo *Id) const { + for (propimpl_iterator i = propimpl_begin(Context), e = propimpl_end(Context); + i != e; ++i){ + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyDecl()->getIdentifier() == Id) + return PID; + } + return 0; +} + +// getInstanceMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCImplDecl::getInstanceMethod(ASTContext &Context, + Selector Sel) const { + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod()) + return MD; + } + return 0; +} + +// getClassMethod - This method returns an instance method by looking in +// the class implementation. Unlike interfaces, we don't look outside the +// implementation. +ObjCMethodDecl *ObjCImplDecl::getClassMethod(ASTContext &Context, + Selector Sel) const { + // Since instance & class methods can have the same name, the loop below + // ensures we get the correct method. + // + // @interface Whatever + // - (int) class_method; + // + (float) class_method; + // @end + // + lookup_const_iterator Meth, MethEnd; + for (llvm::tie(Meth, MethEnd) = lookup(Context, Sel); + Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isClassMethod()) + return MD; + } + return 0; +} + +//===----------------------------------------------------------------------===// +// ObjCImplementationDecl +//===----------------------------------------------------------------------===// + +ObjCImplementationDecl * +ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCInterfaceDecl *ClassInterface, + ObjCInterfaceDecl *SuperDecl) { + return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); +} + +//===----------------------------------------------------------------------===// +// ObjCCompatibleAliasDecl +//===----------------------------------------------------------------------===// + +ObjCCompatibleAliasDecl * +ObjCCompatibleAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, + ObjCInterfaceDecl* AliasedClass) { + return new (C) ObjCCompatibleAliasDecl(DC, L, Id, AliasedClass); +} + +//===----------------------------------------------------------------------===// +// ObjCPropertyDecl +//===----------------------------------------------------------------------===// + +ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id, + QualType T, + PropertyControl propControl) { + return new (C) ObjCPropertyDecl(DC, L, Id, T); +} + + +//===----------------------------------------------------------------------===// +// ObjCPropertyImplDecl +//===----------------------------------------------------------------------===// + +ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation atLoc, + SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivar) { + return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar); +} + + diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp new file mode 100644 index 0000000..f29da8b --- /dev/null +++ b/lib/AST/DeclPrinter.cpp @@ -0,0 +1,722 @@ +//===--- DeclPrinter.cpp - Printing implementation for Decl 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 Decl::dump method, which pretty print the +// AST back out to C/Objective-C/C++/Objective-C++ code. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class VISIBILITY_HIDDEN DeclPrinter : public DeclVisitor<DeclPrinter> { + llvm::raw_ostream &Out; + ASTContext &Context; + PrintingPolicy Policy; + unsigned Indentation; + + llvm::raw_ostream& Indent(); + void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); + + public: + DeclPrinter(llvm::raw_ostream &Out, ASTContext &Context, + const PrintingPolicy &Policy, + unsigned Indentation = 0) + : Out(Out), Context(Context), Policy(Policy), Indentation(Indentation) { } + + void VisitDeclContext(DeclContext *DC, bool Indent = true); + + void VisitTranslationUnitDecl(TranslationUnitDecl *D); + void VisitTypedefDecl(TypedefDecl *D); + void VisitEnumDecl(EnumDecl *D); + void VisitRecordDecl(RecordDecl *D); + void VisitEnumConstantDecl(EnumConstantDecl *D); + void VisitFunctionDecl(FunctionDecl *D); + void VisitFieldDecl(FieldDecl *D); + void VisitVarDecl(VarDecl *D); + void VisitParmVarDecl(ParmVarDecl *D); + void VisitOriginalParmVarDecl(OriginalParmVarDecl *D); + void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitTemplateDecl(TemplateDecl *D); + void VisitObjCMethodDecl(ObjCMethodDecl *D); + void VisitObjCClassDecl(ObjCClassDecl *D); + void VisitObjCImplementationDecl(ObjCImplementationDecl *D); + void VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + void VisitObjCProtocolDecl(ObjCProtocolDecl *D); + void VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + void VisitObjCCategoryDecl(ObjCCategoryDecl *D); + void VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *D); + void VisitObjCPropertyDecl(ObjCPropertyDecl *D); + void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + }; +} + +void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, + unsigned Indentation) { + print(Out, Context, Context.PrintingPolicy, Indentation); +} + +void Decl::print(llvm::raw_ostream &Out, ASTContext &Context, + const PrintingPolicy &Policy, unsigned Indentation) { + DeclPrinter Printer(Out, Context, Policy, Indentation); + Printer.Visit(this); +} + +static QualType GetBaseType(QualType T) { + // FIXME: This should be on the Type class! + QualType BaseType = T; + while (!BaseType->isSpecifierType()) { + if (isa<TypedefType>(BaseType)) + break; + else if (const PointerType* PTy = BaseType->getAsPointerType()) + BaseType = PTy->getPointeeType(); + else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) + BaseType = ATy->getElementType(); + else if (const FunctionType* FTy = BaseType->getAsFunctionType()) + BaseType = FTy->getResultType(); + else + assert(0 && "Unknown declarator!"); + } + return BaseType; +} + +static QualType getDeclType(Decl* D) { + if (TypedefDecl* TDD = dyn_cast<TypedefDecl>(D)) + return TDD->getUnderlyingType(); + if (ValueDecl* VD = dyn_cast<ValueDecl>(D)) + return VD->getType(); + return QualType(); +} + +void Decl::printGroup(Decl** Begin, unsigned NumDecls, + llvm::raw_ostream &Out, ASTContext &Context, + const PrintingPolicy &Policy, + unsigned Indentation) { + if (NumDecls == 1) { + (*Begin)->print(Out, Context, Policy, Indentation); + return; + } + + Decl** End = Begin + NumDecls; + TagDecl* TD = dyn_cast<TagDecl>(*Begin); + if (TD) + ++Begin; + + PrintingPolicy SubPolicy(Policy); + if (TD && TD->isDefinition()) { + TD->print(Out, Context, Policy, Indentation); + Out << " "; + SubPolicy.SuppressTag = true; + } + + bool isFirst = true; + for ( ; Begin != End; ++Begin) { + if (isFirst) { + SubPolicy.SuppressSpecifiers = false; + isFirst = false; + } else { + if (!isFirst) Out << ", "; + SubPolicy.SuppressSpecifiers = true; + } + + (*Begin)->print(Out, Context, SubPolicy, Indentation); + } +} + +void Decl::dump(ASTContext &Context) { + print(llvm::errs(), Context); +} + +llvm::raw_ostream& DeclPrinter::Indent() { + for (unsigned i = 0; i < Indentation; ++i) + Out << " "; + return Out; +} + +void DeclPrinter::ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls) { + this->Indent(); + Decl::printGroup(Decls.data(), Decls.size(), Out, Context, + Policy, Indentation); + Out << ";\n"; + Decls.clear(); + +} + +//---------------------------------------------------------------------------- +// Common C declarations +//---------------------------------------------------------------------------- + +void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { + if (Indent) + Indentation += Policy.Indentation; + + llvm::SmallVector<Decl*, 2> Decls; + for (DeclContext::decl_iterator D = DC->decls_begin(Context), + DEnd = DC->decls_end(Context); + D != DEnd; ++D) { + if (!Policy.Dump) { + // Skip over implicit declarations in pretty-printing mode. + if (D->isImplicit()) continue; + // FIXME: Ugly hack so we don't pretty-print the builtin declaration + // of __builtin_va_list. There should be some other way to check that. + if (isa<NamedDecl>(*D) && cast<NamedDecl>(*D)->getNameAsString() == + "__builtin_va_list") + continue; + } + + // The next bits of code handles stuff like "struct {int x;} a,b"; we're + // forced to merge the declarations because there's no other way to + // refer to the struct in question. This limited merging is safe without + // a bunch of other checks because it only merges declarations directly + // referring to the tag, not typedefs. + // + // Check whether the current declaration should be grouped with a previous + // unnamed struct. + QualType CurDeclType = getDeclType(*D); + if (!Decls.empty() && !CurDeclType.isNull()) { + QualType BaseType = GetBaseType(CurDeclType); + if (!BaseType.isNull() && isa<TagType>(BaseType) && + cast<TagType>(BaseType)->getDecl() == Decls[0]) { + Decls.push_back(*D); + continue; + } + } + + // If we have a merged group waiting to be handled, handle it now. + if (!Decls.empty()) + ProcessDeclGroup(Decls); + + // If the current declaration is an unnamed tag type, save it + // so we can merge it with the subsequent declaration(s) using it. + if (isa<TagDecl>(*D) && !cast<TagDecl>(*D)->getIdentifier()) { + Decls.push_back(*D); + continue; + } + this->Indent(); + Visit(*D); + + // FIXME: Need to be able to tell the DeclPrinter when + const char *Terminator = 0; + if (isa<FunctionDecl>(*D) && + cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) + Terminator = 0; + else if (isa<ObjCMethodDecl>(*D) && cast<ObjCMethodDecl>(*D)->getBody()) + Terminator = 0; + else if (isa<NamespaceDecl>(*D) || isa<LinkageSpecDecl>(*D) || + isa<ObjCImplementationDecl>(*D) || + isa<ObjCInterfaceDecl>(*D) || + isa<ObjCProtocolDecl>(*D) || + isa<ObjCCategoryImplDecl>(*D) || + isa<ObjCCategoryDecl>(*D)) + Terminator = 0; + else if (isa<EnumConstantDecl>(*D)) { + DeclContext::decl_iterator Next = D; + ++Next; + if (Next != DEnd) + Terminator = ","; + } else + Terminator = ";"; + + if (Terminator) + Out << Terminator; + Out << "\n"; + } + + if (!Decls.empty()) + ProcessDeclGroup(Decls); + + if (Indent) + Indentation -= Policy.Indentation; +} + +void DeclPrinter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { + VisitDeclContext(D, false); +} + +void DeclPrinter::VisitTypedefDecl(TypedefDecl *D) { + std::string S = D->getNameAsString(); + D->getUnderlyingType().getAsStringInternal(S, Policy); + if (!Policy.SuppressSpecifiers) + Out << "typedef "; + Out << S; +} + +void DeclPrinter::VisitEnumDecl(EnumDecl *D) { + Out << "enum " << D->getNameAsString() << " {\n"; + VisitDeclContext(D); + Indent() << "}"; +} + +void DeclPrinter::VisitRecordDecl(RecordDecl *D) { + Out << D->getKindName(); + if (D->getIdentifier()) { + Out << " "; + Out << D->getNameAsString(); + } + + if (D->isDefinition()) { + Out << " {\n"; + VisitDeclContext(D); + Indent() << "}"; + } +} + +void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { + Out << D->getNameAsString(); + if (Expr *Init = D->getInitExpr()) { + Out << " = "; + Init->printPretty(Out, Context, 0, Policy, Indentation); + } +} + +void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { + if (!Policy.SuppressSpecifiers) { + switch (D->getStorageClass()) { + case FunctionDecl::None: break; + case FunctionDecl::Extern: Out << "extern "; break; + case FunctionDecl::Static: Out << "static "; break; + case FunctionDecl::PrivateExtern: Out << "__private_extern__ "; break; + } + + if (D->isInline()) Out << "inline "; + if (D->isVirtualAsWritten()) Out << "virtual "; + } + + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressSpecifiers = false; + std::string Proto = D->getNameAsString(); + if (isa<FunctionType>(D->getType().getTypePtr())) { + const FunctionType *AFT = D->getType()->getAsFunctionType(); + + const FunctionProtoType *FT = 0; + if (D->hasWrittenPrototype()) + FT = dyn_cast<FunctionProtoType>(AFT); + + Proto += "("; + if (FT) { + llvm::raw_string_ostream POut(Proto); + DeclPrinter ParamPrinter(POut, Context, SubPolicy, Indentation); + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + if (i) POut << ", "; + ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); + } + + if (FT->isVariadic()) { + if (D->getNumParams()) POut << ", "; + POut << "..."; + } + } else if (D->isThisDeclarationADefinition() && !D->hasPrototype()) { + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + if (i) + Proto += ", "; + Proto += D->getParamDecl(i)->getNameAsString(); + } + } + + Proto += ")"; + AFT->getResultType().getAsStringInternal(Proto, Policy); + } else { + D->getType().getAsStringInternal(Proto, Policy); + } + + Out << Proto; + + if (D->isPure()) + Out << " = 0"; + else if (D->isDeleted()) + Out << " = delete"; + else if (D->isThisDeclarationADefinition()) { + if (!D->hasPrototype() && D->getNumParams()) { + // This is a K&R function definition, so we need to print the + // parameters. + Out << '\n'; + DeclPrinter ParamPrinter(Out, Context, SubPolicy, Indentation); + Indentation += Policy.Indentation; + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + Indent(); + ParamPrinter.VisitParmVarDecl(D->getParamDecl(i)); + Out << ";\n"; + } + Indentation -= Policy.Indentation; + } else + Out << ' '; + + D->getBody(Context)->printPretty(Out, Context, 0, SubPolicy, Indentation); + Out << '\n'; + } +} + +void DeclPrinter::VisitFieldDecl(FieldDecl *D) { + if (!Policy.SuppressSpecifiers && D->isMutable()) + Out << "mutable "; + + std::string Name = D->getNameAsString(); + D->getType().getAsStringInternal(Name, Policy); + Out << Name; + + if (D->isBitField()) { + Out << " : "; + D->getBitWidth()->printPretty(Out, Context, 0, Policy, Indentation); + } +} + +void DeclPrinter::VisitVarDecl(VarDecl *D) { + if (!Policy.SuppressSpecifiers && D->getStorageClass() != VarDecl::None) + Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; + + if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) + Out << "__thread "; + + std::string Name = D->getNameAsString(); + QualType T = D->getType(); + if (OriginalParmVarDecl *Parm = dyn_cast<OriginalParmVarDecl>(D)) + T = Parm->getOriginalType(); + T.getAsStringInternal(Name, Policy); + Out << Name; + if (D->getInit()) { + if (D->hasCXXDirectInitializer()) + Out << "("; + else + Out << " = "; + D->getInit()->printPretty(Out, Context, 0, Policy, Indentation); + if (D->hasCXXDirectInitializer()) + Out << ")"; + } +} + +void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { + VisitVarDecl(D); +} + +void DeclPrinter::VisitOriginalParmVarDecl(OriginalParmVarDecl *D) { + VisitVarDecl(D); +} + +void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { + Out << "__asm ("; + D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ")"; +} + +//---------------------------------------------------------------------------- +// C++ declarations +//---------------------------------------------------------------------------- +void DeclPrinter::VisitOverloadedFunctionDecl(OverloadedFunctionDecl *D) { + assert(false && + "OverloadedFunctionDecls aren't really decls and are never printed"); +} + +void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { + Out << "namespace " << D->getNameAsString() << " {\n"; + VisitDeclContext(D); + Indent() << "}"; +} + +void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + Out << "using namespace "; + if (D->getQualifier()) + D->getQualifier()->print(Out, Policy); + Out << D->getNominatedNamespace()->getNameAsString(); +} + +void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + Out << "namespace " << D->getNameAsString() << " = "; + if (D->getQualifier()) + D->getQualifier()->print(Out, Policy); + Out << D->getAliasedNamespace()->getNameAsString(); +} + +void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { + Out << D->getKindName(); + if (D->getIdentifier()) { + Out << " "; + Out << D->getNameAsString(); + } + + if (D->isDefinition()) { + // Print the base classes + if (D->getNumBases()) { + Out << " : "; + for(CXXRecordDecl::base_class_iterator Base = D->bases_begin(), + BaseEnd = D->bases_end(); + Base != BaseEnd; ++Base) { + if (Base != D->bases_begin()) + Out << ", "; + + if (Base->isVirtual()) + Out << "virtual "; + + switch(Base->getAccessSpecifierAsWritten()) { + case AS_none: break; + case AS_public: Out << "public "; break; + case AS_protected: Out << "protected "; break; + case AS_private: Out << " private "; break; + } + + Out << Base->getType().getAsString(Policy); + } + } + + // Print the class definition + // FIXME: Doesn't print access specifiers, e.g., "public:" + Out << " {\n"; + VisitDeclContext(D); + Indent() << "}"; + } +} + +void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + const char *l; + if (D->getLanguage() == LinkageSpecDecl::lang_c) + l = "C"; + else { + assert(D->getLanguage() == LinkageSpecDecl::lang_cxx && + "unknown language in linkage specification"); + l = "C++"; + } + + Out << "extern \"" << l << "\" "; + if (D->hasBraces()) { + Out << "{\n"; + VisitDeclContext(D); + Indent() << "}"; + } else + Visit(*D->decls_begin(Context)); +} + +void DeclPrinter::VisitTemplateDecl(TemplateDecl *D) { + // TODO: Write template parameters. + Out << "template <...> "; + Visit(D->getTemplatedDecl()); +} + +//---------------------------------------------------------------------------- +// Objective-C declarations +//---------------------------------------------------------------------------- + +void DeclPrinter::VisitObjCClassDecl(ObjCClassDecl *D) { + Out << "@class "; + for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); + I != E; ++I) { + if (I != D->begin()) Out << ", "; + Out << (*I)->getNameAsString(); + } +} + +void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { + if (OMD->isInstanceMethod()) + Out << "- "; + else + Out << "+ "; + if (!OMD->getResultType().isNull()) + Out << '(' << OMD->getResultType().getAsString(Policy) << ")"; + + std::string name = OMD->getSelector().getAsString(); + std::string::size_type pos, lastPos = 0; + for (ObjCMethodDecl::param_iterator PI = OMD->param_begin(), + E = OMD->param_end(); PI != E; ++PI) { + // FIXME: selector is missing here! + pos = name.find_first_of(":", lastPos); + Out << " " << name.substr(lastPos, pos - lastPos); + Out << ":(" << (*PI)->getType().getAsString(Policy) << ")" + << (*PI)->getNameAsString(); + lastPos = pos + 1; + } + + if (OMD->param_begin() == OMD->param_end()) + Out << " " << name; + + if (OMD->isVariadic()) + Out << ", ..."; + + if (OMD->getBody()) { + Out << ' '; + OMD->getBody()->printPretty(Out, Context, 0, Policy); + Out << '\n'; + } +} + +void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { + std::string I = OID->getNameAsString(); + ObjCInterfaceDecl *SID = OID->getSuperClass(); + + if (SID) + Out << "@implementation " << I << " : " << SID->getNameAsString(); + else + Out << "@implementation " << I; + Out << "\n"; + VisitDeclContext(OID, false); + Out << "@end"; +} + +void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { + std::string I = OID->getNameAsString(); + ObjCInterfaceDecl *SID = OID->getSuperClass(); + + if (SID) + Out << "@interface " << I << " : " << SID->getNameAsString(); + else + Out << "@interface " << I; + + // Protocols? + const ObjCList<ObjCProtocolDecl> &Protocols = OID->getReferencedProtocols(); + if (!Protocols.empty()) { + for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), + E = Protocols.end(); I != E; ++I) + Out << (I == Protocols.begin() ? '<' : ',') << (*I)->getNameAsString(); + } + + if (!Protocols.empty()) + Out << "> "; + + if (OID->ivar_size() > 0) { + Out << "{\n"; + Indentation += Policy.Indentation; + for (ObjCInterfaceDecl::ivar_iterator I = OID->ivar_begin(), + E = OID->ivar_end(); I != E; ++I) { + Indent() << (*I)->getType().getAsString(Policy) + << ' ' << (*I)->getNameAsString() << ";\n"; + } + Indentation -= Policy.Indentation; + Out << "}\n"; + } + + VisitDeclContext(OID, false); + Out << "@end"; + // FIXME: implement the rest... +} + +void DeclPrinter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + Out << "@protocol "; + for (ObjCForwardProtocolDecl::protocol_iterator I = D->protocol_begin(), + E = D->protocol_end(); + I != E; ++I) { + if (I != D->protocol_begin()) Out << ", "; + Out << (*I)->getNameAsString(); + } +} + +void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + Out << "@protocol " << PID->getNameAsString() << '\n'; + VisitDeclContext(PID, false); + Out << "@end"; +} + +void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { + Out << "@implementation " + << PID->getClassInterface()->getNameAsString() + << '(' << PID->getNameAsString() << ")\n"; + + VisitDeclContext(PID, false); + Out << "@end"; + // FIXME: implement the rest... +} + +void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { + Out << "@interface " + << PID->getClassInterface()->getNameAsString() + << '(' << PID->getNameAsString() << ")\n"; + VisitDeclContext(PID, false); + Out << "@end"; + + // FIXME: implement the rest... +} + +void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { + Out << "@compatibility_alias " << AID->getNameAsString() + << ' ' << AID->getClassInterface()->getNameAsString() << ";\n"; +} + +/// PrintObjCPropertyDecl - print a property declaration. +/// +void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { + if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Required) + Out << "@required\n"; + else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional) + Out << "@optional\n"; + + Out << "@property"; + if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) { + bool first = true; + Out << " ("; + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readonly) { + Out << (first ? ' ' : ',') << "readonly"; + first = false; + } + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_getter) { + Out << (first ? ' ' : ',') << "getter = " + << PDecl->getGetterName().getAsString(); + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter) { + Out << (first ? ' ' : ',') << "setter = " + << PDecl->getSetterName().getAsString(); + first = false; + } + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_assign) { + Out << (first ? ' ' : ',') << "assign"; + first = false; + } + + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_readwrite) { + Out << (first ? ' ' : ',') << "readwrite"; + first = false; + } + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_retain) { + Out << (first ? ' ' : ',') << "retain"; + first = false; + } + + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_copy) { + Out << (first ? ' ' : ',') << "copy"; + first = false; + } + + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_nonatomic) { + Out << (first ? ' ' : ',') << "nonatomic"; + first = false; + } + Out << " )"; + } + Out << ' ' << PDecl->getType().getAsString(Policy) + << ' ' << PDecl->getNameAsString(); +} + +void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) + Out << "@synthesize "; + else + Out << "@dynamic "; + Out << PID->getPropertyDecl()->getNameAsString(); + if (PID->getPropertyIvarDecl()) + Out << "=" << PID->getPropertyIvarDecl()->getNameAsString(); +} diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp new file mode 100644 index 0000000..f38ee82 --- /dev/null +++ b/lib/AST/DeclTemplate.cpp @@ -0,0 +1,324 @@ +//===--- DeclCXX.cpp - C++ 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 C++ related Decl classes for templates. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/STLExtras.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// TemplateParameterList Implementation +//===----------------------------------------------------------------------===// + +TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + Decl **Params, unsigned NumParams, + SourceLocation RAngleLoc) + : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), + NumParams(NumParams) { + for (unsigned Idx = 0; Idx < NumParams; ++Idx) + begin()[Idx] = Params[Idx]; +} + +TemplateParameterList * +TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, Decl **Params, + unsigned NumParams, SourceLocation RAngleLoc) { + unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams; + unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment; + void *Mem = C.Allocate(Size, Align); + return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, + NumParams, RAngleLoc); +} + +unsigned TemplateParameterList::getMinRequiredArguments() const { + unsigned NumRequiredArgs = size(); + iterator Param = const_cast<TemplateParameterList *>(this)->end(), + ParamBegin = const_cast<TemplateParameterList *>(this)->begin(); + while (Param != ParamBegin) { + --Param; + if (!(isa<TemplateTypeParmDecl>(*Param) && + cast<TemplateTypeParmDecl>(*Param)->hasDefaultArgument()) && + !(isa<NonTypeTemplateParmDecl>(*Param) && + cast<NonTypeTemplateParmDecl>(*Param)->hasDefaultArgument()) && + !(isa<TemplateTemplateParmDecl>(*Param) && + cast<TemplateTemplateParmDecl>(*Param)->hasDefaultArgument())) + break; + + --NumRequiredArgs; + } + + return NumRequiredArgs; +} + +//===----------------------------------------------------------------------===// +// TemplateDecl Implementation +//===----------------------------------------------------------------------===// + +TemplateDecl::~TemplateDecl() { +} + +//===----------------------------------------------------------------------===// +// FunctionTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl) { + return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); +} + +//===----------------------------------------------------------------------===// +// ClassTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + ClassTemplateDecl *PrevDecl) { + Common *CommonPtr; + if (PrevDecl) + CommonPtr = PrevDecl->CommonPtr; + else + CommonPtr = new (C) Common; + + return new (C) ClassTemplateDecl(DC, L, Name, Params, Decl, PrevDecl, + CommonPtr); +} + +ClassTemplateDecl::~ClassTemplateDecl() { + assert(CommonPtr == 0 && "ClassTemplateDecl must be explicitly destroyed"); +} + +void ClassTemplateDecl::Destroy(ASTContext& C) { + if (!PreviousDeclaration) { + CommonPtr->~Common(); + C.Deallocate((void*)CommonPtr); + } + CommonPtr = 0; + + this->~ClassTemplateDecl(); + C.Deallocate((void*)this); +} + +QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { + if (!CommonPtr->InjectedClassNameType.isNull()) + return CommonPtr->InjectedClassNameType; + + // FIXME: n2800 14.6.1p1 should say how the template arguments + // corresponding to template parameter packs should be pack + // expansions. We already say that in 14.6.2.1p2, so it would be + // better to fix that redundancy. + + TemplateParameterList *Params = getTemplateParameters(); + + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs; + TemplateArgs.reserve(Params->size()); + CanonTemplateArgs.reserve(Params->size()); + + for (TemplateParameterList::iterator + Param = Params->begin(), ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + if (isa<TemplateTypeParmDecl>(*Param)) { + QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); + TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), + ParamType)); + CanonTemplateArgs.push_back( + TemplateArgument((*Param)->getLocation(), + Context.getCanonicalType(ParamType))); + } else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + // FIXME: Build canonical expression, too! + Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), + NTTP->getLocation(), + NTTP->getType()->isDependentType(), + /*Value-dependent=*/true); + TemplateArgs.push_back(TemplateArgument(E)); + CanonTemplateArgs.push_back(TemplateArgument(E)); + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); + TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); + CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), + Context.getCanonicalDecl(TTP))); + } + } + + // FIXME: I should really move the "build-the-canonical-type" logic + // into ASTContext::getTemplateSpecializationType. + TemplateName Name = TemplateName(this); + QualType CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), + &CanonTemplateArgs[0], + CanonTemplateArgs.size()); + + CommonPtr->InjectedClassNameType + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + CanonType); + return CommonPtr->InjectedClassNameType; +} + +//===----------------------------------------------------------------------===// +// TemplateTypeParm Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +TemplateTypeParmDecl * +TemplateTypeParmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, bool Typename) { + QualType Type = C.getTemplateTypeParmType(D, P, Id); + return new (C) TemplateTypeParmDecl(DC, L, Id, Typename, Type); +} + +//===----------------------------------------------------------------------===// +// NonTypeTemplateParmDecl Method Implementations +//===----------------------------------------------------------------------===// + +NonTypeTemplateParmDecl * +NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + SourceLocation TypeSpecStartLoc) { + return new (C) NonTypeTemplateParmDecl(DC, L, D, P, Id, T, + TypeSpecStartLoc); +} + +SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument? DefaultArgument->getSourceRange().getBegin() + : SourceLocation(); +} + +//===----------------------------------------------------------------------===// +// TemplateTemplateParmDecl Method Implementations +//===----------------------------------------------------------------------===// + +TemplateTemplateParmDecl * +TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, + TemplateParameterList *Params) { + return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); +} + +SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument? DefaultArgument->getSourceRange().getBegin() + : SourceLocation(); +} + +//===----------------------------------------------------------------------===// +// TemplateArgument Implementation +//===----------------------------------------------------------------------===// + +TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { + TypeOrValue = reinterpret_cast<uintptr_t>(E); + StartLoc = E->getSourceRange().getBegin(); +} + +//===----------------------------------------------------------------------===// +// TemplateArgumentList Implementation +//===----------------------------------------------------------------------===// +TemplateArgumentList::TemplateArgumentList(ASTContext &Context, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + bool CopyArgs) + : NumArguments(NumTemplateArgs) { + if (!CopyArgs) { + Arguments.setPointer(TemplateArgs); + Arguments.setInt(1); + return; + } + + unsigned Size = sizeof(TemplateArgument) * NumTemplateArgs; + unsigned Align = llvm::AlignOf<TemplateArgument>::Alignment; + void *Mem = Context.Allocate(Size, Align); + Arguments.setPointer((TemplateArgument *)Mem); + Arguments.setInt(0); + + TemplateArgument *Args = (TemplateArgument *)Mem; + for (unsigned I = 0; I != NumTemplateArgs; ++I) + new (Args + I) TemplateArgument(TemplateArgs[I]); +} + +TemplateArgumentList::~TemplateArgumentList() { + // FIXME: Deallocate template arguments +} + +//===----------------------------------------------------------------------===// +// ClassTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ClassTemplateSpecializationDecl:: +ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, + DeclContext *DC, SourceLocation L, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) + : CXXRecordDecl(DK, + SpecializedTemplate->getTemplatedDecl()->getTagKind(), + DC, L, + // FIXME: Should we use DeclarationName for the name of + // class template specializations? + SpecializedTemplate->getIdentifier()), + SpecializedTemplate(SpecializedTemplate), + TemplateArgs(Context, TemplateArgs, NumTemplateArgs, /*CopyArgs=*/true), + SpecializationKind(TSK_Undeclared) { +} + +ClassTemplateSpecializationDecl * +ClassTemplateSpecializationDecl::Create(ASTContext &Context, + DeclContext *DC, SourceLocation L, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + ClassTemplateSpecializationDecl *PrevDecl) { + ClassTemplateSpecializationDecl *Result + = new (Context)ClassTemplateSpecializationDecl(Context, + ClassTemplateSpecialization, + DC, L, + SpecializedTemplate, + TemplateArgs, + NumTemplateArgs); + Context.getTypeDeclType(Result, PrevDecl); + return Result; +} + +//===----------------------------------------------------------------------===// +// ClassTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ClassTemplatePartialSpecializationDecl * +ClassTemplatePartialSpecializationDecl:: +Create(ASTContext &Context, DeclContext *DC, SourceLocation L, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + TemplateArgument *TemplateArgs, unsigned NumTemplateArgs, + ClassTemplatePartialSpecializationDecl *PrevDecl) { + ClassTemplatePartialSpecializationDecl *Result + = new (Context)ClassTemplatePartialSpecializationDecl(Context, + DC, L, Params, + SpecializedTemplate, + TemplateArgs, + NumTemplateArgs); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + Context.getTypeDeclType(Result, PrevDecl); + return Result; +} diff --git a/lib/AST/DeclarationName.cpp b/lib/AST/DeclarationName.cpp new file mode 100644 index 0000000..a17abde --- /dev/null +++ b/lib/AST/DeclarationName.cpp @@ -0,0 +1,355 @@ +//===-- DeclarationName.cpp - Declaration names implementation --*- 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 the DeclarationName and DeclarationNameTable +// classes. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/AST/Decl.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +using namespace clang; + +namespace clang { +/// CXXSpecialName - Records the type associated with one of the +/// "special" kinds of declaration names in C++, e.g., constructors, +/// destructors, and conversion functions. +class CXXSpecialName + : public DeclarationNameExtra, public llvm::FoldingSetNode { +public: + /// Type - The type associated with this declaration name. + QualType Type; + + /// FETokenInfo - Extra information associated with this declaration + /// name that can be used by the front end. + void *FETokenInfo; + + void Profile(llvm::FoldingSetNodeID &ID) { + ID.AddInteger(ExtraKindOrNumArgs); + ID.AddPointer(Type.getAsOpaquePtr()); + } +}; + +/// CXXOperatorIdName - Contains extra information for the name of an +/// overloaded operator in C++, such as "operator+. +class CXXOperatorIdName : public DeclarationNameExtra { +public: + /// FETokenInfo - Extra information associated with this operator + /// name that can be used by the front end. + void *FETokenInfo; +}; + +bool operator<(DeclarationName LHS, DeclarationName RHS) { + if (IdentifierInfo *LhsId = LHS.getAsIdentifierInfo()) + if (IdentifierInfo *RhsId = RHS.getAsIdentifierInfo()) + return strcmp(LhsId->getName(), RhsId->getName()) < 0; + + return LHS.getAsOpaqueInteger() < RHS.getAsOpaqueInteger(); +} + +} // end namespace clang + +DeclarationName::DeclarationName(Selector Sel) { + if (!Sel.getAsOpaquePtr()) { + Ptr = StoredObjCZeroArgSelector; + return; + } + + switch (Sel.getNumArgs()) { + case 0: + Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo()); + assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + Ptr |= StoredObjCZeroArgSelector; + break; + + case 1: + Ptr = reinterpret_cast<uintptr_t>(Sel.getAsIdentifierInfo()); + assert((Ptr & PtrMask) == 0 && "Improperly aligned IdentifierInfo"); + Ptr |= StoredObjCOneArgSelector; + break; + + default: + Ptr = Sel.InfoPtr & ~Selector::ArgFlags; + assert((Ptr & PtrMask) == 0 && "Improperly aligned MultiKeywordSelector"); + Ptr |= StoredDeclarationNameExtra; + break; + } +} + +DeclarationName::NameKind DeclarationName::getNameKind() const { + switch (getStoredNameKind()) { + case StoredIdentifier: return Identifier; + case StoredObjCZeroArgSelector: return ObjCZeroArgSelector; + case StoredObjCOneArgSelector: return ObjCOneArgSelector; + + case StoredDeclarationNameExtra: + switch (getExtra()->ExtraKindOrNumArgs) { + case DeclarationNameExtra::CXXConstructor: + return CXXConstructorName; + + case DeclarationNameExtra::CXXDestructor: + return CXXDestructorName; + + case DeclarationNameExtra::CXXConversionFunction: + return CXXConversionFunctionName; + + case DeclarationNameExtra::CXXUsingDirective: + return CXXUsingDirective; + + default: + // Check if we have one of the CXXOperator* enumeration values. + if (getExtra()->ExtraKindOrNumArgs < + DeclarationNameExtra::CXXUsingDirective) + return CXXOperatorName; + + return ObjCMultiArgSelector; + } + break; + } + + // Can't actually get here. + assert(0 && "This should be unreachable!"); + return Identifier; +} + +std::string DeclarationName::getAsString() const { + switch (getNameKind()) { + case Identifier: + if (const IdentifierInfo *II = getAsIdentifierInfo()) + return II->getName(); + return ""; + + case ObjCZeroArgSelector: + case ObjCOneArgSelector: + case ObjCMultiArgSelector: + return getObjCSelector().getAsString(); + + case CXXConstructorName: { + QualType ClassType = getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAsRecordType()) + return ClassRec->getDecl()->getNameAsString(); + return ClassType.getAsString(); + } + + case CXXDestructorName: { + std::string Result = "~"; + QualType Type = getCXXNameType(); + if (const RecordType *Rec = Type->getAsRecordType()) + Result += Rec->getDecl()->getNameAsString(); + else + Result += Type.getAsString(); + return Result; + } + + case CXXOperatorName: { + static const char *OperatorNames[NUM_OVERLOADED_OPERATORS] = { + 0, +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = OperatorNames[getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + + std::string Result = "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + Result += ' '; + Result += OpName; + return Result; + } + + case CXXConversionFunctionName: { + std::string Result = "operator "; + QualType Type = getCXXNameType(); + if (const RecordType *Rec = Type->getAsRecordType()) + Result += Rec->getDecl()->getNameAsString(); + else + Result += Type.getAsString(); + return Result; + } + case CXXUsingDirective: + return "<using-directive>"; + } + + assert(false && "Unexpected declaration name kind"); + return ""; +} + +QualType DeclarationName::getCXXNameType() const { + if (CXXSpecialName *CXXName = getAsCXXSpecialName()) + return CXXName->Type; + else + return QualType(); +} + +OverloadedOperatorKind DeclarationName::getCXXOverloadedOperator() const { + if (CXXOperatorIdName *CXXOp = getAsCXXOperatorIdName()) { + unsigned value + = CXXOp->ExtraKindOrNumArgs - DeclarationNameExtra::CXXConversionFunction; + return static_cast<OverloadedOperatorKind>(value); + } else { + return OO_None; + } +} + +Selector DeclarationName::getObjCSelector() const { + switch (getNameKind()) { + case ObjCZeroArgSelector: + return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 0); + + case ObjCOneArgSelector: + return Selector(reinterpret_cast<IdentifierInfo *>(Ptr & ~PtrMask), 1); + + case ObjCMultiArgSelector: + return Selector(reinterpret_cast<MultiKeywordSelector *>(Ptr & ~PtrMask)); + + default: + break; + } + + return Selector(); +} + +void *DeclarationName::getFETokenInfoAsVoid() const { + switch (getNameKind()) { + case Identifier: + return getAsIdentifierInfo()->getFETokenInfo<void>(); + + case CXXConstructorName: + case CXXDestructorName: + case CXXConversionFunctionName: + return getAsCXXSpecialName()->FETokenInfo; + + case CXXOperatorName: + return getAsCXXOperatorIdName()->FETokenInfo; + + default: + assert(false && "Declaration name has no FETokenInfo"); + } + return 0; +} + +void DeclarationName::setFETokenInfo(void *T) { + switch (getNameKind()) { + case Identifier: + getAsIdentifierInfo()->setFETokenInfo(T); + break; + + case CXXConstructorName: + case CXXDestructorName: + case CXXConversionFunctionName: + getAsCXXSpecialName()->FETokenInfo = T; + break; + + case CXXOperatorName: + getAsCXXOperatorIdName()->FETokenInfo = T; + break; + + default: + assert(false && "Declaration name has no FETokenInfo"); + } +} + +DeclarationName DeclarationName::getUsingDirectiveName() { + // Single instance of DeclarationNameExtra for using-directive + static DeclarationNameExtra UDirExtra = + { DeclarationNameExtra::CXXUsingDirective }; + + uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra); + Ptr |= StoredDeclarationNameExtra; + + return DeclarationName(Ptr); +} + +DeclarationNameTable::DeclarationNameTable() { + CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; + + // Initialize the overloaded operator names. + CXXOperatorNames = new CXXOperatorIdName[NUM_OVERLOADED_OPERATORS]; + for (unsigned Op = 0; Op < NUM_OVERLOADED_OPERATORS; ++Op) { + CXXOperatorNames[Op].ExtraKindOrNumArgs + = Op + DeclarationNameExtra::CXXConversionFunction; + CXXOperatorNames[Op].FETokenInfo = 0; + } +} + +DeclarationNameTable::~DeclarationNameTable() { + llvm::FoldingSet<CXXSpecialName> *set = + static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); + llvm::FoldingSetIterator<CXXSpecialName> I = set->begin(), E = set->end(); + + while (I != E) { + CXXSpecialName *n = &*I++; + delete n; + } + + delete set; + delete [] CXXOperatorNames; +} + +DeclarationName +DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, + QualType Ty) { + assert(Kind >= DeclarationName::CXXConstructorName && + Kind <= DeclarationName::CXXConversionFunctionName && + "Kind must be a C++ special name kind"); + assert(Ty->isCanonical() && + "Can only build C++ special names from canonical types"); + llvm::FoldingSet<CXXSpecialName> *SpecialNames + = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); + + DeclarationNameExtra::ExtraKind EKind; + switch (Kind) { + case DeclarationName::CXXConstructorName: + EKind = DeclarationNameExtra::CXXConstructor; + assert(Ty.getCVRQualifiers() == 0 &&"Constructor type must be unqualified"); + break; + case DeclarationName::CXXDestructorName: + EKind = DeclarationNameExtra::CXXDestructor; + assert(Ty.getCVRQualifiers() == 0 && "Destructor type must be unqualified"); + break; + case DeclarationName::CXXConversionFunctionName: + EKind = DeclarationNameExtra::CXXConversionFunction; + break; + default: + return DeclarationName(); + } + + // Unique selector, to guarantee there is one per name. + llvm::FoldingSetNodeID ID; + ID.AddInteger(EKind); + ID.AddPointer(Ty.getAsOpaquePtr()); + + void *InsertPos = 0; + if (CXXSpecialName *Name = SpecialNames->FindNodeOrInsertPos(ID, InsertPos)) + return DeclarationName(Name); + + CXXSpecialName *SpecialName = new CXXSpecialName; + SpecialName->ExtraKindOrNumArgs = EKind; + SpecialName->Type = Ty; + SpecialName->FETokenInfo = 0; + + SpecialNames->InsertNode(SpecialName, InsertPos); + return DeclarationName(SpecialName); +} + +DeclarationName +DeclarationNameTable::getCXXOperatorName(OverloadedOperatorKind Op) { + return DeclarationName(&CXXOperatorNames[(unsigned)Op]); +} + +unsigned +llvm::DenseMapInfo<clang::DeclarationName>:: +getHashValue(clang::DeclarationName N) { + return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr()); +} + diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp new file mode 100644 index 0000000..4a53a41 --- /dev/null +++ b/lib/AST/Expr.cpp @@ -0,0 +1,2059 @@ +//===--- 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/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/Basic/TargetInfo.h" +#include <algorithm> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +PredefinedExpr* PredefinedExpr::Clone(ASTContext &C) const { + return new (C) PredefinedExpr(Loc, getType(), Type); +} + +IntegerLiteral* IntegerLiteral::Clone(ASTContext &C) const { + return new (C) IntegerLiteral(Value, getType(), Loc); +} + +CharacterLiteral* CharacterLiteral::Clone(ASTContext &C) const { + return new (C) CharacterLiteral(Value, IsWide, getType(), Loc); +} + +FloatingLiteral* FloatingLiteral::Clone(ASTContext &C) const { + bool exact = IsExact; + return new (C) FloatingLiteral(Value, &exact, getType(), Loc); +} + +ImaginaryLiteral* ImaginaryLiteral::Clone(ASTContext &C) const { + // FIXME: Use virtual Clone(), once it is available + Expr *ClonedVal = 0; + if (const IntegerLiteral *IntLit = dyn_cast<IntegerLiteral>(Val)) + ClonedVal = IntLit->Clone(C); + else + ClonedVal = cast<FloatingLiteral>(Val)->Clone(C); + return new (C) ImaginaryLiteral(ClonedVal, getType()); +} + +GNUNullExpr* GNUNullExpr::Clone(ASTContext &C) const { + return new (C) GNUNullExpr(getType(), TokenLoc); +} + +/// getValueAsApproximateDouble - This returns the value as an inaccurate +/// double. Note that this may cause loss of precision, but is useful for +/// debugging dumps, etc. +double FloatingLiteral::getValueAsApproximateDouble() const { + llvm::APFloat V = getValue(); + bool ignored; + V.convert(llvm::APFloat::IEEEdouble, llvm::APFloat::rmNearestTiesToEven, + &ignored); + return V.convertToDouble(); +} + +StringLiteral *StringLiteral::Create(ASTContext &C, const char *StrData, + unsigned ByteLength, bool Wide, + QualType Ty, + const SourceLocation *Loc, + unsigned NumStrs) { + // Allocate enough space for the StringLiteral plus an array of locations for + // any concatenated string tokens. + void *Mem = C.Allocate(sizeof(StringLiteral)+ + sizeof(SourceLocation)*(NumStrs-1), + llvm::alignof<StringLiteral>()); + StringLiteral *SL = new (Mem) StringLiteral(Ty); + + // OPTIMIZE: could allocate this appended to the StringLiteral. + char *AStrData = new (C, 1) char[ByteLength]; + memcpy(AStrData, StrData, ByteLength); + SL->StrData = AStrData; + SL->ByteLength = ByteLength; + SL->IsWide = Wide; + SL->TokLocs[0] = Loc[0]; + SL->NumConcatenated = NumStrs; + + if (NumStrs != 1) + memcpy(&SL->TokLocs[1], Loc+1, sizeof(SourceLocation)*(NumStrs-1)); + return SL; +} + +StringLiteral *StringLiteral::CreateEmpty(ASTContext &C, unsigned NumStrs) { + void *Mem = C.Allocate(sizeof(StringLiteral)+ + sizeof(SourceLocation)*(NumStrs-1), + llvm::alignof<StringLiteral>()); + StringLiteral *SL = new (Mem) StringLiteral(QualType()); + SL->StrData = 0; + SL->ByteLength = 0; + SL->NumConcatenated = NumStrs; + return SL; +} + +StringLiteral* StringLiteral::Clone(ASTContext &C) const { + return Create(C, StrData, ByteLength, IsWide, getType(), + TokLocs, NumConcatenated); +} + +void StringLiteral::Destroy(ASTContext &C) { + C.Deallocate(const_cast<char*>(StrData)); + this->~StringLiteral(); + C.Deallocate(this); +} + +void StringLiteral::setStrData(ASTContext &C, const char *Str, unsigned Len) { + if (StrData) + C.Deallocate(const_cast<char*>(StrData)); + + char *AStrData = new (C, 1) char[Len]; + memcpy(AStrData, Str, Len); + StrData = AStrData; + ByteLength = Len; +} + +/// 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 Extension: return "__extension__"; + case OffsetOf: return "__builtin_offsetof"; + } +} + +UnaryOperator::Opcode +UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { + switch (OO) { + default: assert(false && "No unary operator for overloaded function"); + case OO_PlusPlus: return Postfix ? PostInc : PreInc; + case OO_MinusMinus: return Postfix ? PostDec : PreDec; + case OO_Amp: return AddrOf; + case OO_Star: return Deref; + case OO_Plus: return Plus; + case OO_Minus: return Minus; + case OO_Tilde: return Not; + case OO_Exclaim: return LNot; + } +} + +OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { + switch (Opc) { + case PostInc: case PreInc: return OO_PlusPlus; + case PostDec: case PreDec: return OO_MinusMinus; + case AddrOf: return OO_Amp; + case Deref: return OO_Star; + case Plus: return OO_Plus; + case Minus: return OO_Minus; + case Not: return OO_Tilde; + case LNot: return OO_Exclaim; + default: return OO_None; + } +} + + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, Expr **args, + unsigned numargs, QualType t, SourceLocation rparenloc) + : Expr(SC, t, + fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), + fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, + QualType t, SourceLocation rparenloc) + : Expr(CallExprClass, t, + fn->isTypeDependent() || hasAnyTypeDependentArguments(args, numargs), + fn->isValueDependent() || hasAnyValueDependentArguments(args,numargs)), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+1]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) + SubExprs[i+ARGS_START] = args[i]; + + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext &C, EmptyShell Empty) + : Expr(CallExprClass, Empty), SubExprs(0), NumArgs(0) { + SubExprs = new (C) Stmt*[1]; +} + +void CallExpr::Destroy(ASTContext& C) { + DestroyChildren(C); + if (SubExprs) C.Deallocate(SubExprs); + this->~CallExpr(); + C.Deallocate(this); +} + +/// 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(ASTContext& C, 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) + getArg(i)->Destroy(C); + this->NumArgs = NumArgs; + return; + } + + // Otherwise, we are growing the # arguments. New an bigger argument array. + Stmt **NewSubExprs = new Stmt*[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; + + if (SubExprs) C.Deallocate(SubExprs); + SubExprs = NewSubExprs; + this->NumArgs = NumArgs; +} + +/// isBuiltinCall - If this is a call to a builtin, return the builtin ID. If +/// not, return 0. +unsigned CallExpr::isBuiltinCall(ASTContext &Context) 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 0; + + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr()); + if (!DRE) + return 0; + + const FunctionDecl *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()); + if (!FDecl) + return 0; + + if (!FDecl->getIdentifier()) + return 0; + + return FDecl->getBuiltinID(Context); +} + +QualType CallExpr::getCallReturnType() const { + QualType CalleeType = getCallee()->getType(); + if (const PointerType *FnTypePtr = CalleeType->getAsPointerType()) + CalleeType = FnTypePtr->getPointeeType(); + else if (const BlockPointerType *BPT = CalleeType->getAsBlockPointerType()) + CalleeType = BPT->getPointeeType(); + + const FunctionType *FnType = CalleeType->getAsFunctionType(); + return FnType->getResultType(); +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + case PtrMemD: return ".*"; + case PtrMemI: return "->*"; + 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 ","; + } + + return ""; +} + +BinaryOperator::Opcode +BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { + switch (OO) { + default: assert(false && "Not an overloadable binary operator"); + case OO_Plus: return Add; + case OO_Minus: return Sub; + case OO_Star: return Mul; + case OO_Slash: return Div; + case OO_Percent: return Rem; + case OO_Caret: return Xor; + case OO_Amp: return And; + case OO_Pipe: return Or; + case OO_Equal: return Assign; + case OO_Less: return LT; + case OO_Greater: return GT; + case OO_PlusEqual: return AddAssign; + case OO_MinusEqual: return SubAssign; + case OO_StarEqual: return MulAssign; + case OO_SlashEqual: return DivAssign; + case OO_PercentEqual: return RemAssign; + case OO_CaretEqual: return XorAssign; + case OO_AmpEqual: return AndAssign; + case OO_PipeEqual: return OrAssign; + case OO_LessLess: return Shl; + case OO_GreaterGreater: return Shr; + case OO_LessLessEqual: return ShlAssign; + case OO_GreaterGreaterEqual: return ShrAssign; + case OO_EqualEqual: return EQ; + case OO_ExclaimEqual: return NE; + case OO_LessEqual: return LE; + case OO_GreaterEqual: return GE; + case OO_AmpAmp: return LAnd; + case OO_PipePipe: return LOr; + case OO_Comma: return Comma; + case OO_ArrowStar: return PtrMemI; + } +} + +OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { + static const OverloadedOperatorKind OverOps[] = { + /* .* Cannot be overloaded */OO_None, OO_ArrowStar, + OO_Star, OO_Slash, OO_Percent, + OO_Plus, OO_Minus, + OO_LessLess, OO_GreaterGreater, + OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual, + OO_EqualEqual, OO_ExclaimEqual, + OO_Amp, + OO_Caret, + OO_Pipe, + OO_AmpAmp, + OO_PipePipe, + OO_Equal, OO_StarEqual, + OO_SlashEqual, OO_PercentEqual, + OO_PlusEqual, OO_MinusEqual, + OO_LessLessEqual, OO_GreaterGreaterEqual, + OO_AmpEqual, OO_CaretEqual, + OO_PipeEqual, + OO_Comma + }; + return OverOps[Opc]; +} + +InitListExpr::InitListExpr(SourceLocation lbraceloc, + Expr **initExprs, unsigned numInits, + SourceLocation rbraceloc) + : Expr(InitListExprClass, QualType(), + hasAnyTypeDependentArguments(initExprs, numInits), + hasAnyValueDependentArguments(initExprs, numInits)), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), + UnionFieldInit(0), HadArrayRangeDesignator(false) { + + InitExprs.insert(InitExprs.end(), initExprs, initExprs+numInits); +} + +void InitListExpr::reserveInits(unsigned NumInits) { + if (NumInits > InitExprs.size()) + InitExprs.reserve(NumInits); +} + +void InitListExpr::resizeInits(ASTContext &Context, unsigned NumInits) { + for (unsigned Idx = NumInits, LastIdx = InitExprs.size(); + Idx < LastIdx; ++Idx) + InitExprs[Idx]->Destroy(Context); + InitExprs.resize(NumInits, 0); +} + +Expr *InitListExpr::updateInit(unsigned Init, Expr *expr) { + if (Init >= InitExprs.size()) { + InitExprs.insert(InitExprs.end(), Init - InitExprs.size() + 1, 0); + InitExprs.back() = expr; + return 0; + } + + Expr *Result = cast_or_null<Expr>(InitExprs[Init]); + InitExprs[Init] = expr; + return Result; +} + +/// getFunctionType - Return the underlying function type for this block. +/// +const FunctionType *BlockExpr::getFunctionType() const { + return getType()->getAsBlockPointerType()-> + getPointeeType()->getAsFunctionType(); +} + +SourceLocation BlockExpr::getCaretLocation() const { + return TheBlock->getCaretLocation(); +} +const Stmt *BlockExpr::getBody() const { + return TheBlock->getBody(); +} +Stmt *BlockExpr::getBody() { + return TheBlock->getBody(); +} + + +//===----------------------------------------------------------------------===// +// Generic Expression Routines +//===----------------------------------------------------------------------===// + +/// isUnusedResultAWarning - Return true if this immediate expression should +/// be warned about if the result is unused. If so, fill in Loc and Ranges +/// with location to warn on and the source range[s] to report with the +/// warning. +bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, + SourceRange &R2) const { + // Don't warn if the expr is type dependent. The type could end up + // instantiating to void. + if (isTypeDependent()) + return false; + + switch (getStmtClass()) { + default: + Loc = getExprLoc(); + R1 = getSourceRange(); + return true; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()-> + isUnusedResultAWarning(Loc, R1, R2); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(this); + + switch (UO->getOpcode()) { + default: break; + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: // ++/-- + return false; // Not a warning. + case UnaryOperator::Deref: + // Dereferencing a volatile pointer is a side-effect. + if (getType().isVolatileQualified()) + return false; + break; + case UnaryOperator::Real: + case UnaryOperator::Imag: + // accessing a piece of a volatile complex is a side-effect. + if (UO->getSubExpr()->getType().isVolatileQualified()) + return false; + break; + case UnaryOperator::Extension: + return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + } + Loc = UO->getOperatorLoc(); + R1 = UO->getSubExpr()->getSourceRange(); + return true; + } + case BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(this); + // Consider comma to have side effects if the LHS or RHS does. + if (BO->getOpcode() == BinaryOperator::Comma) + return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2) || + BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2); + + if (BO->isAssignmentOp()) + return false; + Loc = BO->getOperatorLoc(); + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return true; + } + case CompoundAssignOperatorClass: + return false; + + case ConditionalOperatorClass: { + // The condition must be evaluated, but if either the LHS or RHS is a + // warning, warn about them. + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + if (Exp->getLHS() && Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2)) + return true; + return Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2); + } + + case MemberExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // it is a side effect. + if (getType().isVolatileQualified()) + return false; + Loc = cast<MemberExpr>(this)->getMemberLoc(); + R1 = SourceRange(Loc, Loc); + R2 = cast<MemberExpr>(this)->getBase()->getSourceRange(); + return true; + + case ArraySubscriptExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // it is a side effect. + if (getType().isVolatileQualified()) + return false; + Loc = cast<ArraySubscriptExpr>(this)->getRBracketLoc(); + R1 = cast<ArraySubscriptExpr>(this)->getLHS()->getSourceRange(); + R2 = cast<ArraySubscriptExpr>(this)->getRHS()->getSourceRange(); + return true; + + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + // If this is a direct call, get the callee. + const CallExpr *CE = cast<CallExpr>(this); + const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); + if (const DeclRefExpr *CalleeDRE = dyn_cast<DeclRefExpr>(CalleeExpr)) { + // If the callee has attribute pure, const, or warn_unused_result, warn + // about it. void foo() { strlen("bar"); } should warn. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeDRE->getDecl())) + if (FD->getAttr<WarnUnusedResultAttr>() || + FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { + Loc = CE->getCallee()->getLocStart(); + R1 = CE->getCallee()->getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getLocStart(), + CE->getArg(NumArgs-1)->getLocEnd()); + return true; + } + } + return false; + } + case ObjCMessageExprClass: + return false; + case StmtExprClass: { + // Statement exprs don't logically have side effects themselves, but are + // sometimes used in macros in ways that give them a type that is unused. + // For example ({ blah; foo(); }) will end up with a type if foo has a type. + // however, if the result of the stmt expr is dead, we don't want to emit a + // warning. + const CompoundStmt *CS = cast<StmtExpr>(this)->getSubStmt(); + if (!CS->body_empty()) + if (const Expr *E = dyn_cast<Expr>(CS->body_back())) + return E->isUnusedResultAWarning(Loc, R1, R2); + + Loc = cast<StmtExpr>(this)->getLParenLoc(); + R1 = getSourceRange(); + return true; + } + case CStyleCastExprClass: + // 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()->isUnusedResultAWarning(Loc, + R1, R2); + Loc = cast<CStyleCastExpr>(this)->getLParenLoc(); + R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); + return true; + case CXXFunctionalCastExprClass: + // 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()->isUnusedResultAWarning(Loc, + R1, R2); + Loc = cast<CXXFunctionalCastExpr>(this)->getTypeBeginLoc(); + R1 = cast<CXXFunctionalCastExpr>(this)->getSubExpr()->getSourceRange(); + return true; + + case ImplicitCastExprClass: + // Check the operand, since implicit casts are inserted by Sema + return cast<ImplicitCastExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this) + ->getExpr()->isUnusedResultAWarning(Loc, R1, R2); + + case CXXNewExprClass: + // FIXME: In theory, there might be new expressions that don't have side + // effects (e.g. a placement new with an uninitialized POD). + case CXXDeleteExprClass: + return false; + case CXXExprWithTemporariesClass: + return cast<CXXExprWithTemporaries>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2); + } +} + +/// DeclCanBeLvalue - Determine whether the given declaration can be +/// an lvalue. This is a helper routine for isLvalue. +static bool DeclCanBeLvalue(const NamedDecl *Decl, ASTContext &Ctx) { + // C++ [temp.param]p6: + // A non-type non-reference template-parameter is not an lvalue. + if (const NonTypeTemplateParmDecl *NTTParm + = dyn_cast<NonTypeTemplateParmDecl>(Decl)) + return NTTParm->getType()->isReferenceType(); + + return isa<VarDecl>(Decl) || isa<FieldDecl>(Decl) || + // C++ 3.10p2: An lvalue refers to an object or function. + (Ctx.getLangOptions().CPlusPlus && + (isa<FunctionDecl>(Decl) || isa<OverloadedFunctionDecl>(Decl))); +} + +/// 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(ASTContext &Ctx) const { + assert(!TR->isReferenceType() && "Expressions can't have reference type."); + + isLvalueResult Res = isLvalueInternal(Ctx); + if (Res != LV_Valid || Ctx.getLangOptions().CPlusPlus) + return Res; + + // first, check the type (C99 6.3.2.1). Expressions with function + // type in C are not lvalues, but they can be lvalues in C++. + if (TR->isFunctionType()) + return LV_NotObjectType; + + // Allow qualified void which is an incomplete type other than void (yuck). + if (TR->isVoidType() && !Ctx.getCanonicalType(TR).getCVRQualifiers()) + return LV_IncompleteVoidType; + + return LV_Valid; +} + +// Check whether the expression can be sanely treated like an l-value +Expr::isLvalueResult Expr::isLvalueInternal(ASTContext &Ctx) const { + switch (getStmtClass()) { + case StringLiteralClass: // C99 6.5.1p4 + case ObjCEncodeExprClass: // @encode behaves like its string in every way. + 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(Ctx); + return LV_Valid; + case DeclRefExprClass: + case QualifiedDeclRefExprClass: { // C99 6.5.1p2 + const NamedDecl *RefdDecl = cast<DeclRefExpr>(this)->getDecl(); + if (DeclCanBeLvalue(RefdDecl, Ctx)) + return LV_Valid; + break; + } + case BlockDeclRefExprClass: { + const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this); + if (isa<VarDecl>(BDR->getDecl())) + return LV_Valid; + break; + } + case MemberExprClass: { + const MemberExpr *m = cast<MemberExpr>(this); + if (Ctx.getLangOptions().CPlusPlus) { // C++ [expr.ref]p4: + NamedDecl *Member = m->getMemberDecl(); + // C++ [expr.ref]p4: + // If E2 is declared to have type "reference to T", then E1.E2 + // is an lvalue. + if (ValueDecl *Value = dyn_cast<ValueDecl>(Member)) + if (Value->getType()->isReferenceType()) + return LV_Valid; + + // -- If E2 is a static data member [...] then E1.E2 is an lvalue. + if (isa<VarDecl>(Member) && Member->getDeclContext()->isRecord()) + return LV_Valid; + + // -- If E2 is a non-static data member [...]. If E1 is an + // lvalue, then E1.E2 is an lvalue. + if (isa<FieldDecl>(Member)) + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + + // -- If it refers to a static member function [...], then + // E1.E2 is an lvalue. + // -- Otherwise, if E1.E2 refers to a non-static member + // function [...], then E1.E2 is not an lvalue. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) + return Method->isStatic()? LV_Valid : LV_MemberFunction; + + // -- If E2 is a member enumerator [...], the expression E1.E2 + // is not an lvalue. + if (isa<EnumConstantDecl>(Member)) + return LV_InvalidExpression; + + // Not an lvalue. + return LV_InvalidExpression; + } + + // C99 6.5.2.3p4 + return m->isArrow() ? LV_Valid : m->getBase()->isLvalue(Ctx); + } + 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 || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::Extension) + return cast<UnaryOperator>(this)->getSubExpr()->isLvalue(Ctx); // GNU. + + if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.pre.incr]p1 + (cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreInc || + cast<UnaryOperator>(this)->getOpcode() == UnaryOperator::PreDec)) + return LV_Valid; + break; + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->isLvalueCast()? LV_Valid + : LV_InvalidExpression; + case ParenExprClass: // C99 6.5.1p5 + return cast<ParenExpr>(this)->getSubExpr()->isLvalue(Ctx); + case BinaryOperatorClass: + case CompoundAssignOperatorClass: { + const BinaryOperator *BinOp = cast<BinaryOperator>(this); + + if (Ctx.getLangOptions().CPlusPlus && // C++ [expr.comma]p1 + BinOp->getOpcode() == BinaryOperator::Comma) + return BinOp->getRHS()->isLvalue(Ctx); + + // C++ [expr.mptr.oper]p6 + if ((BinOp->getOpcode() == BinaryOperator::PtrMemD || + BinOp->getOpcode() == BinaryOperator::PtrMemI) && + !BinOp->getType()->isFunctionType()) + return BinOp->getLHS()->isLvalue(Ctx); + + if (!BinOp->isAssignmentOp()) + return LV_InvalidExpression; + + if (Ctx.getLangOptions().CPlusPlus) + // C++ [expr.ass]p1: + // The result of an assignment operation [...] is an lvalue. + return LV_Valid; + + + // C99 6.5.16: + // An assignment expression [...] is not an lvalue. + return LV_InvalidExpression; + } + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + // C++0x [expr.call]p10 + // A function call is an lvalue if and only if the result type + // is an lvalue reference. + QualType ReturnType = cast<CallExpr>(this)->getCallReturnType(); + if (ReturnType->isLValueReferenceType()) + return LV_Valid; + + break; + } + case CompoundLiteralExprClass: // C99 6.5.2.5p5 + return LV_Valid; + case ChooseExprClass: + // __builtin_choose_expr is an lvalue if the selected operand is. + return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx)->isLvalue(Ctx); + case ExtVectorElementExprClass: + if (cast<ExtVectorElementExpr>(this)->containsDuplicateElements()) + return LV_DuplicateVectorComponents; + return LV_Valid; + case ObjCIvarRefExprClass: // ObjC instance variables are lvalues. + return LV_Valid; + case ObjCPropertyRefExprClass: // FIXME: check if read-only property. + return LV_Valid; + case ObjCKVCRefExprClass: // FIXME: check if read-only property. + return LV_Valid; + case PredefinedExprClass: + return LV_Valid; + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr()->isLvalue(Ctx); + case CXXConditionDeclExprClass: + return LV_Valid; + case CStyleCastExprClass: + case CXXFunctionalCastExprClass: + case CXXStaticCastExprClass: + case CXXDynamicCastExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + // The result of an explicit cast is an lvalue if the type we are + // casting to is an lvalue reference type. See C++ [expr.cast]p1, + // C++ [expr.static.cast]p2, C++ [expr.dynamic.cast]p2, + // C++ [expr.reinterpret.cast]p1, C++ [expr.const.cast]p1. + if (cast<ExplicitCastExpr>(this)->getTypeAsWritten()-> + isLValueReferenceType()) + return LV_Valid; + break; + case CXXTypeidExprClass: + // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ... + return LV_Valid; + case ConditionalOperatorClass: { + // Complicated handling is only for C++. + if (!Ctx.getLangOptions().CPlusPlus) + return LV_InvalidExpression; + + // Sema should have taken care to ensure that a CXXTemporaryObjectExpr is + // everywhere there's an object converted to an rvalue. Also, any other + // casts should be wrapped by ImplicitCastExprs. There's just the special + // case involving throws to work out. + const ConditionalOperator *Cond = cast<ConditionalOperator>(this); + Expr *True = Cond->getTrueExpr(); + Expr *False = Cond->getFalseExpr(); + // C++0x 5.16p2 + // If either the second or the third operand has type (cv) void, [...] + // the result [...] is an rvalue. + if (True->getType()->isVoidType() || False->getType()->isVoidType()) + return LV_InvalidExpression; + + // Both sides must be lvalues for the result to be an lvalue. + if (True->isLvalue(Ctx) != LV_Valid || False->isLvalue(Ctx) != LV_Valid) + return LV_InvalidExpression; + + // That's it. + 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(ASTContext &Ctx, SourceLocation *Loc) const { + isLvalueResult lvalResult = isLvalue(Ctx); + + switch (lvalResult) { + case LV_Valid: + // C++ 3.10p11: Functions cannot be modified, but pointers to + // functions can be modifiable. + if (Ctx.getLangOptions().CPlusPlus && TR->isFunctionType()) + return MLV_NotObjectType; + break; + + case LV_NotObjectType: return MLV_NotObjectType; + case LV_IncompleteVoidType: return MLV_IncompleteVoidType; + case LV_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; + case LV_InvalidExpression: + // If the top level is a C-style cast, and the subexpression is a valid + // lvalue, then this is probably a use of the old-school "cast as lvalue" + // GCC extension. We don't support it, but we want to produce good + // diagnostics when it happens so that the user knows why. + if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(IgnoreParens())) { + if (CE->getSubExpr()->isLvalue(Ctx) == LV_Valid) { + if (Loc) + *Loc = CE->getLParenLoc(); + return MLV_LValueCast; + } + } + return MLV_InvalidExpression; + case LV_MemberFunction: return MLV_MemberFunction; + } + + // The following is illegal: + // void takeclosure(void (^C)(void)); + // void func() { int x = 1; takeclosure(^{ x = 7; }); } + // + if (isa<BlockDeclRefExpr>(this)) { + const BlockDeclRefExpr *BDR = cast<BlockDeclRefExpr>(this); + if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl())) + return MLV_NotBlockQualified; + } + + QualType CT = Ctx.getCanonicalType(getType()); + + if (CT.isConstQualified()) + return MLV_ConstQualified; + if (CT->isArrayType()) + return MLV_ArrayType; + if (CT->isIncompleteType()) + return MLV_IncompleteType; + + if (const RecordType *r = CT->getAsRecordType()) { + if (r->hasConstFields()) + return MLV_ConstQualified; + } + + // Assigning to an 'implicit' property? + else if (isa<ObjCKVCRefExpr>(this)) { + const ObjCKVCRefExpr* KVCExpr = cast<ObjCKVCRefExpr>(this); + if (KVCExpr->getSetterMethod() == 0) + return MLV_NoSetterProperty; + } + 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 BlockExprClass: + return true; + 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: + case QualifiedDeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + return VD->hasGlobalStorage(); + if (isa<FunctionDecl>(D)) + return true; + 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; + case CXXDefaultArgExprClass: + return cast<CXXDefaultArgExpr>(this)->getExpr()->hasGlobalStorage(); + } +} + +/// isOBJCGCCandidate - Check if an expression is objc gc'able. +/// +bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { + switch (getStmtClass()) { + default: + return false; + case ObjCIvarRefExprClass: + return true; + case Expr::UnaryOperatorClass: + return cast<UnaryOperator>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case CStyleCastExprClass: + return cast<CStyleCastExpr>(this)->getSubExpr()->isOBJCGCCandidate(Ctx); + case DeclRefExprClass: + case QualifiedDeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(this)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasGlobalStorage()) + return true; + QualType T = VD->getType(); + // dereferencing to an object pointer is always a gc'able candidate + if (T->isPointerType() && + Ctx.isObjCObjectPointerType(T->getAsPointerType()->getPointeeType())) + return true; + + } + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(this); + return M->getBase()->isOBJCGCCandidate(Ctx); + } + case ArraySubscriptExprClass: + return cast<ArraySubscriptExpr>(this)->getBase()->isOBJCGCCandidate(Ctx); + } +} +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 + return E; + } +} + +/// IgnoreParenNoopCasts - Ignore parentheses and casts that do not change the +/// value (including ptr->int casts of the same size). Strip off any +/// ParenExpr or CastExprs, returning their operand. +Expr *Expr::IgnoreParenNoopCasts(ASTContext &Ctx) { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } + + if (CastExpr *P = dyn_cast<CastExpr>(E)) { + // We ignore integer <-> casts that are of the same width, ptr<->ptr and + // ptr<->int casts of the same width. We also ignore all identify casts. + Expr *SE = P->getSubExpr(); + + if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { + E = SE; + continue; + } + + if ((E->getType()->isPointerType() || E->getType()->isIntegralType()) && + (SE->getType()->isPointerType() || SE->getType()->isIntegralType()) && + Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { + E = SE; + continue; + } + } + + return E; + } +} + + +/// hasAnyTypeDependentArguments - Determines if any of the expressions +/// in Exprs is type-dependent. +bool Expr::hasAnyTypeDependentArguments(Expr** Exprs, unsigned NumExprs) { + for (unsigned I = 0; I < NumExprs; ++I) + if (Exprs[I]->isTypeDependent()) + return true; + + return false; +} + +/// hasAnyValueDependentArguments - Determines if any of the expressions +/// in Exprs is value-dependent. +bool Expr::hasAnyValueDependentArguments(Expr** Exprs, unsigned NumExprs) { + for (unsigned I = 0; I < NumExprs; ++I) + if (Exprs[I]->isValueDependent()) + return true; + + return false; +} + +bool Expr::isConstantInitializer(ASTContext &Ctx) const { + // This function is attempting whether an expression is an initializer + // which can be evaluated at compile-time. isEvaluatable handles most + // of the cases, but it can't deal with some initializer-specific + // expressions, and it can't deal with aggregates; we deal with those here, + // and fall back to isEvaluatable for the other cases. + + // FIXME: This function assumes the variable being assigned to + // isn't a reference type! + + switch (getStmtClass()) { + default: break; + case StringLiteralClass: + case ObjCEncodeExprClass: + return true; + case CompoundLiteralExprClass: { + // This handles gcc's extension that allows global initializers like + // "struct x {int x;} x = (struct x) {};". + // FIXME: This accepts other cases it shouldn't! + const Expr *Exp = cast<CompoundLiteralExpr>(this)->getInitializer(); + return Exp->isConstantInitializer(Ctx); + } + case InitListExprClass: { + // FIXME: This doesn't deal with fields with reference types correctly. + // FIXME: This incorrectly allows pointers cast to integers to be assigned + // to bitfields. + const InitListExpr *Exp = cast<InitListExpr>(this); + unsigned numInits = Exp->getNumInits(); + for (unsigned i = 0; i < numInits; i++) { + if (!Exp->getInit(i)->isConstantInitializer(Ctx)) + return false; + } + return true; + } + case ImplicitValueInitExprClass: + return true; + case ParenExprClass: { + return cast<ParenExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + } + case UnaryOperatorClass: { + const UnaryOperator* Exp = cast<UnaryOperator>(this); + if (Exp->getOpcode() == UnaryOperator::Extension) + return Exp->getSubExpr()->isConstantInitializer(Ctx); + break; + } + case ImplicitCastExprClass: + case CStyleCastExprClass: + // Handle casts with a destination that's a struct or union; this + // deals with both the gcc no-op struct cast extension and the + // cast-to-union extension. + if (getType()->isRecordType()) + return cast<CastExpr>(this)->getSubExpr()->isConstantInitializer(Ctx); + break; + } + + return isEvaluatable(Ctx); +} + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. + +/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero, +/// comma, etc +/// +/// 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. + +// CheckICE - This function does the fundamental ICE checking: the returned +// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation. +// Note that to reduce code duplication, this helper does no evaluation +// itself; the caller checks whether the expression is evaluatable, and +// in the rare cases where CheckICE actually cares about the evaluated +// value, it calls into Evalute. +// +// Meanings of Val: +// 0: This expression is an ICE if it can be evaluated by Evaluate. +// 1: This expression is not an ICE, but if it isn't evaluated, it's +// a legal subexpression for an ICE. This return value is used to handle +// the comma operator in C99 mode. +// 2: This expression is not an ICE, and is not a legal subexpression for one. + +struct ICEDiag { + unsigned Val; + SourceLocation Loc; + + public: + ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {} + ICEDiag() : Val(0) {} +}; + +ICEDiag NoDiag() { return ICEDiag(); } + +static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); +} + +static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { + assert(!E->isValueDependent() && "Should not see value dependent exprs!"); + if (!E->getType()->isIntegralType()) { + return ICEDiag(2, E->getLocStart()); + } + + switch (E->getStmtClass()) { + default: + return ICEDiag(2, E->getLocStart()); + case Expr::ParenExprClass: + return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXZeroInitValueExprClass: + case Expr::TypesCompatibleExprClass: + case Expr::UnaryTypeTraitExprClass: + return NoDiag(); + case Expr::CallExprClass: + case Expr::CXXOperatorCallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + if (CE->isBuiltinCall(Ctx)) + return CheckEvalInICE(E, Ctx); + return ICEDiag(2, E->getLocStart()); + } + case Expr::DeclRefExprClass: + case Expr::QualifiedDeclRefExprClass: + if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) + return NoDiag(); + if (Ctx.getLangOptions().CPlusPlus && + E->getType().getCVRQualifiers() == QualType::Const) { + // C++ 7.1.5.1p2 + // A variable of non-volatile const-qualified integral or enumeration + // type initialized by an ICE can be used in ICEs. + if (const VarDecl *Dcl = + dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { + if (Dcl->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (Dcl->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, E->getLocStart()); + } + + if (const Expr *Init = Dcl->getInit()) { + ICEDiag Result = CheckICE(Init, Ctx); + // Cache the result of the ICE test. + Dcl->setInitKnownICE(Ctx, Result.Val == 0); + return Result; + } + } + } + return ICEDiag(2, E->getLocStart()); + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + switch (Exp->getOpcode()) { + default: + return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + case UnaryOperator::Real: + case UnaryOperator::Imag: + return CheckICE(Exp->getSubExpr(), Ctx); + case UnaryOperator::OffsetOf: + // Note that per C99, offsetof must be an ICE. And AFAIK, using + // Evaluate matches the proposed gcc behavior for cases like + // "offsetof(struct s{int x[4];}, x[!.0])". This doesn't affect + // compliance: we should warn earlier for offsetof expressions with + // array subscripts that aren't ICEs, and if the array subscripts + // are ICEs, the value of the offsetof must be an integer constant. + return CheckEvalInICE(E, Ctx); + } + } + case Expr::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E); + if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(2, E->getLocStart()); + return NoDiag(); + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(E); + switch (Exp->getOpcode()) { + default: + return ICEDiag(2, E->getLocStart()); + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + case BinaryOperator::LT: + case BinaryOperator::GT: + case BinaryOperator::LE: + case BinaryOperator::GE: + case BinaryOperator::EQ: + case BinaryOperator::NE: + case BinaryOperator::And: + case BinaryOperator::Xor: + case BinaryOperator::Or: + case BinaryOperator::Comma: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (Exp->getOpcode() == BinaryOperator::Div || + Exp->getOpcode() == BinaryOperator::Rem) { + // Evaluate gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Val != 2 && RHSResult.Val != 2) { + llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); + if (REval == 0) + return ICEDiag(1, E->getLocStart()); + if (REval.isSigned() && REval.isAllOnesValue()) { + llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); + if (LEval.isMinSignedValue()) + return ICEDiag(1, E->getLocStart()); + } + } + } + if (Exp->getOpcode() == BinaryOperator::Comma) { + if (Ctx.getLangOptions().C99) { + // C99 6.6p3 introduces a strange edge case: comma can be in an ICE + // if it isn't evaluated. + if (LHSResult.Val == 0 && RHSResult.Val == 0) + return ICEDiag(1, E->getLocStart()); + } else { + // In both C89 and C++, commas in ICEs are illegal. + return ICEDiag(2, E->getLocStart()); + } + } + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + case BinaryOperator::LAnd: + case BinaryOperator::LOr: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (LHSResult.Val == 0 && RHSResult.Val == 1) { + // Rare case where the RHS has a comma "side-effect"; we need + // to actually check the condition to see whether the side + // with the comma is evaluated. + if ((Exp->getOpcode() == BinaryOperator::LAnd) != + (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) + return RHSResult; + return NoDiag(); + } + + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + } + } + case Expr::ImplicitCastExprClass: + case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); + if (SubExpr->getType()->isIntegralType()) + return CheckICE(SubExpr, Ctx); + if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast<ConditionalOperator>(E); + // If the condition (ignoring parens) is a __builtin_constant_p call, + // then only the true side is actually considered in an integer constant + // expression, and it is fully evaluated. This is an important GNU + // extension. See GCC PR38377 for discussion. + if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts())) + if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); + } + ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); + ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (CondResult.Val == 2) + return CondResult; + if (TrueResult.Val == 2) + return TrueResult; + if (FalseResult.Val == 2) + return FalseResult; + if (CondResult.Val == 1) + return CondResult; + if (TrueResult.Val == 0 && FalseResult.Val == 0) + return NoDiag(); + // Rare case where the diagnostics depend on which side is evaluated + // Note that if we get here, CondResult is 0, and at least one of + // TrueResult and FalseResult is non-zero. + if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { + return FalseResult; + } + return TrueResult; + } + case Expr::CXXDefaultArgExprClass: + return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); + case Expr::ChooseExprClass: { + return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(Ctx), Ctx); + } + } +} + +bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, + SourceLocation *Loc, bool isEvaluated) const { + ICEDiag d = CheckICE(this, Ctx); + if (d.Val != 0) { + if (Loc) *Loc = d.Loc; + return false; + } + EvalResult EvalResult; + if (!Evaluate(EvalResult, Ctx)) + assert(0 && "ICE cannot be evaluated!"); + assert(!EvalResult.HasSideEffects && "ICE with side effects!"); + assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); + Result = EvalResult.Val.getInt(); + 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. Except in C++. + if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(this)) { + if (!Ctx.getLangOptions().CPlusPlus) { + // 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); + } else if (const CXXDefaultArgExpr *DefaultArg + = dyn_cast<CXXDefaultArgExpr>(this)) { + // See through default argument expressions + return DefaultArg->getExpr()->isNullPointerConstant(Ctx); + } else if (isa<GNUNullExpr>(this)) { + // The GNU __null extension is always a null pointer constant. + return true; + } + + // C++0x nullptr_t is always a null pointer constant. + if (getType()->isNullPtrType()) + return true; + + // 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 Result; + return isIntegerConstantExpr(Result, Ctx) && Result == 0; +} + +FieldDecl *Expr::getBitField() { + Expr *E = this->IgnoreParenCasts(); + + if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) + if (Field->isBitField()) + return Field; + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) + if (BinOp->isAssignmentOp() && BinOp->getLHS()) + return BinOp->getLHS()->getBitField(); + + return 0; +} + +/// isArrow - Return true if the base expression is a pointer to vector, +/// return false if the base expression is a vector. +bool ExtVectorElementExpr::isArrow() const { + return getBase()->getType()->isPointerType(); +} + +unsigned ExtVectorElementExpr::getNumElements() const { + if (const VectorType *VT = getType()->getAsVectorType()) + return VT->getNumElements(); + return 1; +} + +/// containsDuplicateElements - Return true if any element access is repeated. +bool ExtVectorElementExpr::containsDuplicateElements() const { + const char *compStr = Accessor->getName(); + unsigned length = Accessor->getLength(); + + // Halving swizzles do not contain duplicate elements. + if (!strcmp(compStr, "hi") || !strcmp(compStr, "lo") || + !strcmp(compStr, "even") || !strcmp(compStr, "odd")) + return false; + + // Advance past s-char prefix on hex swizzles. + if (*compStr == 's') { + compStr++; + length--; + } + + 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 the fields as a llvm ConstantArray. +void ExtVectorElementExpr::getEncodedElementAccess( + llvm::SmallVectorImpl<unsigned> &Elts) const { + const char *compStr = Accessor->getName(); + if (*compStr == 's') + compStr++; + + bool isHi = !strcmp(compStr, "hi"); + bool isLo = !strcmp(compStr, "lo"); + bool isEven = !strcmp(compStr, "even"); + bool isOdd = !strcmp(compStr, "odd"); + + for (unsigned i = 0, e = getNumElements(); i != e; ++i) { + uint64_t Index; + + if (isHi) + Index = e + i; + else if (isLo) + Index = i; + else if (isEven) + Index = 2 * i; + else if (isOdd) + Index = 2 * i + 1; + else + Index = ExtVectorType::getAccessorIdx(compStr[i]); + + Elts.push_back(Index); + } +} + +// 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) { + NumArgs = nargs; + SubExprs = new Stmt*[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) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) clsName | IsClsMethDeclUnknown); + 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. +ObjCMessageExpr::ObjCMessageExpr(ObjCInterfaceDecl *cls, Selector selInfo, + QualType retType, ObjCMethodDecl *mproto, + SourceLocation LBrac, SourceLocation RBrac, + Expr **ArgExprs, unsigned nargs) +: Expr(ObjCMessageExprClass, retType), SelName(selInfo), +MethodProto(mproto) { + NumArgs = nargs; + SubExprs = new Stmt*[NumArgs+1]; + SubExprs[RECEIVER] = (Expr*) ((uintptr_t) cls | IsClsMethDeclKnown); + if (NumArgs) { + for (unsigned i = 0; i != NumArgs; ++i) + SubExprs[i+ARGS_START] = static_cast<Expr *>(ArgExprs[i]); + } + LBracloc = LBrac; + RBracloc = RBrac; +} + +ObjCMessageExpr::ClassInfo ObjCMessageExpr::getClassInfo() const { + uintptr_t x = (uintptr_t) SubExprs[RECEIVER]; + switch (x & Flags) { + default: + assert(false && "Invalid ObjCMessageExpr."); + case IsInstMeth: + return ClassInfo(0, 0); + case IsClsMethDeclUnknown: + return ClassInfo(0, (IdentifierInfo*) (x & ~Flags)); + case IsClsMethDeclKnown: { + ObjCInterfaceDecl* D = (ObjCInterfaceDecl*) (x & ~Flags); + return ClassInfo(D, D->getIdentifier()); + } + } +} + +void ObjCMessageExpr::setClassInfo(const ObjCMessageExpr::ClassInfo &CI) { + if (CI.first == 0 && CI.second == 0) + SubExprs[RECEIVER] = (Expr*)((uintptr_t)0 | IsInstMeth); + else if (CI.first == 0) + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.second | IsClsMethDeclUnknown); + else + SubExprs[RECEIVER] = (Expr*)((uintptr_t)CI.first | IsClsMethDeclKnown); +} + + +bool ChooseExpr::isConditionTrue(ASTContext &C) const { + return getCond()->EvaluateAsInt(C) != 0; +} + +void ShuffleVectorExpr::setExprs(Expr ** Exprs, unsigned NumExprs) { + if (NumExprs) + delete [] SubExprs; + + SubExprs = new Stmt* [NumExprs]; + this->NumExprs = NumExprs; + memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); +} + +void SizeOfAlignOfExpr::Destroy(ASTContext& C) { + // Override default behavior of traversing children. If this has a type + // operand and the type is a variable-length array, the child iteration + // will iterate over the size expression. However, this expression belongs + // to the type, not to this, so we don't want to delete it. + // We still want to delete this expression. + if (isArgumentType()) { + this->~SizeOfAlignOfExpr(); + C.Deallocate(this); + } + else + Expr::Destroy(C); +} + +//===----------------------------------------------------------------------===// +// DesignatedInitExpr +//===----------------------------------------------------------------------===// + +IdentifierInfo *DesignatedInitExpr::Designator::getFieldName() { + assert(Kind == FieldDesignator && "Only valid on a field designator"); + if (Field.NameOrField & 0x01) + return reinterpret_cast<IdentifierInfo *>(Field.NameOrField&~0x01); + else + return getField()->getIdentifier(); +} + +DesignatedInitExpr::DesignatedInitExpr(QualType Ty, unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, + Expr **IndexExprs, + unsigned NumIndexExprs, + Expr *Init) + : Expr(DesignatedInitExprClass, Ty, + Init->isTypeDependent(), Init->isValueDependent()), + EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + this->Designators = new Designator[NumDesignators]; + + // Record the initializer itself. + child_iterator Child = child_begin(); + *Child++ = Init; + + // Copy the designators and their subexpressions, computing + // value-dependence along the way. + unsigned IndexIdx = 0; + for (unsigned I = 0; I != NumDesignators; ++I) { + this->Designators[I] = Designators[I]; + + if (this->Designators[I].isArrayDesignator()) { + // Compute type- and value-dependence. + Expr *Index = IndexExprs[IndexIdx]; + ValueDependent = ValueDependent || + Index->isTypeDependent() || Index->isValueDependent(); + + // Copy the index expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + } else if (this->Designators[I].isArrayRangeDesignator()) { + // Compute type- and value-dependence. + Expr *Start = IndexExprs[IndexIdx]; + Expr *End = IndexExprs[IndexIdx + 1]; + ValueDependent = ValueDependent || + Start->isTypeDependent() || Start->isValueDependent() || + End->isTypeDependent() || End->isValueDependent(); + + // Copy the start/end expressions into permanent storage. + *Child++ = IndexExprs[IndexIdx++]; + *Child++ = IndexExprs[IndexIdx++]; + } + } + + assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions"); +} + +DesignatedInitExpr * +DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, + unsigned NumDesignators, + Expr **IndexExprs, unsigned NumIndexExprs, + SourceLocation ColonOrEqualLoc, + bool UsesColonSyntax, Expr *Init) { + void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + + sizeof(Stmt *) * (NumIndexExprs + 1), 8); + return new (Mem) DesignatedInitExpr(C.VoidTy, NumDesignators, Designators, + ColonOrEqualLoc, UsesColonSyntax, + IndexExprs, NumIndexExprs, Init); +} + +DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, + unsigned NumIndexExprs) { + void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + + sizeof(Stmt *) * (NumIndexExprs + 1), 8); + return new (Mem) DesignatedInitExpr(NumIndexExprs + 1); +} + +void DesignatedInitExpr::setDesignators(const Designator *Desigs, + unsigned NumDesigs) { + if (Designators) + delete [] Designators; + + Designators = new Designator[NumDesigs]; + NumDesignators = NumDesigs; + for (unsigned I = 0; I != NumDesigs; ++I) + Designators[I] = Desigs[I]; +} + +SourceRange DesignatedInitExpr::getSourceRange() const { + SourceLocation StartLoc; + Designator &First = + *const_cast<DesignatedInitExpr*>(this)->designators_begin(); + if (First.isFieldDesignator()) { + if (GNUSyntax) + StartLoc = SourceLocation::getFromRawEncoding(First.Field.FieldLoc); + else + StartLoc = SourceLocation::getFromRawEncoding(First.Field.DotLoc); + } else + StartLoc = + SourceLocation::getFromRawEncoding(First.ArrayOrRange.LBracketLoc); + return SourceRange(StartLoc, getInit()->getSourceRange().getEnd()); +} + +Expr *DesignatedInitExpr::getArrayIndex(const Designator& D) { + assert(D.Kind == Designator::ArrayDesignator && "Requires array designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); +} + +Expr *DesignatedInitExpr::getArrayRangeStart(const Designator& D) { + assert(D.Kind == Designator::ArrayRangeDesignator && + "Requires array range designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 1)); +} + +Expr *DesignatedInitExpr::getArrayRangeEnd(const Designator& D) { + assert(D.Kind == Designator::ArrayRangeDesignator && + "Requires array range designator"); + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + Stmt **SubExprs = reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); + return cast<Expr>(*(SubExprs + D.ArrayOrRange.Index + 2)); +} + +/// \brief Replaces the designator at index @p Idx with the series +/// of designators in [First, Last). +void DesignatedInitExpr::ExpandDesignator(unsigned Idx, + const Designator *First, + const Designator *Last) { + unsigned NumNewDesignators = Last - First; + if (NumNewDesignators == 0) { + std::copy_backward(Designators + Idx + 1, + Designators + NumDesignators, + Designators + Idx); + --NumNewDesignators; + return; + } else if (NumNewDesignators == 1) { + Designators[Idx] = *First; + return; + } + + Designator *NewDesignators + = new Designator[NumDesignators - 1 + NumNewDesignators]; + std::copy(Designators, Designators + Idx, NewDesignators); + std::copy(First, Last, NewDesignators + Idx); + std::copy(Designators + Idx + 1, Designators + NumDesignators, + NewDesignators + Idx + NumNewDesignators); + delete [] Designators; + Designators = NewDesignators; + NumDesignators = NumDesignators - 1 + NumNewDesignators; +} + +void DesignatedInitExpr::Destroy(ASTContext &C) { + delete [] Designators; + Expr::Destroy(C); +} + +ImplicitValueInitExpr *ImplicitValueInitExpr::Clone(ASTContext &C) const { + return new (C) ImplicitValueInitExpr(getType()); +} + +//===----------------------------------------------------------------------===// +// ExprIterator. +//===----------------------------------------------------------------------===// + +Expr* ExprIterator::operator[](size_t idx) { return cast<Expr>(I[idx]); } +Expr* ExprIterator::operator*() const { return cast<Expr>(*I); } +Expr* ExprIterator::operator->() const { return cast<Expr>(*I); } +const Expr* ConstExprIterator::operator[](size_t idx) const { + return cast<Expr>(I[idx]); +} +const Expr* ConstExprIterator::operator*() const { return cast<Expr>(*I); } +const Expr* ConstExprIterator::operator->() const { return cast<Expr>(*I); } + +//===----------------------------------------------------------------------===// +// 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 &Base; } +Stmt::child_iterator ObjCIvarRefExpr::child_end() { return &Base+1; } + +// ObjCPropertyRefExpr +Stmt::child_iterator ObjCPropertyRefExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCPropertyRefExpr::child_end() { return &Base+1; } + +// ObjCKVCRefExpr +Stmt::child_iterator ObjCKVCRefExpr::child_begin() { return &Base; } +Stmt::child_iterator ObjCKVCRefExpr::child_end() { return &Base+1; } + +// ObjCSuperExpr +Stmt::child_iterator ObjCSuperExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator ObjCSuperExpr::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 &Val; } +Stmt::child_iterator ImaginaryLiteral::child_end() { return &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 &Val; } +Stmt::child_iterator ParenExpr::child_end() { return &Val+1; } + +// UnaryOperator +Stmt::child_iterator UnaryOperator::child_begin() { return &Val; } +Stmt::child_iterator UnaryOperator::child_end() { return &Val+1; } + +// SizeOfAlignOfExpr +Stmt::child_iterator SizeOfAlignOfExpr::child_begin() { + // If this is of a type and the type is a VLA type (and not a typedef), the + // size expression of the VLA needs to be treated as an executable expression. + // Why isn't this weirdness documented better in StmtIterator? + if (isArgumentType()) { + if (VariableArrayType* T = dyn_cast<VariableArrayType>( + getArgumentType().getTypePtr())) + return child_iterator(T); + return child_iterator(); + } + return child_iterator(&Argument.Ex); +} +Stmt::child_iterator SizeOfAlignOfExpr::child_end() { + if (isArgumentType()) + return child_iterator(); + return child_iterator(&Argument.Ex + 1); +} + +// ArraySubscriptExpr +Stmt::child_iterator ArraySubscriptExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ArraySubscriptExpr::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// CallExpr +Stmt::child_iterator CallExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator CallExpr::child_end() { + return &SubExprs[0]+NumArgs+ARGS_START; +} + +// MemberExpr +Stmt::child_iterator MemberExpr::child_begin() { return &Base; } +Stmt::child_iterator MemberExpr::child_end() { return &Base+1; } + +// ExtVectorElementExpr +Stmt::child_iterator ExtVectorElementExpr::child_begin() { return &Base; } +Stmt::child_iterator ExtVectorElementExpr::child_end() { return &Base+1; } + +// CompoundLiteralExpr +Stmt::child_iterator CompoundLiteralExpr::child_begin() { return &Init; } +Stmt::child_iterator CompoundLiteralExpr::child_end() { return &Init+1; } + +// CastExpr +Stmt::child_iterator CastExpr::child_begin() { return &Op; } +Stmt::child_iterator CastExpr::child_end() { return &Op+1; } + +// BinaryOperator +Stmt::child_iterator BinaryOperator::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator BinaryOperator::child_end() { + return &SubExprs[0]+END_EXPR; +} + +// ConditionalOperator +Stmt::child_iterator ConditionalOperator::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ConditionalOperator::child_end() { + return &SubExprs[0]+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 &SubStmt; } +Stmt::child_iterator StmtExpr::child_end() { return &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 &SubExprs[0]; } +Stmt::child_iterator ChooseExpr::child_end() { return &SubExprs[0]+END_EXPR; } + +// GNUNullExpr +Stmt::child_iterator GNUNullExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator GNUNullExpr::child_end() { return child_iterator(); } + +// ShuffleVectorExpr +Stmt::child_iterator ShuffleVectorExpr::child_begin() { + return &SubExprs[0]; +} +Stmt::child_iterator ShuffleVectorExpr::child_end() { + return &SubExprs[0]+NumExprs; +} + +// VAArgExpr +Stmt::child_iterator VAArgExpr::child_begin() { return &Val; } +Stmt::child_iterator VAArgExpr::child_end() { return &Val+1; } + +// InitListExpr +Stmt::child_iterator InitListExpr::child_begin() { + return InitExprs.size() ? &InitExprs[0] : 0; +} +Stmt::child_iterator InitListExpr::child_end() { + return InitExprs.size() ? &InitExprs[0] + InitExprs.size() : 0; +} + +// DesignatedInitExpr +Stmt::child_iterator DesignatedInitExpr::child_begin() { + char* Ptr = static_cast<char*>(static_cast<void *>(this)); + Ptr += sizeof(DesignatedInitExpr); + return reinterpret_cast<Stmt**>(reinterpret_cast<void**>(Ptr)); +} +Stmt::child_iterator DesignatedInitExpr::child_end() { + return child_iterator(&*child_begin() + NumSubExprs); +} + +// ImplicitValueInitExpr +Stmt::child_iterator ImplicitValueInitExpr::child_begin() { + return child_iterator(); +} + +Stmt::child_iterator ImplicitValueInitExpr::child_end() { + return child_iterator(); +} + +// ObjCStringLiteral +Stmt::child_iterator ObjCStringLiteral::child_begin() { + return &String; +} +Stmt::child_iterator ObjCStringLiteral::child_end() { + return &String+1; +} + +// 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 getReceiver() ? &SubExprs[0] : &SubExprs[0] + ARGS_START; +} +Stmt::child_iterator ObjCMessageExpr::child_end() { + return &SubExprs[0]+ARGS_START+getNumArgs(); +} + +// Blocks +Stmt::child_iterator BlockExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator BlockExpr::child_end() { return child_iterator(); } + +Stmt::child_iterator BlockDeclRefExpr::child_begin() { return child_iterator();} +Stmt::child_iterator BlockDeclRefExpr::child_end() { return child_iterator(); } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp new file mode 100644 index 0000000..4a15245 --- /dev/null +++ b/lib/AST/ExprCXX.cpp @@ -0,0 +1,424 @@ +//===--- 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/Basic/IdentifierTable.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/ExprCXX.h" +using namespace clang; + +void CXXConditionDeclExpr::Destroy(ASTContext& C) { + // FIXME: Cannot destroy the decl here, because it is linked into the + // DeclContext's chain. + //getVarDecl()->Destroy(C); + this->~CXXConditionDeclExpr(); + C.Deallocate(this); +} + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +// CXXTypeidExpr - has child iterators if the operand is an expression +Stmt::child_iterator CXXTypeidExpr::child_begin() { + return isTypeOperand() ? child_iterator() : &Operand.Ex; +} +Stmt::child_iterator CXXTypeidExpr::child_end() { + return isTypeOperand() ? child_iterator() : &Operand.Ex+1; +} + +// CXXBoolLiteralExpr +Stmt::child_iterator CXXBoolLiteralExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXBoolLiteralExpr::child_end() { + return child_iterator(); +} + +// CXXNullPtrLiteralExpr +Stmt::child_iterator CXXNullPtrLiteralExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXNullPtrLiteralExpr::child_end() { + return child_iterator(); +} + +// CXXThisExpr +Stmt::child_iterator CXXThisExpr::child_begin() { return child_iterator(); } +Stmt::child_iterator CXXThisExpr::child_end() { return child_iterator(); } + +// CXXThrowExpr +Stmt::child_iterator CXXThrowExpr::child_begin() { return &Op; } +Stmt::child_iterator CXXThrowExpr::child_end() { + // If Op is 0, we are processing throw; which has no children. + return Op ? &Op+1 : &Op; +} + +// CXXDefaultArgExpr +Stmt::child_iterator CXXDefaultArgExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXDefaultArgExpr::child_end() { + return child_iterator(); +} + +// CXXZeroInitValueExpr +Stmt::child_iterator CXXZeroInitValueExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator CXXZeroInitValueExpr::child_end() { + return child_iterator(); +} + +// CXXConditionDeclExpr +Stmt::child_iterator CXXConditionDeclExpr::child_begin() { + return getVarDecl(); +} +Stmt::child_iterator CXXConditionDeclExpr::child_end() { + return child_iterator(); +} + +// CXXNewExpr +CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, + Expr **placementArgs, unsigned numPlaceArgs, + bool parenTypeId, Expr *arraySize, + CXXConstructorDecl *constructor, bool initializer, + Expr **constructorArgs, unsigned numConsArgs, + FunctionDecl *operatorDelete, QualType ty, + SourceLocation startLoc, SourceLocation endLoc) + : Expr(CXXNewExprClass, ty, ty->isDependentType(), ty->isDependentType()), + GlobalNew(globalNew), ParenTypeId(parenTypeId), + Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs), + NumConstructorArgs(numConsArgs), OperatorNew(operatorNew), + OperatorDelete(operatorDelete), Constructor(constructor), + StartLoc(startLoc), EndLoc(endLoc) +{ + unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; + SubExprs = new Stmt*[TotalSize]; + unsigned i = 0; + if (Array) + SubExprs[i++] = arraySize; + for (unsigned j = 0; j < NumPlacementArgs; ++j) + SubExprs[i++] = placementArgs[j]; + for (unsigned j = 0; j < NumConstructorArgs; ++j) + SubExprs[i++] = constructorArgs[j]; + assert(i == TotalSize); +} + +Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; } +Stmt::child_iterator CXXNewExpr::child_end() { + return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs(); +} + +// CXXDeleteExpr +Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; } +Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; } + +// UnresolvedFunctionNameExpr +Stmt::child_iterator UnresolvedFunctionNameExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator UnresolvedFunctionNameExpr::child_end() { + return child_iterator(); +} + +UnresolvedFunctionNameExpr* +UnresolvedFunctionNameExpr::Clone(ASTContext &C) const { + return new (C) UnresolvedFunctionNameExpr(Name, getType(), Loc); +} + +// UnaryTypeTraitExpr +Stmt::child_iterator UnaryTypeTraitExpr::child_begin() { + return child_iterator(); +} +Stmt::child_iterator UnaryTypeTraitExpr::child_end() { + return child_iterator(); +} + +// UnresolvedDeclRefExpr +StmtIterator UnresolvedDeclRefExpr::child_begin() { + return child_iterator(); +} + +StmtIterator UnresolvedDeclRefExpr::child_end() { + return child_iterator(); +} + +bool UnaryTypeTraitExpr::EvaluateTrait() const { + switch(UTT) { + default: assert(false && "Unknown type trait or not implemented"); + case UTT_IsPOD: return QueriedType->isPODType(); + case UTT_IsClass: // Fallthrough + case UTT_IsUnion: + if (const RecordType *Record = QueriedType->getAsRecordType()) { + bool Union = Record->getDecl()->isUnion(); + return UTT == UTT_IsUnion ? Union : !Union; + } + return false; + case UTT_IsEnum: return QueriedType->isEnumeralType(); + case UTT_IsPolymorphic: + if (const RecordType *Record = QueriedType->getAsRecordType()) { + // Type traits are only parsed in C++, so we've got CXXRecords. + return cast<CXXRecordDecl>(Record->getDecl())->isPolymorphic(); + } + return false; + case UTT_IsAbstract: + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); + return false; + case UTT_HasTrivialConstructor: + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); + return false; + case UTT_HasTrivialDestructor: + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); + return false; + } +} + +SourceRange CXXOperatorCallExpr::getSourceRange() const { + OverloadedOperatorKind Kind = getOperator(); + if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { + if (getNumArgs() == 1) + // Prefix operator + return SourceRange(getOperatorLoc(), + getArg(0)->getSourceRange().getEnd()); + else + // Postfix operator + return SourceRange(getArg(0)->getSourceRange().getEnd(), + getOperatorLoc()); + } else if (Kind == OO_Call) { + return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc()); + } else if (Kind == OO_Subscript) { + return SourceRange(getArg(0)->getSourceRange().getBegin(), getRParenLoc()); + } else if (getNumArgs() == 1) { + return SourceRange(getOperatorLoc(), getArg(0)->getSourceRange().getEnd()); + } else if (getNumArgs() == 2) { + return SourceRange(getArg(0)->getSourceRange().getBegin(), + getArg(1)->getSourceRange().getEnd()); + } else { + return SourceRange(); + } +} + +Expr *CXXMemberCallExpr::getImplicitObjectArgument() { + if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return MemExpr->getBase(); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + +//===----------------------------------------------------------------------===// +// Named casts +//===----------------------------------------------------------------------===// + +/// getCastName - Get the name of the C++ cast being used, e.g., +/// "static_cast", "dynamic_cast", "reinterpret_cast", or +/// "const_cast". The returned pointer must not be freed. +const char *CXXNamedCastExpr::getCastName() const { + switch (getStmtClass()) { + case CXXStaticCastExprClass: return "static_cast"; + case CXXDynamicCastExprClass: return "dynamic_cast"; + case CXXReinterpretCastExprClass: return "reinterpret_cast"; + case CXXConstCastExprClass: return "const_cast"; + default: return "<invalid cast>"; + } +} + +CXXTemporary *CXXTemporary::Create(ASTContext &C, + const CXXDestructorDecl *Destructor) { + return new (C) CXXTemporary(Destructor); +} + +void CXXTemporary::Destroy(ASTContext &C) { + this->~CXXTemporary(); + C.Deallocate(this); +} + +CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, + CXXTemporary *Temp, + Expr* SubExpr) { + assert(SubExpr->getType()->isRecordType() && + "Expression bound to a temporary must have record type!"); + + return new (C) CXXBindTemporaryExpr(Temp, SubExpr); +} + +void CXXBindTemporaryExpr::Destroy(ASTContext &C) { + Temp->Destroy(C); + this->~CXXBindTemporaryExpr(); + C.Deallocate(this); +} + +CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, + CXXConstructorDecl *Cons, + QualType writtenTy, + SourceLocation tyBeginLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation rParenLoc) + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, writtenTy, Cons, + false, Args, NumArgs), + TyBeginLoc(tyBeginLoc), RParenLoc(rParenLoc) { +} + +CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, + CXXConstructorDecl *D, bool Elidable, + Expr **Args, unsigned NumArgs) { + return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, D, Elidable, + Args, NumArgs); +} + +CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + CXXConstructorDecl *D, bool elidable, + Expr **args, unsigned numargs) +: Expr(SC, T, + T->isDependentType(), + (T->isDependentType() || + CallExpr::hasAnyValueDependentArguments(args, numargs))), + Constructor(D), Elidable(elidable), Args(0), NumArgs(numargs) { + if (NumArgs > 0) { + Args = new (C) Stmt*[NumArgs]; + for (unsigned i = 0; i < NumArgs; ++i) + Args[i] = args[i]; + } +} + +void CXXConstructExpr::Destroy(ASTContext &C) { + DestroyChildren(C); + if (Args) + C.Deallocate(Args); + this->~CXXConstructExpr(); + C.Deallocate(this); +} + +CXXExprWithTemporaries::CXXExprWithTemporaries(Expr *subexpr, + CXXTemporary **temps, + unsigned numtemps) +: Expr(CXXExprWithTemporariesClass, subexpr->getType(), + subexpr->isTypeDependent(), subexpr->isValueDependent()), + SubExpr(subexpr), Temps(0), NumTemps(numtemps) { + if (NumTemps > 0) { + Temps = new CXXTemporary*[NumTemps]; + for (unsigned i = 0; i < NumTemps; ++i) + Temps[i] = temps[i]; + } +} + +CXXExprWithTemporaries *CXXExprWithTemporaries::Create(ASTContext &C, + Expr *SubExpr, + CXXTemporary **Temps, + unsigned NumTemps) { + return new (C) CXXExprWithTemporaries(SubExpr, Temps, NumTemps); +} + +void CXXExprWithTemporaries::Destroy(ASTContext &C) { + DestroyChildren(C); + this->~CXXExprWithTemporaries(); + C.Deallocate(this); +} + +CXXExprWithTemporaries::~CXXExprWithTemporaries() { + delete[] Temps; +} + +// CXXBindTemporaryExpr +Stmt::child_iterator CXXBindTemporaryExpr::child_begin() { + return &SubExpr; +} + +Stmt::child_iterator CXXBindTemporaryExpr::child_end() { + return &SubExpr + 1; +} + +// CXXConstructExpr +Stmt::child_iterator CXXConstructExpr::child_begin() { + return &Args[0]; +} +Stmt::child_iterator CXXConstructExpr::child_end() { + return &Args[0]+NumArgs; +} + +// CXXExprWithTemporaries +Stmt::child_iterator CXXExprWithTemporaries::child_begin() { + return &SubExpr; +} + +Stmt::child_iterator CXXExprWithTemporaries::child_end() { + return &SubExpr + 1; +} + +CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr( + SourceLocation TyBeginLoc, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) + : Expr(CXXUnresolvedConstructExprClass, T.getNonReferenceType(), + T->isDependentType(), true), + TyBeginLoc(TyBeginLoc), + Type(T), + LParenLoc(LParenLoc), + RParenLoc(RParenLoc), + NumArgs(NumArgs) { + Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); + memcpy(StoredArgs, Args, sizeof(Expr *) * NumArgs); +} + +CXXUnresolvedConstructExpr * +CXXUnresolvedConstructExpr::Create(ASTContext &C, + SourceLocation TyBegin, + QualType T, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + + sizeof(Expr *) * NumArgs); + return new (Mem) CXXUnresolvedConstructExpr(TyBegin, T, LParenLoc, + Args, NumArgs, RParenLoc); +} + +Stmt::child_iterator CXXUnresolvedConstructExpr::child_begin() { + return child_iterator(reinterpret_cast<Stmt **>(this + 1)); +} + +Stmt::child_iterator CXXUnresolvedConstructExpr::child_end() { + return child_iterator(reinterpret_cast<Stmt **>(this + 1) + NumArgs); +} + +Stmt::child_iterator CXXUnresolvedMemberExpr::child_begin() { + return child_iterator(&Base); +} + +Stmt::child_iterator CXXUnresolvedMemberExpr::child_end() { + return child_iterator(&Base + 1); +} + +//===----------------------------------------------------------------------===// +// Cloners +//===----------------------------------------------------------------------===// + +CXXBoolLiteralExpr* CXXBoolLiteralExpr::Clone(ASTContext &C) const { + return new (C) CXXBoolLiteralExpr(Value, getType(), Loc); +} + +CXXNullPtrLiteralExpr* CXXNullPtrLiteralExpr::Clone(ASTContext &C) const { + return new (C) CXXNullPtrLiteralExpr(getType(), Loc); +} + +CXXZeroInitValueExpr* CXXZeroInitValueExpr::Clone(ASTContext &C) const { + return new (C) CXXZeroInitValueExpr(getType(), TyBeginLoc, RParenLoc); +} diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp new file mode 100644 index 0000000..50fdcfd --- /dev/null +++ b/lib/AST/ExprConstant.cpp @@ -0,0 +1,1723 @@ +//===--- ExprConstant.cpp - Expression Constant Evaluator -----------------===// +// +// 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 constant evaluator. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Compiler.h" +#include <cstring> + +using namespace clang; +using llvm::APSInt; +using llvm::APFloat; + +/// EvalInfo - This is a private struct used by the evaluator to capture +/// information about a subexpression as it is folded. It retains information +/// about the AST context, but also maintains information about the folded +/// expression. +/// +/// If an expression could be evaluated, it is still possible it is not a C +/// "integer constant expression" or constant expression. If not, this struct +/// captures information about how and why not. +/// +/// One bit of information passed *into* the request for constant folding +/// indicates whether the subexpression is "evaluated" or not according to C +/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can +/// evaluate the expression regardless of what the RHS is, but C only allows +/// certain things in certain situations. +struct EvalInfo { + ASTContext &Ctx; + + /// EvalResult - Contains information about the evaluation. + Expr::EvalResult &EvalResult; + + EvalInfo(ASTContext &ctx, Expr::EvalResult& evalresult) : Ctx(ctx), + EvalResult(evalresult) {} +}; + + +static bool EvaluateLValue(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluatePointer(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateInteger(const Expr *E, APSInt &Result, EvalInfo &Info); +static bool EvaluateIntegerOrLValue(const Expr *E, APValue &Result, EvalInfo &Info); +static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info); +static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info); + +//===----------------------------------------------------------------------===// +// Misc utilities +//===----------------------------------------------------------------------===// + +static bool HandleConversionToBool(Expr* E, bool& Result, EvalInfo &Info) { + if (E->getType()->isIntegralType()) { + APSInt IntResult; + if (!EvaluateInteger(E, IntResult, Info)) + return false; + Result = IntResult != 0; + return true; + } else if (E->getType()->isRealFloatingType()) { + APFloat FloatResult(0.0); + if (!EvaluateFloat(E, FloatResult, Info)) + return false; + Result = !FloatResult.isZero(); + return true; + } else if (E->getType()->hasPointerRepresentation()) { + APValue PointerResult; + if (!EvaluatePointer(E, PointerResult, Info)) + return false; + // FIXME: Is this accurate for all kinds of bases? If not, what would + // the check look like? + Result = PointerResult.getLValueBase() || PointerResult.getLValueOffset(); + return true; + } else if (E->getType()->isAnyComplexType()) { + APValue ComplexResult; + if (!EvaluateComplex(E, ComplexResult, Info)) + return false; + if (ComplexResult.isComplexFloat()) { + Result = !ComplexResult.getComplexFloatReal().isZero() || + !ComplexResult.getComplexFloatImag().isZero(); + } else { + Result = ComplexResult.getComplexIntReal().getBoolValue() || + ComplexResult.getComplexIntImag().getBoolValue(); + } + return true; + } + + return false; +} + +static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType, + APFloat &Value, ASTContext &Ctx) { + unsigned DestWidth = Ctx.getIntWidth(DestType); + // Determine whether we are converting to unsigned or signed. + bool DestSigned = DestType->isSignedIntegerType(); + + // FIXME: Warning for overflow. + uint64_t Space[4]; + bool ignored; + (void)Value.convertToInteger(Space, DestWidth, DestSigned, + llvm::APFloat::rmTowardZero, &ignored); + return APSInt(llvm::APInt(DestWidth, 4, Space), !DestSigned); +} + +static APFloat HandleFloatToFloatCast(QualType DestType, QualType SrcType, + APFloat &Value, ASTContext &Ctx) { + bool ignored; + APFloat Result = Value; + Result.convert(Ctx.getFloatTypeSemantics(DestType), + APFloat::rmNearestTiesToEven, &ignored); + return Result; +} + +static APSInt HandleIntToIntCast(QualType DestType, QualType SrcType, + APSInt &Value, ASTContext &Ctx) { + unsigned DestWidth = Ctx.getIntWidth(DestType); + APSInt Result = Value; + // Figure out if this is a truncate, extend or noop cast. + // If the input is signed, do a sign extend, noop, or truncate. + Result.extOrTrunc(DestWidth); + Result.setIsUnsigned(DestType->isUnsignedIntegerType()); + return Result; +} + +static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, + APSInt &Value, ASTContext &Ctx) { + + APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1); + Result.convertFromAPInt(Value, Value.isSigned(), + APFloat::rmNearestTiesToEven); + return Result; +} + +//===----------------------------------------------------------------------===// +// LValue Evaluation +//===----------------------------------------------------------------------===// +namespace { +class VISIBILITY_HIDDEN LValueExprEvaluator + : public StmtVisitor<LValueExprEvaluator, APValue> { + EvalInfo &Info; +public: + + LValueExprEvaluator(EvalInfo &info) : Info(info) {} + + APValue VisitStmt(Stmt *S) { + return APValue(); + } + + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + APValue VisitDeclRefExpr(DeclRefExpr *E); + APValue VisitBlockExpr(BlockExpr *E); + APValue VisitPredefinedExpr(PredefinedExpr *E) { return APValue(E, 0); } + APValue VisitCompoundLiteralExpr(CompoundLiteralExpr *E); + APValue VisitMemberExpr(MemberExpr *E); + APValue VisitStringLiteral(StringLiteral *E) { return APValue(E, 0); } + APValue VisitObjCEncodeExpr(ObjCEncodeExpr *E) { return APValue(E, 0); } + APValue VisitArraySubscriptExpr(ArraySubscriptExpr *E); + APValue VisitUnaryDeref(UnaryOperator *E); + APValue VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + APValue VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + // FIXME: Missing: __real__, __imag__ +}; +} // end anonymous namespace + +static bool EvaluateLValue(const Expr* E, APValue& Result, EvalInfo &Info) { + Result = LValueExprEvaluator(Info).Visit(const_cast<Expr*>(E)); + return Result.isLValue(); +} + +APValue LValueExprEvaluator::VisitDeclRefExpr(DeclRefExpr *E) +{ + if (!E->hasGlobalStorage()) + return APValue(); + + if (isa<FunctionDecl>(E->getDecl())) { + return APValue(E, 0); + } else if (VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { + if (!VD->getType()->isReferenceType()) + return APValue(E, 0); + if (VD->getInit()) + return Visit(VD->getInit()); + } + + return APValue(); +} + +APValue LValueExprEvaluator::VisitBlockExpr(BlockExpr *E) +{ + if (E->hasBlockDeclRefExprs()) + return APValue(); + + return APValue(E, 0); +} + +APValue LValueExprEvaluator::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { + if (E->isFileScope()) + return APValue(E, 0); + return APValue(); +} + +APValue LValueExprEvaluator::VisitMemberExpr(MemberExpr *E) { + APValue result; + QualType Ty; + if (E->isArrow()) { + if (!EvaluatePointer(E->getBase(), result, Info)) + return APValue(); + Ty = E->getBase()->getType()->getAsPointerType()->getPointeeType(); + } else { + result = Visit(E->getBase()); + if (result.isUninit()) + return APValue(); + Ty = E->getBase()->getType(); + } + + RecordDecl *RD = Ty->getAsRecordType()->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); + if (!FD) // FIXME: deal with other kinds of member expressions + return APValue(); + + if (FD->getType()->isReferenceType()) + return APValue(); + + // FIXME: This is linear time. + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(Info.Ctx), + FieldEnd = RD->field_end(Info.Ctx); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) + break; + } + + result.setLValue(result.getLValueBase(), + result.getLValueOffset() + RL.getFieldOffset(i) / 8); + + return result; +} + +APValue LValueExprEvaluator::VisitArraySubscriptExpr(ArraySubscriptExpr *E) +{ + APValue Result; + + if (!EvaluatePointer(E->getBase(), Result, Info)) + return APValue(); + + APSInt Index; + if (!EvaluateInteger(E->getIdx(), Index, Info)) + return APValue(); + + uint64_t ElementSize = Info.Ctx.getTypeSize(E->getType()) / 8; + + uint64_t Offset = Index.getSExtValue() * ElementSize; + Result.setLValue(Result.getLValueBase(), + Result.getLValueOffset() + Offset); + return Result; +} + +APValue LValueExprEvaluator::VisitUnaryDeref(UnaryOperator *E) +{ + APValue Result; + if (!EvaluatePointer(E->getSubExpr(), Result, Info)) + return APValue(); + return Result; +} + +//===----------------------------------------------------------------------===// +// Pointer Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN PointerExprEvaluator + : public StmtVisitor<PointerExprEvaluator, APValue> { + EvalInfo &Info; +public: + + PointerExprEvaluator(EvalInfo &info) : Info(info) {} + + APValue VisitStmt(Stmt *S) { + return APValue(); + } + + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + + APValue VisitBinaryOperator(const BinaryOperator *E); + APValue VisitCastExpr(const CastExpr* E); + APValue VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + APValue VisitUnaryAddrOf(const UnaryOperator *E); + APValue VisitObjCStringLiteral(ObjCStringLiteral *E) + { return APValue(E, 0); } + APValue VisitAddrLabelExpr(AddrLabelExpr *E) + { return APValue(E, 0); } + APValue VisitCallExpr(CallExpr *E); + APValue VisitBlockExpr(BlockExpr *E) { + if (!E->hasBlockDeclRefExprs()) + return APValue(E, 0); + return APValue(); + } + APValue VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) + { return APValue((Expr*)0, 0); } + APValue VisitConditionalOperator(ConditionalOperator *E); + APValue VisitChooseExpr(ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + APValue VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) + { return APValue((Expr*)0, 0); } + // FIXME: Missing: @protocol, @selector +}; +} // end anonymous namespace + +static bool EvaluatePointer(const Expr* E, APValue& Result, EvalInfo &Info) { + if (!E->getType()->hasPointerRepresentation()) + return false; + Result = PointerExprEvaluator(Info).Visit(const_cast<Expr*>(E)); + return Result.isLValue(); +} + +APValue PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() != BinaryOperator::Add && + E->getOpcode() != BinaryOperator::Sub) + return APValue(); + + const Expr *PExp = E->getLHS(); + const Expr *IExp = E->getRHS(); + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + APValue ResultLValue; + if (!EvaluatePointer(PExp, ResultLValue, Info)) + return APValue(); + + llvm::APSInt AdditionalOffset(32); + if (!EvaluateInteger(IExp, AdditionalOffset, Info)) + return APValue(); + + QualType PointeeType = PExp->getType()->getAsPointerType()->getPointeeType(); + uint64_t SizeOfPointee; + + // Explicitly handle GNU void* and function pointer arithmetic extensions. + if (PointeeType->isVoidType() || PointeeType->isFunctionType()) + SizeOfPointee = 1; + else + SizeOfPointee = Info.Ctx.getTypeSize(PointeeType) / 8; + + uint64_t Offset = ResultLValue.getLValueOffset(); + + if (E->getOpcode() == BinaryOperator::Add) + Offset += AdditionalOffset.getLimitedValue() * SizeOfPointee; + else + Offset -= AdditionalOffset.getLimitedValue() * SizeOfPointee; + + return APValue(ResultLValue.getLValueBase(), Offset); +} + +APValue PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { + APValue result; + if (EvaluateLValue(E->getSubExpr(), result, Info)) + return result; + return APValue(); +} + + +APValue PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { + const Expr* SubExpr = E->getSubExpr(); + + // Check for pointer->pointer cast + if (SubExpr->getType()->isPointerType()) { + APValue Result; + if (EvaluatePointer(SubExpr, Result, Info)) + return Result; + return APValue(); + } + + if (SubExpr->getType()->isIntegralType()) { + APValue Result; + if (!EvaluateIntegerOrLValue(SubExpr, Result, Info)) + return APValue(); + + if (Result.isInt()) { + Result.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + return APValue(0, Result.getInt().getZExtValue()); + } + + // Cast is of an lvalue, no need to change value. + return Result; + } + + if (SubExpr->getType()->isFunctionType() || + SubExpr->getType()->isBlockPointerType() || + SubExpr->getType()->isArrayType()) { + APValue Result; + if (EvaluateLValue(SubExpr, Result, Info)) + return Result; + return APValue(); + } + + return APValue(); +} + +APValue PointerExprEvaluator::VisitCallExpr(CallExpr *E) { + if (E->isBuiltinCall(Info.Ctx) == + Builtin::BI__builtin___CFStringMakeConstantString) + return APValue(E, 0); + return APValue(); +} + +APValue PointerExprEvaluator::VisitConditionalOperator(ConditionalOperator *E) { + bool BoolResult; + if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) + return APValue(); + + Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); + + APValue Result; + if (EvaluatePointer(EvalExpr, Result, Info)) + return Result; + return APValue(); +} + +//===----------------------------------------------------------------------===// +// Vector Evaluation +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN VectorExprEvaluator + : public StmtVisitor<VectorExprEvaluator, APValue> { + EvalInfo &Info; + APValue GetZeroVector(QualType VecType); + public: + + VectorExprEvaluator(EvalInfo &info) : Info(info) {} + + APValue VisitStmt(Stmt *S) { + return APValue(); + } + + APValue VisitParenExpr(ParenExpr *E) + { return Visit(E->getSubExpr()); } + APValue VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + APValue VisitUnaryPlus(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + APValue VisitUnaryReal(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + APValue VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) + { return GetZeroVector(E->getType()); } + APValue VisitCastExpr(const CastExpr* E); + APValue VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); + APValue VisitInitListExpr(const InitListExpr *E); + APValue VisitConditionalOperator(const ConditionalOperator *E); + APValue VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + APValue VisitUnaryImag(const UnaryOperator *E); + // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div, + // binary comparisons, binary and/or/xor, + // shufflevector, ExtVectorElementExpr + // (Note that these require implementing conversions + // between vector types.) + }; +} // end anonymous namespace + +static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) { + if (!E->getType()->isVectorType()) + return false; + Result = VectorExprEvaluator(Info).Visit(const_cast<Expr*>(E)); + return !Result.isUninit(); +} + +APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { + const Expr* SE = E->getSubExpr(); + + // Check for vector->vector bitcast. + if (SE->getType()->isVectorType()) + return this->Visit(const_cast<Expr*>(SE)); + + return APValue(); +} + +APValue +VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return this->Visit(const_cast<Expr*>(E->getInitializer())); +} + +APValue +VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { + const VectorType *VT = E->getType()->getAsVectorType(); + unsigned NumInits = E->getNumInits(); + unsigned NumElements = VT->getNumElements(); + + QualType EltTy = VT->getElementType(); + llvm::SmallVector<APValue, 4> Elements; + + for (unsigned i = 0; i < NumElements; i++) { + if (EltTy->isIntegerType()) { + llvm::APSInt sInt(32); + if (i < NumInits) { + if (!EvaluateInteger(E->getInit(i), sInt, Info)) + return APValue(); + } else { + sInt = Info.Ctx.MakeIntValue(0, EltTy); + } + Elements.push_back(APValue(sInt)); + } else { + llvm::APFloat f(0.0); + if (i < NumInits) { + if (!EvaluateFloat(E->getInit(i), f, Info)) + return APValue(); + } else { + f = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy)); + } + Elements.push_back(APValue(f)); + } + } + return APValue(&Elements[0], Elements.size()); +} + +APValue +VectorExprEvaluator::GetZeroVector(QualType T) { + const VectorType *VT = T->getAsVectorType(); + QualType EltTy = VT->getElementType(); + APValue ZeroElement; + if (EltTy->isIntegerType()) + ZeroElement = APValue(Info.Ctx.MakeIntValue(0, EltTy)); + else + ZeroElement = + APValue(APFloat::getZero(Info.Ctx.getFloatTypeSemantics(EltTy))); + + llvm::SmallVector<APValue, 4> Elements(VT->getNumElements(), ZeroElement); + return APValue(&Elements[0], Elements.size()); +} + +APValue VectorExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { + bool BoolResult; + if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) + return APValue(); + + Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); + + APValue Result; + if (EvaluateVector(EvalExpr, Result, Info)) + return Result; + return APValue(); +} + +APValue VectorExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { + if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + return GetZeroVector(E->getType()); +} + +//===----------------------------------------------------------------------===// +// Integer Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN IntExprEvaluator + : public StmtVisitor<IntExprEvaluator, bool> { + EvalInfo &Info; + APValue &Result; +public: + IntExprEvaluator(EvalInfo &info, APValue &result) + : Info(info), Result(result) {} + + bool Success(const llvm::APSInt &SI, const Expr *E) { + assert(E->getType()->isIntegralType() && "Invalid evaluation result."); + assert(SI.isSigned() == E->getType()->isSignedIntegerType() && + "Invalid evaluation result."); + assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(SI); + return true; + } + + bool Success(const llvm::APInt &I, const Expr *E) { + assert(E->getType()->isIntegralType() && "Invalid evaluation result."); + assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(APSInt(I)); + Result.getInt().setIsUnsigned(E->getType()->isUnsignedIntegerType()); + return true; + } + + bool Success(uint64_t Value, const Expr *E) { + assert(E->getType()->isIntegralType() && "Invalid evaluation result."); + Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + return true; + } + + bool Error(SourceLocation L, diag::kind D, const Expr *E) { + // Take the first error. + if (Info.EvalResult.Diag == 0) { + Info.EvalResult.DiagLoc = L; + Info.EvalResult.Diag = D; + Info.EvalResult.DiagExpr = E; + } + return false; + } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitStmt(Stmt *) { + assert(0 && "This should be called on integers, stmts are not integers"); + return false; + } + + bool VisitExpr(Expr *E) { + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + + bool VisitIntegerLiteral(const IntegerLiteral *E) { + return Success(E->getValue(), E); + } + bool VisitCharacterLiteral(const CharacterLiteral *E) { + return Success(E->getValue(), E); + } + bool VisitTypesCompatibleExpr(const TypesCompatibleExpr *E) { + // Per gcc docs "this built-in function ignores top level + // qualifiers". We need to use the canonical version to properly + // be able to strip CRV qualifiers from the type. + QualType T0 = Info.Ctx.getCanonicalType(E->getArgType1()); + QualType T1 = Info.Ctx.getCanonicalType(E->getArgType2()); + return Success(Info.Ctx.typesAreCompatible(T0.getUnqualifiedType(), + T1.getUnqualifiedType()), + E); + } + bool VisitDeclRefExpr(const DeclRefExpr *E); + bool VisitCallExpr(const CallExpr *E); + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitConditionalOperator(const ConditionalOperator *E); + + bool VisitCastExpr(CastExpr* E); + bool VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E); + + bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitGNUNullExpr(const GNUNullExpr *E) { + return Success(0, E); + } + + bool VisitCXXZeroInitValueExpr(const CXXZeroInitValueExpr *E) { + return Success(0, E); + } + + bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { + return Success(0, E); + } + + bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { + return Success(E->EvaluateTrait(), E); + } + + bool VisitChooseExpr(const ChooseExpr *E) { + return Visit(E->getChosenSubExpr(Info.Ctx)); + } + + bool VisitUnaryReal(const UnaryOperator *E); + bool VisitUnaryImag(const UnaryOperator *E); + +private: + unsigned GetAlignOfExpr(const Expr *E); + unsigned GetAlignOfType(QualType T); + // FIXME: Missing: array subscript of vector, member of vector +}; +} // end anonymous namespace + +static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { + if (!E->getType()->isIntegralType()) + return false; + + return IntExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); +} + +static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { + APValue Val; + if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) + return false; + Result = Val.getInt(); + return true; +} + +bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { + // Enums are integer constant exprs. + if (const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(E->getDecl())) { + // FIXME: This is an ugly hack around the fact that enums don't set their + // signedness consistently; see PR3173. + APSInt SI = D->getInitVal(); + SI.setIsUnsigned(!E->getType()->isSignedIntegerType()); + // FIXME: This is an ugly hack around the fact that enums don't + // set their width (!?!) consistently; see PR3173. + SI.extOrTrunc(Info.Ctx.getIntWidth(E->getType())); + return Success(SI, E); + } + + // In C++, const, non-volatile integers initialized with ICEs are ICEs. + // In C, they can also be folded, although they are not ICEs. + if (E->getType().getCVRQualifiers() == QualType::Const) { + if (const VarDecl *D = dyn_cast<VarDecl>(E->getDecl())) { + if (APValue *V = D->getEvaluatedValue()) + return Success(V->getInt(), E); + if (const Expr *Init = D->getInit()) { + if (Visit(const_cast<Expr*>(Init))) { + // Cache the evaluated value in the variable declaration. + D->setEvaluatedValue(Info.Ctx, Result); + return true; + } + + return false; + } + } + } + + // Otherwise, random variable references are not constants. + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); +} + +/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way +/// as GCC. +static int EvaluateBuiltinClassifyType(const CallExpr *E) { + // The following enum mimics the values returned by GCC. + // FIXME: Does GCC differ between lvalue and rvalue references here? + 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 + }; + + // If no argument was supplied, default to "no_type_class". This isn't + // ideal, however it is what gcc does. + if (E->getNumArgs() == 0) + return no_type_class; + + QualType ArgTy = E->getArg(0)->getType(); + if (ArgTy->isVoidType()) + return void_type_class; + else if (ArgTy->isEnumeralType()) + return enumeral_type_class; + else if (ArgTy->isBooleanType()) + return boolean_type_class; + else if (ArgTy->isCharType()) + return string_type_class; // gcc doesn't appear to use char_type_class + else if (ArgTy->isIntegerType()) + return integer_type_class; + else if (ArgTy->isPointerType()) + return pointer_type_class; + else if (ArgTy->isReferenceType()) + return reference_type_class; + else if (ArgTy->isRealType()) + return real_type_class; + else if (ArgTy->isComplexType()) + return complex_type_class; + else if (ArgTy->isFunctionType()) + return function_type_class; + else if (ArgTy->isStructureType()) + return record_type_class; + else if (ArgTy->isUnionType()) + return union_type_class; + else if (ArgTy->isArrayType()) + return array_type_class; + else if (ArgTy->isUnionType()) + return union_type_class; + else // FIXME: offset_type_class, method_type_class, & lang_type_class? + assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); + return -1; +} + +bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { + switch (E->isBuiltinCall(Info.Ctx)) { + default: + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + case Builtin::BI__builtin_classify_type: + return Success(EvaluateBuiltinClassifyType(E), E); + + case Builtin::BI__builtin_constant_p: + // __builtin_constant_p always has one operand: it returns true if that + // operand can be folded, false otherwise. + return Success(E->getArg(0)->isEvaluatable(Info.Ctx), E); + } +} + +bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BinaryOperator::Comma) { + if (!Visit(E->getRHS())) + return false; + + // If we can't evaluate the LHS, it might have side effects; + // conservatively mark it. + if (!E->getLHS()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + + return true; + } + + if (E->isLogicalOp()) { + // These need to be handled specially because the operands aren't + // necessarily integral + bool lhsResult, rhsResult; + + if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) { + // We were able to evaluate the LHS, see if we can get away with not + // evaluating the RHS: 0 && X -> 0, 1 || X -> 1 + if (lhsResult == (E->getOpcode() == BinaryOperator::LOr)) + return Success(lhsResult, E); + + if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { + if (E->getOpcode() == BinaryOperator::LOr) + return Success(lhsResult || rhsResult, E); + else + return Success(lhsResult && rhsResult, E); + } + } else { + if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { + // We can't evaluate the LHS; however, sometimes the result + // is determined by the RHS: X && 0 -> 0, X || 1 -> 1. + if (rhsResult == (E->getOpcode() == BinaryOperator::LOr) || + !rhsResult == (E->getOpcode() == BinaryOperator::LAnd)) { + // Since we weren't able to evaluate the left hand side, it + // must have had side effects. + Info.EvalResult.HasSideEffects = true; + + return Success(rhsResult, E); + } + } + } + + return false; + } + + QualType LHSTy = E->getLHS()->getType(); + QualType RHSTy = E->getRHS()->getType(); + + if (LHSTy->isAnyComplexType()) { + assert(RHSTy->isAnyComplexType() && "Invalid comparison"); + APValue LHS, RHS; + + if (!EvaluateComplex(E->getLHS(), LHS, Info)) + return false; + + if (!EvaluateComplex(E->getRHS(), RHS, Info)) + return false; + + if (LHS.isComplexFloat()) { + APFloat::cmpResult CR_r = + LHS.getComplexFloatReal().compare(RHS.getComplexFloatReal()); + APFloat::cmpResult CR_i = + LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); + + if (E->getOpcode() == BinaryOperator::EQ) + return Success((CR_r == APFloat::cmpEqual && + CR_i == APFloat::cmpEqual), E); + else { + assert(E->getOpcode() == BinaryOperator::NE && + "Invalid complex comparison."); + return Success(((CR_r == APFloat::cmpGreaterThan || + CR_r == APFloat::cmpLessThan) && + (CR_i == APFloat::cmpGreaterThan || + CR_i == APFloat::cmpLessThan)), E); + } + } else { + if (E->getOpcode() == BinaryOperator::EQ) + return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() && + LHS.getComplexIntImag() == RHS.getComplexIntImag()), E); + else { + assert(E->getOpcode() == BinaryOperator::NE && + "Invalid compex comparison."); + return Success((LHS.getComplexIntReal() != RHS.getComplexIntReal() || + LHS.getComplexIntImag() != RHS.getComplexIntImag()), E); + } + } + } + + if (LHSTy->isRealFloatingType() && + RHSTy->isRealFloatingType()) { + APFloat RHS(0.0), LHS(0.0); + + if (!EvaluateFloat(E->getRHS(), RHS, Info)) + return false; + + if (!EvaluateFloat(E->getLHS(), LHS, Info)) + return false; + + APFloat::cmpResult CR = LHS.compare(RHS); + + switch (E->getOpcode()) { + default: + assert(0 && "Invalid binary operator!"); + case BinaryOperator::LT: + return Success(CR == APFloat::cmpLessThan, E); + case BinaryOperator::GT: + return Success(CR == APFloat::cmpGreaterThan, E); + case BinaryOperator::LE: + return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); + case BinaryOperator::GE: + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, + E); + case BinaryOperator::EQ: + return Success(CR == APFloat::cmpEqual, E); + case BinaryOperator::NE: + return Success(CR == APFloat::cmpGreaterThan + || CR == APFloat::cmpLessThan, E); + } + } + + if (LHSTy->isPointerType() && RHSTy->isPointerType()) { + if (E->getOpcode() == BinaryOperator::Sub || E->isEqualityOp()) { + APValue LHSValue; + if (!EvaluatePointer(E->getLHS(), LHSValue, Info)) + return false; + + APValue RHSValue; + if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) + return false; + + // Reject any bases; this is conservative, but good enough for + // common uses + if (LHSValue.getLValueBase() || RHSValue.getLValueBase()) + return false; + + if (E->getOpcode() == BinaryOperator::Sub) { + const QualType Type = E->getLHS()->getType(); + const QualType ElementType = Type->getAsPointerType()->getPointeeType(); + + uint64_t D = LHSValue.getLValueOffset() - RHSValue.getLValueOffset(); + D /= Info.Ctx.getTypeSize(ElementType) / 8; + + return Success(D, E); + } + bool Result; + if (E->getOpcode() == BinaryOperator::EQ) { + Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset(); + } else { + Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset(); + } + return Success(Result, E); + } + } + if (!LHSTy->isIntegralType() || + !RHSTy->isIntegralType()) { + // We can't continue from here for non-integral types, and they + // could potentially confuse the following operations. + return false; + } + + // The LHS of a constant expr is always evaluated and needed. + if (!Visit(E->getLHS())) + return false; // error in subexpression. + + APValue RHSVal; + if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info)) + return false; + + // Handle cases like (unsigned long)&a + 4. + if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) { + uint64_t offset = Result.getLValueOffset(); + if (E->getOpcode() == BinaryOperator::Add) + offset += RHSVal.getInt().getZExtValue(); + else + offset -= RHSVal.getInt().getZExtValue(); + Result = APValue(Result.getLValueBase(), offset); + return true; + } + + // Handle cases like 4 + (unsigned long)&a + if (E->getOpcode() == BinaryOperator::Add && + RHSVal.isLValue() && Result.isInt()) { + uint64_t offset = RHSVal.getLValueOffset(); + offset += Result.getInt().getZExtValue(); + Result = APValue(RHSVal.getLValueBase(), offset); + return true; + } + + // All the following cases expect both operands to be an integer + if (!Result.isInt() || !RHSVal.isInt()) + return false; + + APSInt& RHS = RHSVal.getInt(); + + switch (E->getOpcode()) { + default: + return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); + case BinaryOperator::Mul: return Success(Result.getInt() * RHS, E); + case BinaryOperator::Add: return Success(Result.getInt() + RHS, E); + case BinaryOperator::Sub: return Success(Result.getInt() - RHS, E); + case BinaryOperator::And: return Success(Result.getInt() & RHS, E); + case BinaryOperator::Xor: return Success(Result.getInt() ^ RHS, E); + case BinaryOperator::Or: return Success(Result.getInt() | RHS, E); + case BinaryOperator::Div: + if (RHS == 0) + return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); + return Success(Result.getInt() / RHS, E); + case BinaryOperator::Rem: + if (RHS == 0) + return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); + return Success(Result.getInt() % RHS, E); + case BinaryOperator::Shl: { + // FIXME: Warn about out of range shift amounts! + unsigned SA = + (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); + return Success(Result.getInt() << SA, E); + } + case BinaryOperator::Shr: { + unsigned SA = + (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); + return Success(Result.getInt() >> SA, E); + } + + case BinaryOperator::LT: return Success(Result.getInt() < RHS, E); + case BinaryOperator::GT: return Success(Result.getInt() > RHS, E); + case BinaryOperator::LE: return Success(Result.getInt() <= RHS, E); + case BinaryOperator::GE: return Success(Result.getInt() >= RHS, E); + case BinaryOperator::EQ: return Success(Result.getInt() == RHS, E); + case BinaryOperator::NE: return Success(Result.getInt() != RHS, E); + } +} + +bool IntExprEvaluator::VisitConditionalOperator(const ConditionalOperator *E) { + bool Cond; + if (!HandleConversionToBool(E->getCond(), Cond, Info)) + return false; + + return Visit(Cond ? E->getTrueExpr() : E->getFalseExpr()); +} + +unsigned IntExprEvaluator::GetAlignOfType(QualType T) { + // Get information about the alignment. + unsigned CharSize = Info.Ctx.Target.getCharWidth(); + + // __alignof is defined to return the preferred alignment. + return Info.Ctx.getPreferredTypeAlign(T.getTypePtr()) / CharSize; +} + +unsigned IntExprEvaluator::GetAlignOfExpr(const Expr *E) { + E = E->IgnoreParens(); + + // alignof decl is always accepted, even if it doesn't make sense: we default + // to 1 in those cases. + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return Info.Ctx.getDeclAlignInBytes(DRE->getDecl()); + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return Info.Ctx.getDeclAlignInBytes(ME->getMemberDecl()); + + return GetAlignOfType(E->getType()); +} + + +/// VisitSizeAlignOfExpr - Evaluate a sizeof or alignof with a result as the +/// expression's type. +bool IntExprEvaluator::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr *E) { + QualType DstTy = E->getType(); + + // Handle alignof separately. + if (!E->isSizeOf()) { + if (E->isArgumentType()) + return Success(GetAlignOfType(E->getArgumentType()), E); + else + return Success(GetAlignOfExpr(E->getArgumentExpr()), E); + } + + QualType SrcTy = E->getTypeOfArgument(); + + // sizeof(void), __alignof__(void), sizeof(function) = 1 as a gcc + // extension. + if (SrcTy->isVoidType() || SrcTy->isFunctionType()) + return Success(1, E); + + // sizeof(vla) is not a constantexpr: C99 6.5.3.4p2. + if (!SrcTy->isConstantSizeType()) + return false; + + // Get information about the size. + unsigned BitWidth = Info.Ctx.getTypeSize(SrcTy); + return Success(BitWidth / Info.Ctx.Target.getCharWidth(), E); +} + +bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + // Special case unary operators that do not need their subexpression + // evaluated. offsetof/sizeof/alignof are all special. + if (E->isOffsetOfOp()) { + // The AST for offsetof is defined in such a way that we can just + // directly Evaluate it as an l-value. + APValue LV; + if (!EvaluateLValue(E->getSubExpr(), LV, Info)) + return false; + if (LV.getLValueBase()) + return false; + return Success(LV.getLValueOffset(), E); + } + + if (E->getOpcode() == UnaryOperator::LNot) { + // LNot's operand isn't necessarily an integer, so we handle it specially. + bool bres; + if (!HandleConversionToBool(E->getSubExpr(), bres, Info)) + return false; + return Success(!bres, E); + } + + // Only handle integral operations... + if (!E->getSubExpr()->getType()->isIntegralType()) + return false; + + // Get the operand value into 'Result'. + if (!Visit(E->getSubExpr())) + return false; + + switch (E->getOpcode()) { + default: + // Address, indirect, pre/post inc/dec, etc are not valid constant exprs. + // See C99 6.6p3. + return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E); + case UnaryOperator::Extension: + // FIXME: Should extension allow i-c-e extension expressions in its scope? + // If so, we could clear the diagnostic ID. + return true; + case UnaryOperator::Plus: + // The result is always just the subexpr. + return true; + case UnaryOperator::Minus: + if (!Result.isInt()) return false; + return Success(-Result.getInt(), E); + case UnaryOperator::Not: + if (!Result.isInt()) return false; + return Success(~Result.getInt(), E); + } +} + +/// HandleCast - This is used to evaluate implicit or explicit casts where the +/// result type is integer. +bool IntExprEvaluator::VisitCastExpr(CastExpr *E) { + Expr *SubExpr = E->getSubExpr(); + QualType DestType = E->getType(); + QualType SrcType = SubExpr->getType(); + + if (DestType->isBooleanType()) { + bool BoolResult; + if (!HandleConversionToBool(SubExpr, BoolResult, Info)) + return false; + return Success(BoolResult, E); + } + + // Handle simple integer->integer casts. + if (SrcType->isIntegralType()) { + if (!Visit(SubExpr)) + return false; + + if (!Result.isInt()) { + // Only allow casts of lvalues if they are lossless. + return Info.Ctx.getTypeSize(DestType) == Info.Ctx.getTypeSize(SrcType); + } + + return Success(HandleIntToIntCast(DestType, SrcType, + Result.getInt(), Info.Ctx), E); + } + + // FIXME: Clean this up! + if (SrcType->isPointerType()) { + APValue LV; + if (!EvaluatePointer(SubExpr, LV, Info)) + return false; + + if (LV.getLValueBase()) { + // Only allow based lvalue casts if they are lossless. + if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(SrcType)) + return false; + + Result = LV; + return true; + } + + APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset(), SrcType); + return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E); + } + + if (SrcType->isArrayType() || SrcType->isFunctionType()) { + // This handles double-conversion cases, where there's both + // an l-value promotion and an implicit conversion to int. + APValue LV; + if (!EvaluateLValue(SubExpr, LV, Info)) + return false; + + if (Info.Ctx.getTypeSize(DestType) != Info.Ctx.getTypeSize(Info.Ctx.VoidPtrTy)) + return false; + + Result = LV; + return true; + } + + if (SrcType->isAnyComplexType()) { + APValue C; + if (!EvaluateComplex(SubExpr, C, Info)) + return false; + if (C.isComplexFloat()) + return Success(HandleFloatToIntCast(DestType, SrcType, + C.getComplexFloatReal(), Info.Ctx), + E); + else + return Success(HandleIntToIntCast(DestType, SrcType, + C.getComplexIntReal(), Info.Ctx), E); + } + // FIXME: Handle vectors + + if (!SrcType->isRealFloatingType()) + return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + + APFloat F(0.0); + if (!EvaluateFloat(SubExpr, F, Info)) + return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + + return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); +} + +bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { + if (E->getSubExpr()->getType()->isAnyComplexType()) { + APValue LV; + if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt()) + return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + return Success(LV.getComplexIntReal(), E); + } + + return Visit(E->getSubExpr()); +} + +bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { + if (E->getSubExpr()->getType()->isComplexIntegerType()) { + APValue LV; + if (!EvaluateComplex(E->getSubExpr(), LV, Info) || !LV.isComplexInt()) + return Error(E->getExprLoc(), diag::note_invalid_subexpr_in_ice, E); + return Success(LV.getComplexIntImag(), E); + } + + if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + return Success(0, E); +} + +//===----------------------------------------------------------------------===// +// Float Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN FloatExprEvaluator + : public StmtVisitor<FloatExprEvaluator, bool> { + EvalInfo &Info; + APFloat &Result; +public: + FloatExprEvaluator(EvalInfo &info, APFloat &result) + : Info(info), Result(result) {} + + bool VisitStmt(Stmt *S) { + return false; + } + + bool VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitCallExpr(const CallExpr *E); + + bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitFloatingLiteral(const FloatingLiteral *E); + bool VisitCastExpr(CastExpr *E); + bool VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E); + + bool VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + bool VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + + // FIXME: Missing: __real__/__imag__, array subscript of vector, + // member of vector, ImplicitValueInitExpr, + // conditional ?:, comma +}; +} // end anonymous namespace + +static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { + return FloatExprEvaluator(Info, Result).Visit(const_cast<Expr*>(E)); +} + +bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { + switch (E->isBuiltinCall(Info.Ctx)) { + default: return false; + case Builtin::BI__builtin_huge_val: + case Builtin::BI__builtin_huge_valf: + case Builtin::BI__builtin_huge_vall: + case Builtin::BI__builtin_inf: + case Builtin::BI__builtin_inff: + case Builtin::BI__builtin_infl: { + const llvm::fltSemantics &Sem = + Info.Ctx.getFloatTypeSemantics(E->getType()); + Result = llvm::APFloat::getInf(Sem); + return true; + } + + case Builtin::BI__builtin_nan: + case Builtin::BI__builtin_nanf: + case Builtin::BI__builtin_nanl: + // If this is __builtin_nan() turn this into a nan, otherwise we + // can't constant fold it. + if (const StringLiteral *S = + dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenCasts())) { + if (!S->isWide()) { + const llvm::fltSemantics &Sem = + Info.Ctx.getFloatTypeSemantics(E->getType()); + llvm::SmallString<16> s; + s.append(S->getStrData(), S->getStrData() + S->getByteLength()); + s += '\0'; + long l; + char *endp; + l = strtol(&s[0], &endp, 0); + if (endp != s.end()-1) + return false; + unsigned type = (unsigned int)l;; + Result = llvm::APFloat::getNaN(Sem, false, type); + return true; + } + } + return false; + + case Builtin::BI__builtin_fabs: + case Builtin::BI__builtin_fabsf: + case Builtin::BI__builtin_fabsl: + if (!EvaluateFloat(E->getArg(0), Result, Info)) + return false; + + if (Result.isNegative()) + Result.changeSign(); + return true; + + case Builtin::BI__builtin_copysign: + case Builtin::BI__builtin_copysignf: + case Builtin::BI__builtin_copysignl: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + Result.copySign(RHS); + return true; + } + } +} + +bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + if (E->getOpcode() == UnaryOperator::Deref) + return false; + + if (!EvaluateFloat(E->getSubExpr(), Result, Info)) + return false; + + switch (E->getOpcode()) { + default: return false; + case UnaryOperator::Plus: + return true; + case UnaryOperator::Minus: + Result.changeSign(); + return true; + } +} + +bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + // FIXME: Diagnostics? I really don't understand how the warnings + // and errors are supposed to work. + APFloat RHS(0.0); + if (!EvaluateFloat(E->getLHS(), Result, Info)) + return false; + if (!EvaluateFloat(E->getRHS(), RHS, Info)) + return false; + + switch (E->getOpcode()) { + default: return false; + case BinaryOperator::Mul: + Result.multiply(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Add: + Result.add(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Sub: + Result.subtract(RHS, APFloat::rmNearestTiesToEven); + return true; + case BinaryOperator::Div: + Result.divide(RHS, APFloat::rmNearestTiesToEven); + return true; + } +} + +bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { + Result = E->getValue(); + return true; +} + +bool FloatExprEvaluator::VisitCastExpr(CastExpr *E) { + Expr* SubExpr = E->getSubExpr(); + + if (SubExpr->getType()->isIntegralType()) { + APSInt IntResult; + if (!EvaluateInteger(SubExpr, IntResult, Info)) + return false; + Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), + IntResult, Info.Ctx); + return true; + } + if (SubExpr->getType()->isRealFloatingType()) { + if (!Visit(SubExpr)) + return false; + Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(), + Result, Info.Ctx); + return true; + } + // FIXME: Handle complex types + + return false; +} + +bool FloatExprEvaluator::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *E) { + Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType())); + return true; +} + +//===----------------------------------------------------------------------===// +// Complex Evaluation (for float and integer) +//===----------------------------------------------------------------------===// + +namespace { +class VISIBILITY_HIDDEN ComplexExprEvaluator + : public StmtVisitor<ComplexExprEvaluator, APValue> { + EvalInfo &Info; + +public: + ComplexExprEvaluator(EvalInfo &info) : Info(info) {} + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + APValue VisitStmt(Stmt *S) { + return APValue(); + } + + APValue VisitParenExpr(ParenExpr *E) { return Visit(E->getSubExpr()); } + + APValue VisitImaginaryLiteral(ImaginaryLiteral *E) { + Expr* SubExpr = E->getSubExpr(); + + if (SubExpr->getType()->isRealFloatingType()) { + APFloat Result(0.0); + + if (!EvaluateFloat(SubExpr, Result, Info)) + return APValue(); + + return APValue(APFloat(Result.getSemantics(), APFloat::fcZero, false), + Result); + } else { + assert(SubExpr->getType()->isIntegerType() && + "Unexpected imaginary literal."); + + llvm::APSInt Result; + if (!EvaluateInteger(SubExpr, Result, Info)) + return APValue(); + + llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); + Zero = 0; + return APValue(Zero, Result); + } + } + + APValue VisitCastExpr(CastExpr *E) { + Expr* SubExpr = E->getSubExpr(); + QualType EltType = E->getType()->getAsComplexType()->getElementType(); + QualType SubType = SubExpr->getType(); + + if (SubType->isRealFloatingType()) { + APFloat Result(0.0); + + if (!EvaluateFloat(SubExpr, Result, Info)) + return APValue(); + + if (EltType->isRealFloatingType()) { + Result = HandleFloatToFloatCast(EltType, SubType, Result, Info.Ctx); + return APValue(Result, + APFloat(Result.getSemantics(), APFloat::fcZero, false)); + } else { + llvm::APSInt IResult; + IResult = HandleFloatToIntCast(EltType, SubType, Result, Info.Ctx); + llvm::APSInt Zero(IResult.getBitWidth(), !IResult.isSigned()); + Zero = 0; + return APValue(IResult, Zero); + } + } else if (SubType->isIntegerType()) { + APSInt Result; + + if (!EvaluateInteger(SubExpr, Result, Info)) + return APValue(); + + if (EltType->isRealFloatingType()) { + APFloat FResult = + HandleIntToFloatCast(EltType, SubType, Result, Info.Ctx); + return APValue(FResult, + APFloat(FResult.getSemantics(), APFloat::fcZero, false)); + } else { + Result = HandleIntToIntCast(EltType, SubType, Result, Info.Ctx); + llvm::APSInt Zero(Result.getBitWidth(), !Result.isSigned()); + Zero = 0; + return APValue(Result, Zero); + } + } else if (const ComplexType *CT = SubType->getAsComplexType()) { + APValue Src; + + if (!EvaluateComplex(SubExpr, Src, Info)) + return APValue(); + + QualType SrcType = CT->getElementType(); + + if (Src.isComplexFloat()) { + if (EltType->isRealFloatingType()) { + return APValue(HandleFloatToFloatCast(EltType, SrcType, + Src.getComplexFloatReal(), + Info.Ctx), + HandleFloatToFloatCast(EltType, SrcType, + Src.getComplexFloatImag(), + Info.Ctx)); + } else { + return APValue(HandleFloatToIntCast(EltType, SrcType, + Src.getComplexFloatReal(), + Info.Ctx), + HandleFloatToIntCast(EltType, SrcType, + Src.getComplexFloatImag(), + Info.Ctx)); + } + } else { + assert(Src.isComplexInt() && "Invalid evaluate result."); + if (EltType->isRealFloatingType()) { + return APValue(HandleIntToFloatCast(EltType, SrcType, + Src.getComplexIntReal(), + Info.Ctx), + HandleIntToFloatCast(EltType, SrcType, + Src.getComplexIntImag(), + Info.Ctx)); + } else { + return APValue(HandleIntToIntCast(EltType, SrcType, + Src.getComplexIntReal(), + Info.Ctx), + HandleIntToIntCast(EltType, SrcType, + Src.getComplexIntImag(), + Info.Ctx)); + } + } + } + + // FIXME: Handle more casts. + return APValue(); + } + + APValue VisitBinaryOperator(const BinaryOperator *E); + APValue VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + APValue VisitUnaryExtension(const UnaryOperator *E) + { return Visit(E->getSubExpr()); } + // FIXME Missing: unary +/-/~, binary div, ImplicitValueInitExpr, + // conditional ?:, comma +}; +} // end anonymous namespace + +static bool EvaluateComplex(const Expr *E, APValue &Result, EvalInfo &Info) +{ + Result = ComplexExprEvaluator(Info).Visit(const_cast<Expr*>(E)); + assert((!Result.isComplexFloat() || + (&Result.getComplexFloatReal().getSemantics() == + &Result.getComplexFloatImag().getSemantics())) && + "Invalid complex evaluation."); + return Result.isComplexFloat() || Result.isComplexInt(); +} + +APValue ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) +{ + APValue Result, RHS; + + if (!EvaluateComplex(E->getLHS(), Result, Info)) + return APValue(); + + if (!EvaluateComplex(E->getRHS(), RHS, Info)) + return APValue(); + + assert(Result.isComplexFloat() == RHS.isComplexFloat() && + "Invalid operands to binary operator."); + switch (E->getOpcode()) { + default: return APValue(); + case BinaryOperator::Add: + if (Result.isComplexFloat()) { + Result.getComplexFloatReal().add(RHS.getComplexFloatReal(), + APFloat::rmNearestTiesToEven); + Result.getComplexFloatImag().add(RHS.getComplexFloatImag(), + APFloat::rmNearestTiesToEven); + } else { + Result.getComplexIntReal() += RHS.getComplexIntReal(); + Result.getComplexIntImag() += RHS.getComplexIntImag(); + } + break; + case BinaryOperator::Sub: + if (Result.isComplexFloat()) { + Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(), + APFloat::rmNearestTiesToEven); + Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(), + APFloat::rmNearestTiesToEven); + } else { + Result.getComplexIntReal() -= RHS.getComplexIntReal(); + Result.getComplexIntImag() -= RHS.getComplexIntImag(); + } + break; + case BinaryOperator::Mul: + if (Result.isComplexFloat()) { + APValue LHS = Result; + APFloat &LHS_r = LHS.getComplexFloatReal(); + APFloat &LHS_i = LHS.getComplexFloatImag(); + APFloat &RHS_r = RHS.getComplexFloatReal(); + APFloat &RHS_i = RHS.getComplexFloatImag(); + + APFloat Tmp = LHS_r; + Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Result.getComplexFloatReal() = Tmp; + Tmp = LHS_i; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Result.getComplexFloatReal().subtract(Tmp, APFloat::rmNearestTiesToEven); + + Tmp = LHS_r; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Result.getComplexFloatImag() = Tmp; + Tmp = LHS_i; + Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); + } else { + APValue LHS = Result; + Result.getComplexIntReal() = + (LHS.getComplexIntReal() * RHS.getComplexIntReal() - + LHS.getComplexIntImag() * RHS.getComplexIntImag()); + Result.getComplexIntImag() = + (LHS.getComplexIntReal() * RHS.getComplexIntImag() + + LHS.getComplexIntImag() * RHS.getComplexIntReal()); + } + break; + } + + return Result; +} + +//===----------------------------------------------------------------------===// +// Top level Expr::Evaluate method. +//===----------------------------------------------------------------------===// + +/// Evaluate - Return true if this is a constant which we can fold using +/// any crazy technique (that has nothing to do with language standards) that +/// we want to. If this function returns true, it returns the folded constant +/// in Result. +bool Expr::Evaluate(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + + if (getType()->isVectorType()) { + if (!EvaluateVector(this, Result.Val, Info)) + return false; + } else if (getType()->isIntegerType()) { + if (!IntExprEvaluator(Info, Result.Val).Visit(const_cast<Expr*>(this))) + return false; + } else if (getType()->hasPointerRepresentation()) { + if (!EvaluatePointer(this, Result.Val, Info)) + return false; + } else if (getType()->isRealFloatingType()) { + llvm::APFloat f(0.0); + if (!EvaluateFloat(this, f, Info)) + return false; + + Result.Val = APValue(f); + } else if (getType()->isAnyComplexType()) { + if (!EvaluateComplex(this, Result.Val, Info)) + return false; + } else + return false; + + return true; +} + +bool Expr::EvaluateAsLValue(EvalResult &Result, ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + + return EvaluateLValue(this, Result.Val, Info) && !Result.HasSideEffects; +} + +/// isEvaluatable - Call Evaluate to see if this expression can be constant +/// folded, but discard the result. +bool Expr::isEvaluatable(ASTContext &Ctx) const { + EvalResult Result; + return Evaluate(Result, Ctx) && !Result.HasSideEffects; +} + +APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { + EvalResult EvalResult; + bool Result = Evaluate(EvalResult, Ctx); + Result = Result; + assert(Result && "Could not evaluate expression"); + assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer"); + + return EvalResult.Val.getInt(); +} diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp new file mode 100644 index 0000000..dd2fc14 --- /dev/null +++ b/lib/AST/InheritViz.cpp @@ -0,0 +1,168 @@ +//===- InheritViz.cpp - Graphviz visualization for inheritance --*- 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 CXXRecordDecl::viewInheritance, which +// generates a GraphViz DOT file that depicts the class inheritance +// diagram and then calls Graphviz/dot+gv on it. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/TypeOrdering.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" +#include <map> + +using namespace llvm; + +namespace clang { + +/// InheritanceHierarchyWriter - Helper class that writes out a +/// GraphViz file that diagrams the inheritance hierarchy starting at +/// a given C++ class type. Note that we do not use LLVM's +/// GraphWriter, because the interface does not permit us to properly +/// differentiate between uses of types as virtual bases +/// vs. non-virtual bases. +class InheritanceHierarchyWriter { + ASTContext& Context; + llvm::raw_ostream &Out; + std::map<QualType, int, QualTypeOrdering> DirectBaseCount; + std::set<QualType, QualTypeOrdering> KnownVirtualBases; + +public: + InheritanceHierarchyWriter(ASTContext& Context, llvm::raw_ostream& Out) + : Context(Context), Out(Out) { } + + void WriteGraph(QualType Type) { + Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n"; + WriteNode(Type, false); + Out << "}\n"; + } + +protected: + /// WriteNode - Write out the description of node in the inheritance + /// diagram, which may be a base class or it may be the root node. + void WriteNode(QualType Type, bool FromVirtual); + + /// WriteNodeReference - Write out a reference to the given node, + /// using a unique identifier for each direct base and for the + /// (only) virtual base. + llvm::raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual); +}; + +void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { + QualType CanonType = Context.getCanonicalType(Type); + + if (FromVirtual) { + if (KnownVirtualBases.find(CanonType) != KnownVirtualBases.end()) + return; + + // We haven't seen this virtual base before, so display it and + // its bases. + KnownVirtualBases.insert(CanonType); + } + + // Declare the node itself. + Out << " "; + WriteNodeReference(Type, FromVirtual); + + // Give the node a label based on the name of the class. + std::string TypeName = Type.getAsString(); + Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName); + + // If the name of the class was a typedef or something different + // from the "real" class name, show the real class name in + // parentheses so we don't confuse ourselves. + if (TypeName != CanonType.getAsString()) { + Out << "\\n(" << CanonType.getAsString() << ")"; + } + + // Finished describing the node. + Out << " \"];\n"; + + // Display the base classes. + const CXXRecordDecl *Decl + = static_cast<const CXXRecordDecl *>(Type->getAsRecordType()->getDecl()); + for (CXXRecordDecl::base_class_const_iterator Base = Decl->bases_begin(); + Base != Decl->bases_end(); ++Base) { + QualType CanonBaseType = Context.getCanonicalType(Base->getType()); + + // If this is not virtual inheritance, bump the direct base + // count for the type. + if (!Base->isVirtual()) + ++DirectBaseCount[CanonBaseType]; + + // Write out the node (if we need to). + WriteNode(Base->getType(), Base->isVirtual()); + + // Write out the edge. + Out << " "; + WriteNodeReference(Type, FromVirtual); + Out << " -> "; + WriteNodeReference(Base->getType(), Base->isVirtual()); + + // Write out edge attributes to show the kind of inheritance. + if (Base->isVirtual()) { + Out << " [ style=\"dashed\" ]"; + } + Out << ";"; + } +} + +/// WriteNodeReference - Write out a reference to the given node, +/// using a unique identifier for each direct base and for the +/// (only) virtual base. +llvm::raw_ostream& +InheritanceHierarchyWriter::WriteNodeReference(QualType Type, + bool FromVirtual) { + QualType CanonType = Context.getCanonicalType(Type); + + Out << "Class_" << CanonType.getAsOpaquePtr(); + if (!FromVirtual) + Out << "_" << DirectBaseCount[CanonType]; + return Out; +} + +/// viewInheritance - Display the inheritance hierarchy of this C++ +/// class using GraphViz. +void CXXRecordDecl::viewInheritance(ASTContext& Context) const { + QualType Self = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); + std::string ErrMsg; + sys::Path Filename = sys::Path::GetTemporaryDirectory(&ErrMsg); + if (Filename.isEmpty()) { + llvm::errs() << "Error: " << ErrMsg << "\n"; + return; + } + Filename.appendComponent(Self.getAsString() + ".dot"); + if (Filename.makeUnique(true,&ErrMsg)) { + llvm::errs() << "Error: " << ErrMsg << "\n"; + return; + } + + llvm::errs() << "Writing '" << Filename.c_str() << "'... "; + + llvm::raw_fd_ostream O(Filename.c_str(), false, ErrMsg); + + if (ErrMsg.empty()) { + InheritanceHierarchyWriter Writer(Context, O); + Writer.WriteGraph(Self); + llvm::errs() << " done. \n"; + + O.close(); + + // Display the graph + DisplayGraph(Filename); + } else { + llvm::errs() << "error opening file for writing!\n"; + } +} + +} diff --git a/lib/AST/Makefile b/lib/AST/Makefile new file mode 100644 index 0000000..f7d4e9f --- /dev/null +++ b/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 -I$(PROJ_OBJ_DIR)/../../include + +include $(LEVEL)/Makefile.common + diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp new file mode 100644 index 0000000..09522a2 --- /dev/null +++ b/lib/AST/NestedNameSpecifier.cpp @@ -0,0 +1,160 @@ +//===--- NestedNameSpecifier.cpp - C++ nested name specifiers -----*- 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 NestedNameSpecifier class, which represents +// a C++ nested-name-specifier. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> + +using namespace clang; + +NestedNameSpecifier * +NestedNameSpecifier::FindOrInsert(ASTContext &Context, + const NestedNameSpecifier &Mockup) { + llvm::FoldingSetNodeID ID; + Mockup.Profile(ID); + + void *InsertPos = 0; + NestedNameSpecifier *NNS + = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos); + if (!NNS) { + NNS = new (Context, 4) NestedNameSpecifier(Mockup); + Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos); + } + + return NNS; +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + IdentifierInfo *II) { + assert(II && "Identifier cannot be NULL"); + assert(Prefix && Prefix->isDependent() && "Prefix must be dependent"); + + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(Prefix); + Mockup.Prefix.setInt(Identifier); + Mockup.Specifier = II; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + NamespaceDecl *NS) { + assert(NS && "Namespace cannot be NULL"); + assert((!Prefix || + (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && + "Broken nested name specifier"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(Prefix); + Mockup.Prefix.setInt(Namespace); + Mockup.Specifier = NS; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(ASTContext &Context, NestedNameSpecifier *Prefix, + bool Template, Type *T) { + assert(T && "Type cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(Prefix); + Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec); + Mockup.Specifier = T; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) { + if (!Context.GlobalNestedNameSpecifier) + Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); + return Context.GlobalNestedNameSpecifier; +} + +/// \brief Whether this nested name specifier refers to a dependent +/// type or not. +bool NestedNameSpecifier::isDependent() const { + switch (getKind()) { + case Identifier: + // Identifier specifiers always represent dependent types + return true; + + case Namespace: + case Global: + return false; + + case TypeSpec: + case TypeSpecWithTemplate: + return getAsType()->isDependentType(); + } + + // Necessary to suppress a GCC warning. + return false; +} + +/// \brief Print this nested name specifier to the given output +/// stream. +void +NestedNameSpecifier::print(llvm::raw_ostream &OS, + const PrintingPolicy &Policy) const { + if (getPrefix()) + getPrefix()->print(OS, Policy); + + switch (getKind()) { + case Identifier: + OS << getAsIdentifier()->getName(); + break; + + case Namespace: + OS << getAsNamespace()->getIdentifier()->getName(); + break; + + case Global: + break; + + case TypeSpecWithTemplate: + OS << "template "; + // Fall through to print the type. + + case TypeSpec: { + std::string TypeStr; + Type *T = getAsType(); + + // If this is a qualified name type, suppress the qualification: + // it's part of our nested-name-specifier sequence anyway. FIXME: + // We should be able to assert that this doesn't happen. + if (const QualifiedNameType *QualT = dyn_cast<QualifiedNameType>(T)) + T = QualT->getNamedType().getTypePtr(); + + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + T->getAsStringInternal(TypeStr, InnerPolicy); + OS << TypeStr; + break; + } + } + + OS << "::"; +} + +void NestedNameSpecifier::Destroy(ASTContext &Context) { + this->~NestedNameSpecifier(); + Context.Deallocate((void *)this); +} + +void NestedNameSpecifier::dump() { + PrintingPolicy Policy; + Policy.CPlusPlus = true; + print(llvm::errs(), Policy); +} diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp new file mode 100644 index 0000000..9d87daa --- /dev/null +++ b/lib/AST/ParentMap.cpp @@ -0,0 +1,94 @@ +//===--- ParentMap.cpp - Mappings from Stmts to their Parents ---*- 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 ParentMap class. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ParentMap.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Expr.h" +#include "llvm/ADT/DenseMap.h" + +using namespace clang; + +typedef llvm::DenseMap<Stmt*, Stmt*> MapTy; + +static void BuildParentMap(MapTy& M, Stmt* S) { + for (Stmt::child_iterator I=S->child_begin(), E=S->child_end(); I!=E; ++I) + if (*I) { + M[*I] = S; + BuildParentMap(M, *I); + } +} + +ParentMap::ParentMap(Stmt* S) : Impl(0) { + if (S) { + MapTy *M = new MapTy(); + BuildParentMap(*M, S); + Impl = M; + } +} + +ParentMap::~ParentMap() { + delete (MapTy*) Impl; +} + +Stmt* ParentMap::getParent(Stmt* S) const { + MapTy* M = (MapTy*) Impl; + MapTy::iterator I = M->find(S); + return I == M->end() ? 0 : I->second; +} + +Stmt *ParentMap::getParentIgnoreParens(Stmt *S) const { + do { S = getParent(S); } while (S && isa<ParenExpr>(S)); + return S; +} + +bool ParentMap::isConsumedExpr(Expr* E) const { + Stmt *P = getParent(E); + Stmt *DirectChild = E; + + // Ignore parents that are parentheses or casts. + while (P && (isa<ParenExpr>(P) || isa<CastExpr>(P))) { + DirectChild = P; + P = getParent(P); + } + + if (!P) + return false; + + switch (P->getStmtClass()) { + default: + return isa<Expr>(P); + case Stmt::DeclStmtClass: + return true; + case Stmt::BinaryOperatorClass: { + BinaryOperator *BE = cast<BinaryOperator>(P); + // If it is a comma, only the right side is consumed. + // If it isn't a comma, both sides are consumed. + return BE->getOpcode()!=BinaryOperator::Comma ||DirectChild==BE->getRHS(); + } + case Stmt::ForStmtClass: + return DirectChild == cast<ForStmt>(P)->getCond(); + case Stmt::WhileStmtClass: + return DirectChild == cast<WhileStmt>(P)->getCond(); + case Stmt::DoStmtClass: + return DirectChild == cast<DoStmt>(P)->getCond(); + case Stmt::IfStmtClass: + return DirectChild == cast<IfStmt>(P)->getCond(); + case Stmt::IndirectGotoStmtClass: + return DirectChild == cast<IndirectGotoStmt>(P)->getTarget(); + case Stmt::SwitchStmtClass: + return DirectChild == cast<SwitchStmt>(P)->getCond(); + case Stmt::ReturnStmtClass: + return true; + } +} + diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp new file mode 100644 index 0000000..1757791 --- /dev/null +++ b/lib/AST/Stmt.cpp @@ -0,0 +1,587 @@ +//===--- 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/ExprObjC.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/Type.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.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(CLASS, PARENT) \ + StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ + StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); +#include "clang/AST/StmtNodes.def" + + return StmtClassInfo[E]; +} + +const char *Stmt::getStmtClassName() const { + return getStmtInfoTableEntry(sClass).Name; +} + +void Stmt::DestroyChildren(ASTContext &C) { + for (child_iterator I = child_begin(), E = child_end(); I !=E; ) + if (Stmt* Child = *I++) Child->Destroy(C); +} + +void Stmt::Destroy(ASTContext &C) { + DestroyChildren(C); + // FIXME: Eventually all Stmts should be allocated with the allocator + // in ASTContext, just like with Decls. + this->~Stmt(); + C.Deallocate((void *)this); +} + +void DeclStmt::Destroy(ASTContext &C) { + this->~DeclStmt(); + C.Deallocate((void *)this); +} + +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; + if (StmtClassInfo[i].Counter == 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; +} + +NullStmt* NullStmt::Clone(ASTContext &C) const { + return new (C) NullStmt(SemiLoc); +} + +ContinueStmt* ContinueStmt::Clone(ASTContext &C) const { + return new (C) ContinueStmt(ContinueLoc); +} + +BreakStmt* BreakStmt::Clone(ASTContext &C) const { + return new (C) BreakStmt(BreakLoc); +} + +void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { + if (this->Body) + C.Deallocate(Body); + this->NumStmts = NumStmts; + + Body = new (C) Stmt*[NumStmts]; + memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts); +} + +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; + } + } +} + +Expr *AsmStmt::getOutputExpr(unsigned i) { + return cast<Expr>(Exprs[i]); +} + +/// getOutputConstraint - Return the constraint string for the specified +/// output operand. All output constraints are known to be non-empty (either +/// '=' or '+'). +std::string AsmStmt::getOutputConstraint(unsigned i) const { + return std::string(Constraints[i]->getStrData(), + Constraints[i]->getByteLength()); +} + +/// getNumPlusOperands - Return the number of output operands that have a "+" +/// constraint. +unsigned AsmStmt::getNumPlusOperands() const { + unsigned Res = 0; + for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) + if (isOutputPlusConstraint(i)) + ++Res; + return Res; +} + + + +Expr *AsmStmt::getInputExpr(unsigned i) { + return cast<Expr>(Exprs[i + NumOutputs]); +} + +/// getInputConstraint - Return the specified input constraint. Unlike output +/// constraints, these can be empty. +std::string AsmStmt::getInputConstraint(unsigned i) const { + return std::string(Constraints[i + NumOutputs]->getStrData(), + Constraints[i + NumOutputs]->getByteLength()); +} + + +void AsmStmt::setOutputsAndInputs(unsigned NumOutputs, + unsigned NumInputs, + const std::string *Names, + StringLiteral **Constraints, + Stmt **Exprs) { + this->NumOutputs = NumOutputs; + this->NumInputs = NumInputs; + this->Names.clear(); + this->Names.insert(this->Names.end(), Names, Names + NumOutputs + NumInputs); + this->Constraints.clear(); + this->Constraints.insert(this->Constraints.end(), + Constraints, Constraints + NumOutputs + NumInputs); + this->Exprs.clear(); + this->Exprs.insert(this->Exprs.end(), Exprs, Exprs + NumOutputs + NumInputs); +} + +/// getNamedOperand - Given a symbolic operand reference like %[foo], +/// translate this into a numeric value needed to reference the same operand. +/// This returns -1 if the operand name is invalid. +int AsmStmt::getNamedOperand(const std::string &SymbolicName) const { + unsigned NumPlusOperands = 0; + + // Check if this is an output operand. + for (unsigned i = 0, e = getNumOutputs(); i != e; ++i) { + if (getOutputName(i) == SymbolicName) + return i; + } + + for (unsigned i = 0, e = getNumInputs(); i != e; ++i) + if (getInputName(i) == SymbolicName) + return getNumOutputs() + NumPlusOperands + i; + + // Not found. + return -1; +} + +void AsmStmt::setClobbers(StringLiteral **Clobbers, unsigned NumClobbers) { + this->Clobbers.clear(); + this->Clobbers.insert(this->Clobbers.end(), Clobbers, Clobbers + NumClobbers); +} + +/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing +/// it into pieces. If the asm string is erroneous, emit errors and return +/// true, otherwise return false. +unsigned AsmStmt::AnalyzeAsmString(llvm::SmallVectorImpl<AsmStringPiece>&Pieces, + ASTContext &C, unsigned &DiagOffs) const { + const char *StrStart = getAsmString()->getStrData(); + const char *StrEnd = StrStart + getAsmString()->getByteLength(); + const char *CurPtr = StrStart; + + // "Simple" inline asms have no constraints or operands, just convert the asm + // string to escape $'s. + if (isSimple()) { + std::string Result; + for (; CurPtr != StrEnd; ++CurPtr) { + switch (*CurPtr) { + case '$': + Result += "$$"; + break; + default: + Result += *CurPtr; + break; + } + } + Pieces.push_back(AsmStringPiece(Result)); + return 0; + } + + // CurStringPiece - The current string that we are building up as we scan the + // asm string. + std::string CurStringPiece; + + while (1) { + // Done with the string? + if (CurPtr == StrEnd) { + if (!CurStringPiece.empty()) + Pieces.push_back(AsmStringPiece(CurStringPiece)); + return 0; + } + + char CurChar = *CurPtr++; + if (CurChar == '$') { + CurStringPiece += "$$"; + continue; + } else if (CurChar != '%') { + CurStringPiece += CurChar; + continue; + } + + // Escaped "%" character in asm string. + if (CurPtr == StrEnd) { + // % at end of string is invalid (no escape). + DiagOffs = CurPtr-StrStart-1; + return diag::err_asm_invalid_escape; + } + + char EscapedChar = *CurPtr++; + if (EscapedChar == '%') { // %% -> % + // Escaped percentage sign. + CurStringPiece += '%'; + continue; + } + + if (EscapedChar == '=') { // %= -> Generate an unique ID. + CurStringPiece += "${:uid}"; + continue; + } + + // Otherwise, we have an operand. If we have accumulated a string so far, + // add it to the Pieces list. + if (!CurStringPiece.empty()) { + Pieces.push_back(AsmStringPiece(CurStringPiece)); + CurStringPiece.clear(); + } + + // Handle %x4 and %x[foo] by capturing x as the modifier character. + char Modifier = '\0'; + if (isalpha(EscapedChar)) { + Modifier = EscapedChar; + EscapedChar = *CurPtr++; + } + + if (isdigit(EscapedChar)) { + // %n - Assembler operand n + unsigned N = 0; + + --CurPtr; + while (CurPtr != StrEnd && isdigit(*CurPtr)) + N = N*10 + ((*CurPtr++)-'0'); + + unsigned NumOperands = + getNumOutputs() + getNumPlusOperands() + getNumInputs(); + if (N >= NumOperands) { + DiagOffs = CurPtr-StrStart-1; + return diag::err_asm_invalid_operand_number; + } + + Pieces.push_back(AsmStringPiece(N, Modifier)); + continue; + } + + // Handle %[foo], a symbolic operand reference. + if (EscapedChar == '[') { + DiagOffs = CurPtr-StrStart-1; + + // Find the ']'. + const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); + if (NameEnd == 0) + return diag::err_asm_unterminated_symbolic_operand_name; + if (NameEnd == CurPtr) + return diag::err_asm_empty_symbolic_operand_name; + + std::string SymbolicName(CurPtr, NameEnd); + + int N = getNamedOperand(SymbolicName); + if (N == -1) { + // Verify that an operand with that name exists. + DiagOffs = CurPtr-StrStart; + return diag::err_asm_unknown_symbolic_operand_name; + } + Pieces.push_back(AsmStringPiece(N, Modifier)); + + CurPtr = NameEnd+1; + continue; + } + + DiagOffs = CurPtr-StrStart-1; + return diag::err_asm_invalid_escape; + } +} + +//===----------------------------------------------------------------------===// +// 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, + ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, + Stmt *atCatchList) +: Stmt(ObjCAtCatchStmtClass) { + ExceptionDecl = catchVarDecl; + SubExprs[BODY] = atCatchStmt; + SubExprs[NEXT_CATCH] = NULL; + // FIXME: O(N^2) in number of catch blocks. + if (atCatchList) { + 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 StmtIterator(DG.begin(), DG.end()); +} + +Stmt::child_iterator DeclStmt::child_end() { + return StmtIterator(DG.end(), DG.end()); +} + +// 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]+NumStmts; } + +// 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 +Expr* IndirectGotoStmt::getTarget() { return cast<Expr>(Target); } +const Expr* IndirectGotoStmt::getTarget() const { return cast<Expr>(Target); } + +Stmt::child_iterator IndirectGotoStmt::child_begin() { return &Target; } +Stmt::child_iterator IndirectGotoStmt::child_end() { return &Target+1; } + +// 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 +const Expr* ReturnStmt::getRetValue() const { + return cast_or_null<Expr>(RetExpr); +} +Expr* ReturnStmt::getRetValue() { + return cast_or_null<Expr>(RetExpr); +} + +Stmt::child_iterator ReturnStmt::child_begin() { + return &RetExpr; +} +Stmt::child_iterator ReturnStmt::child_end() { + return RetExpr ? &RetExpr+1 : &RetExpr; +} + +// AsmStmt +Stmt::child_iterator AsmStmt::child_begin() { + return Exprs.empty() ? 0 : &Exprs[0]; +} +Stmt::child_iterator AsmStmt::child_end() { + return Exprs.empty() ? 0 : &Exprs[0] + Exprs.size(); +} + +// 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; +} + +// CXXCatchStmt +Stmt::child_iterator CXXCatchStmt::child_begin() { + return &HandlerBlock; +} + +Stmt::child_iterator CXXCatchStmt::child_end() { + return &HandlerBlock + 1; +} + +QualType CXXCatchStmt::getCaughtType() { + if (ExceptionDecl) + return ExceptionDecl->getType(); + return QualType(); +} + +void CXXCatchStmt::Destroy(ASTContext& C) { + if (ExceptionDecl) + ExceptionDecl->Destroy(C); + Stmt::Destroy(C); +} + +// CXXTryStmt +Stmt::child_iterator CXXTryStmt::child_begin() { return &Stmts[0]; } +Stmt::child_iterator CXXTryStmt::child_end() { return &Stmts[0]+Stmts.size(); } + +CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc) { + Stmts.push_back(tryBlock); + Stmts.insert(Stmts.end(), handlers, handlers + numHandlers); +} diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp new file mode 100644 index 0000000..b24e912 --- /dev/null +++ b/lib/AST/StmtDumper.cpp @@ -0,0 +1,542 @@ +//===--- 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/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/PrettyPrinter.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; + + PrintingPolicy Policy; + 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 (!T.isNull()) { + // 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)) { + QualType Simplified = + TDT->LookThroughTypedefs().getQualifiedType(T.getCVRQualifiers()); + fprintf(F, ":'%s'", Simplified.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 VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); + void VisitBinaryOperator(BinaryOperator *Node); + void VisitCompoundAssignOperator(CompoundAssignOperator *Node); + void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitTypesCompatibleExpr(TypesCompatibleExpr *Node); + + // C++ + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); + void VisitCXXThisExpr(CXXThisExpr *Node); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); + + // ObjC + void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(ObjCMessageExpr* Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); + void VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + void VisitObjCSuperExpr(ObjCSuperExpr *Node); + }; +} + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +void StmtDumper::DumpLocation(SourceLocation Loc) { + SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); + + if (SpellingLoc.isInvalid()) { + fprintf(stderr, "<invalid sloc>"); + return; + } + + // The general format we print out is filename:line:col, but we drop pieces + // that haven't changed since the last loc printed. + PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc); + + if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { + fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(), + PLoc.getColumn()); + LastLocFilename = PLoc.getFilename(); + LastLocLine = PLoc.getLine(); + } else if (PLoc.getLine() != LastLocLine) { + fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn()); + LastLocLine = PLoc.getLine(); + } else { + fprintf(stderr, "col:%u", PLoc.getColumn()); + } +} + +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->getNameAsString().c_str()); + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + fprintf(F, "\""); + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getStorageClass() != VarDecl::None) + fprintf(F, "%s ", + VarDecl::getStorageClassSpecifierString(V->getStorageClass())); + } + + std::string Name = VD->getNameAsString(); + VD->getType().getAsStringInternal(Name, Policy); + 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 if (UsingDirectiveDecl *UD = dyn_cast<UsingDirectiveDecl>(D)) { + // print using-directive decl (e.g. "using namespace x;") + const char *ns; + if (const IdentifierInfo *II = UD->getNominatedNamespace()->getIdentifier()) + ns = II->getName(); + else + ns = "<anonymous>"; + fprintf(F, "\"%s %s;\"",UD->getDeclKindName(), ns); + } else { + assert(0 && "Unexpected decl"); + } +} + +void StmtDumper::VisitDeclStmt(DeclStmt *Node) { + DumpStmt(Node); + fprintf(F,"\n"); + for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); + DI != DE; ++DI) { + Decl* D = *DI; + ++IndentLevel; + Indent(); + fprintf(F, "%p ", (void*) D); + DumpDeclarator(D); + if (DI+1 != DE) + fprintf(F,"\n"); + --IndentLevel; + } +} + +void StmtDumper::VisitLabelStmt(LabelStmt *Node) { + DumpStmt(Node); + fprintf(F, " '%s'", 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::Var: fprintf(F,"Var"); break; + case Decl::ParmVar: fprintf(F,"ParmVar"); break; + case Decl::EnumConstant: fprintf(F,"EnumConstant"); break; + case Decl::Typedef: fprintf(F,"Typedef"); break; + case Decl::Record: fprintf(F,"Record"); break; + case Decl::Enum: fprintf(F,"Enum"); break; + case Decl::CXXRecord: fprintf(F,"CXXRecord"); 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()->getNameAsString().c_str(), + (void*)Node->getDecl()); +} + +void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + DumpExpr(Node); + + fprintf(F, " %sDecl='%s' %p", Node->getDecl()->getDeclKindName(), + Node->getDecl()->getNameAsString().c_str(), (void*)Node->getDecl()); + if (Node->isFreeIvar()) + fprintf(F, " isFreeIvar"); +} + +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->getValueAsApproximateDouble()); +} + +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::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s ", Node->isSizeOf() ? "sizeof" : "alignof"); + if (Node->isArgumentType()) + DumpType(Node->getArgumentType()); +} + +void StmtDumper::VisitMemberExpr(MemberExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s%s %p", Node->isArrow() ? "->" : ".", + Node->getMemberDecl()->getNameAsString().c_str(), + (void*)Node->getMemberDecl()); +} +void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *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' ComputeLHSTy=", + BinaryOperator::getOpcodeStr(Node->getOpcode())); + DumpType(Node->getComputationLHSType()); + fprintf(F, " ComputeResultTy="); + DumpType(Node->getComputationResultType()); +} + +// 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::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s<%s>", Node->getCastName(), + Node->getTypeAsWritten().getAsString().c_str()); +} + +void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + DumpExpr(Node); + fprintf(F, " %s", Node->getValue() ? "true" : "false"); +} + +void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { + DumpExpr(Node); + fprintf(F, " this"); +} + +void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { + DumpExpr(Node); + fprintf(F, " functional cast to %s", + Node->getTypeAsWritten().getAsString().c_str()); +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { + DumpExpr(Node); + fprintf(F, " selector=%s", Node->getSelector().getAsString().c_str()); + IdentifierInfo* clsName = Node->getClassName(); + if (clsName) fprintf(F, " class=%s", clsName->getName()); +} + +void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + DumpType(Node->getEncodedType()); +} + +void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + fprintf(F, "%s", Node->getSelector().getAsString().c_str()); +} + +void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + + fprintf(F, " "); + fprintf(F, "%s", Node->getProtocol()->getNameAsString().c_str()); +} + +void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + DumpExpr(Node); + + fprintf(F, " Kind=PropertyRef Property=\"%s\"", + Node->getProperty()->getNameAsString().c_str()); +} + +void StmtDumper::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { + DumpExpr(Node); + + ObjCMethodDecl *Getter = Node->getGetterMethod(); + ObjCMethodDecl *Setter = Node->getSetterMethod(); + fprintf(F, " Kind=MethodRef Getter=\"%s\" Setter=\"%s\"", + Getter->getSelector().getAsString().c_str(), + Setter ? Setter->getSelector().getAsString().c_str() : "(null)"); +} + +void StmtDumper::VisitObjCSuperExpr(ObjCSuperExpr *Node) { + DumpExpr(Node); + fprintf(F, " super"); +} + +//===----------------------------------------------------------------------===// +// 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/lib/AST/StmtIterator.cpp b/lib/AST/StmtIterator.cpp new file mode 100644 index 0000000..5c22e28 --- /dev/null +++ b/lib/AST/StmtIterator.cpp @@ -0,0 +1,155 @@ +//===--- 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/Decl.h" + +using namespace clang; + +// FIXME: Add support for dependent-sized array types in C++? +// Does it even make sense to build a CFG for an uninstantiated template? +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) + return; + + if (inDecl()) { + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) + if (VD->Init) + return; + + NextDecl(); + } + else if (inDeclGroup()) { + if (VarDecl* VD = dyn_cast<VarDecl>(*DGI)) + if (VD->Init) + return; + + NextDecl(); + } + else { + assert (inSizeOfTypeVA()); + assert(!decl); + RawVAPtr = 0; + } +} + +void StmtIteratorBase::NextDecl(bool ImmediateAdvance) { + assert (getVAPtr() == NULL); + + if (inDecl()) { + assert (decl); + + // FIXME: SIMPLIFY AWAY. + if (ImmediateAdvance) + decl = 0; + else if (HandleDecl(decl)) + return; + } + else { + assert (inDeclGroup()); + + if (ImmediateAdvance) + ++DGI; + + for ( ; DGI != DGE; ++DGI) + if (HandleDecl(*DGI)) + return; + } + + RawVAPtr = 0; +} + +bool StmtIteratorBase::HandleDecl(Decl* D) { + + if (VarDecl* VD = dyn_cast<VarDecl>(D)) { + if (VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { + setVAPtr(VAPtr); + return true; + } + + if (VD->getInit()) + return true; + } + else if (TypedefDecl* TD = dyn_cast<TypedefDecl>(D)) { + if (VariableArrayType* VAPtr = + FindVA(TD->getUnderlyingType().getTypePtr())) { + setVAPtr(VAPtr); + return true; + } + } + else if (EnumConstantDecl* ECD = dyn_cast<EnumConstantDecl>(D)) { + if (ECD->getInitExpr()) + return true; + } + + return false; +} + +StmtIteratorBase::StmtIteratorBase(Decl* d) + : decl(d), RawVAPtr(DeclMode) { + assert (decl); + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) + : DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(VariableArrayType* t) +: decl(0), RawVAPtr(SizeOfTypeVAMode) { + RawVAPtr |= reinterpret_cast<uintptr_t>(t); +} + +Stmt*& StmtIteratorBase::GetDeclExpr() const { + + if (VariableArrayType* VAPtr = getVAPtr()) { + assert (VAPtr->SizeExpr); + return VAPtr->SizeExpr; + } + + assert (inDecl() || inDeclGroup()); + + if (inDeclGroup()) { + VarDecl* VD = cast<VarDecl>(*DGI); + return *VD->getInitAddress(); + } + + assert (inDecl()); + + if (VarDecl* VD = dyn_cast<VarDecl>(decl)) { + assert (VD->Init); + return *VD->getInitAddress(); + } + + EnumConstantDecl* ECD = cast<EnumConstantDecl>(decl); + return ECD->Init; +} diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp new file mode 100644 index 0000000..710da63 --- /dev/null +++ b/lib/AST/StmtPrinter.cpp @@ -0,0 +1,1239 @@ +//===--- 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/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/Streams.h" +#include "llvm/Support/Format.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtPrinter Visitor +//===----------------------------------------------------------------------===// + +namespace { + class VISIBILITY_HIDDEN StmtPrinter : public StmtVisitor<StmtPrinter> { + llvm::raw_ostream &OS; + ASTContext &Context; + unsigned IndentLevel; + clang::PrinterHelper* Helper; + PrintingPolicy Policy; + + public: + StmtPrinter(llvm::raw_ostream &os, ASTContext &C, PrinterHelper* helper, + const PrintingPolicy &Policy = PrintingPolicy(), + unsigned Indentation = 0) + : OS(os), Context(C), IndentLevel(Indentation), Helper(helper), + Policy(Policy) {} + + void PrintStmt(Stmt *S) { + PrintStmt(S, Policy.Indentation); + } + + void PrintStmt(Stmt *S, int SubIndent) { + 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 PrintRawDeclStmt(DeclStmt *S); + void PrintRawIfStmt(IfStmt *If); + void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); + + void PrintExpr(Expr *E) { + if (E) + Visit(E); + else + OS << "<null expr>"; + } + + llvm::raw_ostream &Indent(int Delta = 0) { + 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(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) { + D->print(OS, Context, Policy, IndentLevel); +} + +void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { + DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); + llvm::SmallVector<Decl*, 2> Decls; + for ( ; Begin != End; ++Begin) + Decls.push_back(*Begin); + + Decl::printGroup(Decls.data(), Decls.size(), OS, Context, Policy, + IndentLevel); +} + +void StmtPrinter::VisitNullStmt(NullStmt *Node) { + Indent() << ";\n"; +} + +void StmtPrinter::VisitDeclStmt(DeclStmt *Node) { + Indent(); + PrintRawDeclStmt(Node); + 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()); + OS << ')'; + + 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())) + PrintRawDeclStmt(DS); + 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())) + PrintRawDeclStmt(DS); + 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->getOutputConstraintLiteral(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->getInputConstraintLiteral(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->getCatchParamDecl()) { + if (Decl *DS = catchStmt->getCatchParamDecl()) + PrintRawDecl(DS); + } + 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"; +} + +void StmtPrinter::PrintRawCXXCatchStmt(CXXCatchStmt *Node) { + OS << "catch ("; + if (Decl *ExDecl = Node->getExceptionDecl()) + PrintRawDecl(ExDecl); + else + OS << "..."; + OS << ") "; + PrintRawCompoundStmt(cast<CompoundStmt>(Node->getHandlerBlock())); +} + +void StmtPrinter::VisitCXXCatchStmt(CXXCatchStmt *Node) { + Indent(); + PrintRawCXXCatchStmt(Node); + OS << "\n"; +} + +void StmtPrinter::VisitCXXTryStmt(CXXTryStmt *Node) { + Indent() << "try "; + PrintRawCompoundStmt(Node->getTryBlock()); + for(unsigned i = 0, e = Node->getNumHandlers(); i < e; ++i) { + OS << " "; + PrintRawCXXCatchStmt(Node->getHandler(i)); + } + OS << "\n"; +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitExpr(Expr *Node) { + OS << "<<unknown expr type>>"; +} + +void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + OS << Node->getDecl()->getNameAsString(); +} + +void StmtPrinter::VisitQualifiedDeclRefExpr(QualifiedDeclRefExpr *Node) { + NamedDecl *D = Node->getDecl(); + + Node->getQualifier()->print(OS, Policy); + OS << D->getNameAsString(); +} + +void StmtPrinter::VisitUnresolvedDeclRefExpr(UnresolvedDeclRefExpr *Node) { + Node->getQualifier()->print(OS, Policy); + OS << Node->getDeclName().getAsString(); +} + +void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + OS << Node->getDecl()->getNameAsString(); +} + +void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << "."; + } + OS << Node->getProperty()->getNameAsCString(); +} + +void StmtPrinter::VisitObjCKVCRefExpr(ObjCKVCRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << "."; + } + // FIXME: Setter/Getter names +} + +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) { + unsigned value = Node->getValue(); + if (Node->isWide()) + OS << "L"; + 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" << llvm::format("%x", value) << "'"; + } 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 (Node->getType()->getAsBuiltinType()->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->getValueAsApproximateDouble(); +} + +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) { + unsigned char Char = Str->getStrData()[i]; + + switch (Char) { + default: + if (isprint(Char)) + OS << (char)Char; + else // Output anything hard as an octal escape. + OS << '\\' + << (char)('0'+ ((Char >> 6) & 7)) + << (char)('0'+ ((Char >> 3) & 7)) + << (char)('0'+ ((Char >> 0) & 7)); + break; + // Handle some common non-printable cases 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 __real. + switch (Node->getOpcode()) { + default: break; + 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<UnaryOperator>(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()->getNameAsString(); + return false; + } +} + +void StmtPrinter::VisitUnaryOffsetOf(UnaryOperator *Node) { + OS << "__builtin_offsetof("; + PrintOffsetOfDesignator(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *Node) { + OS << (Node->isSizeOf() ? "sizeof" : "__alignof"); + if (Node->isArgumentType()) + OS << "(" << Node->getArgumentType().getAsString() << ")"; + else { + OS << " "; + PrintExpr(Node->getArgumentExpr()); + } +} +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 (isa<CXXDefaultArgExpr>(Call->getArg(i))) { + // Don't print any defaulted arguments + break; + } + + if (i) OS << ", "; + PrintExpr(Call->getArg(i)); + } + OS << ")"; +} +void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { + // FIXME: Suppress printing implicit bases (like "this") + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + // FIXME: Suppress printing references to unnamed objects + // representing anonymous unions/structs + OS << Node->getMemberDecl()->getNameAsString(); +} +void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { + PrintExpr(Node->getBase()); + OS << "."; + OS << Node->getAccessor().getName(); +} +void StmtPrinter::VisitCastExpr(CastExpr *) { + assert(0 && "CastExpr is an abstract class"); +} +void StmtPrinter::VisitExplicitCastExpr(ExplicitCastExpr *) { + assert(0 && "ExplicitCastExpr is an abstract class"); +} +void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *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 extension 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::VisitGNUNullExpr(GNUNullExpr *) { + OS << "__null"; +} + +void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) { + OS << "__builtin_shufflevector("; + for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << ")"; +} + +void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { + if (Node->getSyntacticForm()) { + Visit(Node->getSyntacticForm()); + return; + } + + OS << "{ "; + for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { + if (i) OS << ", "; + if (Node->getInit(i)) + PrintExpr(Node->getInit(i)); + else + OS << "0"; + } + OS << " }"; +} + +void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { + for (DesignatedInitExpr::designators_iterator D = Node->designators_begin(), + DEnd = Node->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + if (D->getDotLoc().isInvalid()) + OS << D->getFieldName()->getName() << ":"; + else + OS << "." << D->getFieldName()->getName(); + } else { + OS << "["; + if (D->isArrayDesignator()) { + PrintExpr(Node->getArrayIndex(*D)); + } else { + PrintExpr(Node->getArrayRangeStart(*D)); + OS << " ... "; + PrintExpr(Node->getArrayRangeEnd(*D)); + } + OS << "]"; + } + } + + OS << " = "; + PrintExpr(Node->getInit()); +} + +void StmtPrinter::VisitImplicitValueInitExpr(ImplicitValueInitExpr *Node) { + if (Policy.CPlusPlus) + OS << "/*implicit*/" << Node->getType().getAsString(Policy) << "()"; + else { + OS << "/*implicit*/(" << Node->getType().getAsString(Policy) << ")"; + if (Node->getType()->isRecordType()) + OS << "{}"; + else + OS << 0; + } +} + +void StmtPrinter::VisitVAArgExpr(VAArgExpr *Node) { + OS << "__builtin_va_arg("; + PrintExpr(Node->getSubExpr()); + OS << ", "; + OS << Node->getType().getAsString(); + OS << ")"; +} + +// C++ +void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { + const char *OpStrings[NUM_OVERLOADED_OPERATORS] = { + "", +#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + + OverloadedOperatorKind Kind = Node->getOperator(); + if (Kind == OO_PlusPlus || Kind == OO_MinusMinus) { + if (Node->getNumArgs() == 1) { + OS << OpStrings[Kind] << ' '; + PrintExpr(Node->getArg(0)); + } else { + PrintExpr(Node->getArg(0)); + OS << ' ' << OpStrings[Kind]; + } + } else if (Kind == OO_Call) { + PrintExpr(Node->getArg(0)); + OS << '('; + for (unsigned ArgIdx = 1; ArgIdx < Node->getNumArgs(); ++ArgIdx) { + if (ArgIdx > 1) + OS << ", "; + if (!isa<CXXDefaultArgExpr>(Node->getArg(ArgIdx))) + PrintExpr(Node->getArg(ArgIdx)); + } + OS << ')'; + } else if (Kind == OO_Subscript) { + PrintExpr(Node->getArg(0)); + OS << '['; + PrintExpr(Node->getArg(1)); + OS << ']'; + } else if (Node->getNumArgs() == 1) { + OS << OpStrings[Kind] << ' '; + PrintExpr(Node->getArg(0)); + } else if (Node->getNumArgs() == 2) { + PrintExpr(Node->getArg(0)); + OS << ' ' << OpStrings[Kind] << ' '; + PrintExpr(Node->getArg(1)); + } else { + assert(false && "unknown overloaded operator"); + } +} + +void StmtPrinter::VisitCXXMemberCallExpr(CXXMemberCallExpr *Node) { + VisitCallExpr(cast<CallExpr>(Node)); +} + +void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { + OS << Node->getCastName() << '<'; + OS << Node->getTypeAsWritten().getAsString() << ">("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXStaticCastExpr(CXXStaticCastExpr *Node) { + VisitCXXNamedCastExpr(Node); +} + +void StmtPrinter::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *Node) { + VisitCXXNamedCastExpr(Node); +} + +void StmtPrinter::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *Node) { + VisitCXXNamedCastExpr(Node); +} + +void StmtPrinter::VisitCXXConstCastExpr(CXXConstCastExpr *Node) { + VisitCXXNamedCastExpr(Node); +} + +void StmtPrinter::VisitCXXTypeidExpr(CXXTypeidExpr *Node) { + OS << "typeid("; + if (Node->isTypeOperand()) { + OS << Node->getTypeOperand().getAsString(); + } else { + PrintExpr(Node->getExprOperand()); + } + OS << ")"; +} + +void StmtPrinter::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + OS << (Node->getValue() ? "true" : "false"); +} + +void StmtPrinter::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *Node) { + OS << "nullptr"; +} + +void StmtPrinter::VisitCXXThisExpr(CXXThisExpr *Node) { + OS << "this"; +} + +void StmtPrinter::VisitCXXThrowExpr(CXXThrowExpr *Node) { + if (Node->getSubExpr() == 0) + OS << "throw"; + else { + OS << "throw "; + PrintExpr(Node->getSubExpr()); + } +} + +void StmtPrinter::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *Node) { + // Nothing to print: we picked up the default argument +} + +void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { + OS << Node->getType().getAsString(); + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { + PrintExpr(Node->getSubExpr()); +} + +void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { + OS << Node->getType().getAsString(); + OS << "("; + for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), + ArgEnd = Node->arg_end(); + Arg != ArgEnd; ++Arg) { + if (Arg != Node->arg_begin()) + OS << ", "; + PrintExpr(*Arg); + } + OS << ")"; +} + +void StmtPrinter::VisitCXXZeroInitValueExpr(CXXZeroInitValueExpr *Node) { + OS << Node->getType().getAsString() << "()"; +} + +void +StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) { + PrintRawDecl(E->getVarDecl()); +} + +void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { + if (E->isGlobalNew()) + OS << "::"; + OS << "new "; + unsigned NumPlace = E->getNumPlacementArgs(); + if (NumPlace > 0) { + OS << "("; + PrintExpr(E->getPlacementArg(0)); + for (unsigned i = 1; i < NumPlace; ++i) { + OS << ", "; + PrintExpr(E->getPlacementArg(i)); + } + OS << ") "; + } + if (E->isParenTypeId()) + OS << "("; + std::string TypeS; + if (Expr *Size = E->getArraySize()) { + llvm::raw_string_ostream s(TypeS); + Size->printPretty(s, Context, Helper, Policy); + s.flush(); + TypeS = "[" + TypeS + "]"; + } + E->getAllocatedType().getAsStringInternal(TypeS, Policy); + OS << TypeS; + if (E->isParenTypeId()) + OS << ")"; + + if (E->hasInitializer()) { + OS << "("; + unsigned NumCons = E->getNumConstructorArgs(); + if (NumCons > 0) { + PrintExpr(E->getConstructorArg(0)); + for (unsigned i = 1; i < NumCons; ++i) { + OS << ", "; + PrintExpr(E->getConstructorArg(i)); + } + } + OS << ")"; + } +} + +void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) { + if (E->isGlobalDelete()) + OS << "::"; + OS << "delete "; + if (E->isArrayForm()) + OS << "[] "; + PrintExpr(E->getArgument()); +} + +void StmtPrinter::VisitUnresolvedFunctionNameExpr(UnresolvedFunctionNameExpr *E) { + OS << E->getName().getAsString(); +} + +void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { + // Nothing to print. +} + +void StmtPrinter::VisitCXXExprWithTemporaries(CXXExprWithTemporaries *E) { + // Just forward to the sub expression. + PrintExpr(E->getSubExpr()); +} + +void +StmtPrinter::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *Node) { + OS << Node->getTypeAsWritten().getAsString(); + OS << "("; + for (CXXUnresolvedConstructExpr::arg_iterator Arg = Node->arg_begin(), + ArgEnd = Node->arg_end(); + Arg != ArgEnd; ++Arg) { + if (Arg != Node->arg_begin()) + OS << ", "; + PrintExpr(*Arg); + } + OS << ")"; +} + +void StmtPrinter::VisitCXXUnresolvedMemberExpr(CXXUnresolvedMemberExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + OS << Node->getMember().getAsString(); +} + +static const char *getTypeTraitName(UnaryTypeTrait UTT) { + switch (UTT) { + default: assert(false && "Unknown type trait"); + case UTT_HasNothrowAssign: return "__has_nothrow_assign"; + case UTT_HasNothrowCopy: return "__has_nothrow_copy"; + case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; + case UTT_HasTrivialAssign: return "__has_trivial_assign"; + case UTT_HasTrivialCopy: return "__has_trivial_copy"; + case UTT_HasTrivialConstructor: return "__has_trivial_constructor"; + case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; + case UTT_HasVirtualDestructor: return "__has_virtual_destructor"; + case UTT_IsAbstract: return "__is_abstract"; + case UTT_IsClass: return "__is_class"; + case UTT_IsEmpty: return "__is_empty"; + case UTT_IsEnum: return "__is_enum"; + case UTT_IsPOD: return "__is_pod"; + case UTT_IsPolymorphic: return "__is_polymorphic"; + case UTT_IsUnion: return "__is_union"; + } +} + +void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getQueriedType().getAsString() << ")"; +} + +// 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().getAsString() << ')'; +} + +void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + OS << "@protocol(" << Node->getProtocol()->getNameAsString() << ')'; +} + +void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { + OS << "["; + Expr *receiver = Mess->getReceiver(); + if (receiver) PrintExpr(receiver); + else OS << Mess->getClassName()->getName(); + OS << ' '; + Selector selector = Mess->getSelector(); + if (selector.isUnarySelector()) { + OS << selector.getIdentifierInfoForSlot(0)->getName(); + } else { + for (unsigned i = 0, e = Mess->getNumArgs(); i != e; ++i) { + if (i < selector.getNumArgs()) { + if (i > 0) OS << ' '; + if (selector.getIdentifierInfoForSlot(i)) + OS << selector.getIdentifierInfoForSlot(i)->getName() << ':'; + else + OS << ":"; + } + else OS << ", "; // Handle variadic methods. + + PrintExpr(Mess->getArg(i)); + } + } + OS << "]"; +} + +void StmtPrinter::VisitObjCSuperExpr(ObjCSuperExpr *) { + OS << "super"; +} + +void StmtPrinter::VisitBlockExpr(BlockExpr *Node) { + BlockDecl *BD = Node->getBlockDecl(); + OS << "^"; + + const FunctionType *AFT = Node->getFunctionType(); + + if (isa<FunctionNoProtoType>(AFT)) { + OS << "()"; + } else if (!BD->param_empty() || cast<FunctionProtoType>(AFT)->isVariadic()) { + OS << '('; + std::string ParamStr; + for (BlockDecl::param_iterator AI = BD->param_begin(), + E = BD->param_end(); AI != E; ++AI) { + if (AI != BD->param_begin()) OS << ", "; + ParamStr = (*AI)->getNameAsString(); + (*AI)->getType().getAsStringInternal(ParamStr, Policy); + OS << ParamStr; + } + + const FunctionProtoType *FT = cast<FunctionProtoType>(AFT); + if (FT->isVariadic()) { + if (!BD->param_empty()) OS << ", "; + OS << "..."; + } + OS << ')'; + } +} + +void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { + OS << Node->getDecl()->getNameAsString(); +} +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dumpPretty(ASTContext& Context) const { + printPretty(llvm::errs(), Context, 0, PrintingPolicy()); +} + +void Stmt::printPretty(llvm::raw_ostream &OS, ASTContext& Context, + PrinterHelper* Helper, + const PrintingPolicy &Policy, + unsigned Indentation) const { + if (this == 0) { + OS << "<NULL>"; + return; + } + + if (Policy.Dump) { + dump(); + return; + } + + StmtPrinter P(OS, Context, Helper, Policy, Indentation); + P.Visit(const_cast<Stmt*>(this)); +} + +//===----------------------------------------------------------------------===// +// PrinterHelper +//===----------------------------------------------------------------------===// + +// Implement virtual destructor. +PrinterHelper::~PrinterHelper() {} diff --git a/lib/AST/StmtViz.cpp b/lib/AST/StmtViz.cpp new file mode 100644 index 0000000..1316d35 --- /dev/null +++ b/lib/AST/StmtViz.cpp @@ -0,0 +1,61 @@ +//===--- 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 "clang/AST/Decl.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::string OutSStr; + llvm::raw_string_ostream Out(OutSStr); + + 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/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp new file mode 100644 index 0000000..3613da7 --- /dev/null +++ b/lib/AST/TemplateName.cpp @@ -0,0 +1,65 @@ +//===--- TemplateName.h - C++ Template Name Representation-------*- 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 TemplateName interface and subclasses. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TemplateName.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +TemplateDecl *TemplateName::getAsTemplateDecl() const { + if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) + return Template; + + if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) + return QTN->getTemplateDecl(); + + return 0; +} + +bool TemplateName::isDependent() const { + if (TemplateDecl *Template = getAsTemplateDecl()) { + // FIXME: We don't yet have a notion of dependent + // declarations. When we do, check that. This hack won't last + // long!. + return isa<TemplateTemplateParmDecl>(Template); + } + + return true; +} + +void +TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, + bool SuppressNNS) const { + if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) + OS << Template->getIdentifier()->getName(); + else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + if (!SuppressNNS) + QTN->getQualifier()->print(OS, Policy); + if (QTN->hasTemplateKeyword()) + OS << "template "; + OS << QTN->getTemplateDecl()->getIdentifier()->getName(); + } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { + if (!SuppressNNS) + DTN->getQualifier()->print(OS, Policy); + OS << "template "; + OS << DTN->getName()->getName(); + } +} + +void TemplateName::dump() const { + PrintingPolicy Policy; + Policy.CPlusPlus = true; + print(llvm::errs(), Policy); +} diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp new file mode 100644 index 0000000..b2ee58f --- /dev/null +++ b/lib/AST/Type.cpp @@ -0,0 +1,1658 @@ +//===--- 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/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +bool QualType::isConstant(ASTContext &Ctx) const { + if (isConstQualified()) + return true; + + if (getTypePtr()->isArrayType()) + return Ctx.getAsArrayType(*this)->getElementType().isConstant(Ctx); + + return false; +} + +void Type::Destroy(ASTContext& C) { + this->~Type(); + C.Deallocate(this); +} + +void VariableArrayType::Destroy(ASTContext& C) { + if (SizeExpr) + SizeExpr->Destroy(C); + this->~VariableArrayType(); + C.Deallocate(this); +} + +void DependentSizedArrayType::Destroy(ASTContext& C) { + SizeExpr->Destroy(C); + this->~DependentSizedArrayType(); + C.Deallocate(this); +} + +/// getArrayElementTypeNoTypeQual - If this is an array type, return the +/// element type of the array, potentially with type qualifiers missing. +/// This method should never be used when type qualifiers are meaningful. +const Type *Type::getArrayElementTypeNoTypeQual() const { + // If this is directly an array type, return it. + if (const ArrayType *ATy = dyn_cast<ArrayType>(this)) + return ATy->getElementType().getTypePtr(); + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ArrayType>(CanonicalType)) { + // Look through type qualifiers + if (ArrayType *AT = dyn_cast<ArrayType>(CanonicalType.getUnqualifiedType())) + return AT->getElementType().getTypePtr(); + return 0; + } + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getDesugaredType())->getElementType().getTypePtr(); +} + +/// getDesugaredType - Return the specified type with any "sugar" removed from +/// the 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 returns "T*" as "T*", (not as "int*"), because the pointer is +/// concrete. +/// +/// \param ForDisplay When true, the desugaring is provided for +/// display purposes only. In this case, we apply more heuristics to +/// decide whether it is worth providing a desugared form of the type +/// or not. +QualType QualType::getDesugaredType(bool ForDisplay) const { + return getTypePtr()->getDesugaredType(ForDisplay) + .getWithAdditionalQualifiers(getCVRQualifiers()); +} + +/// 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. +/// +/// \param ForDisplay When true, the desugaring is provided for +/// display purposes only. In this case, we apply more heuristics to +/// decide whether it is worth providing a desugared form of the type +/// or not. +QualType Type::getDesugaredType(bool ForDisplay) const { + if (const TypedefType *TDT = dyn_cast<TypedefType>(this)) + return TDT->LookThroughTypedefs().getDesugaredType(); + if (const TypeOfExprType *TOE = dyn_cast<TypeOfExprType>(this)) + return TOE->getUnderlyingExpr()->getType().getDesugaredType(); + if (const TypeOfType *TOT = dyn_cast<TypeOfType>(this)) + return TOT->getUnderlyingType().getDesugaredType(); + if (const TemplateSpecializationType *Spec + = dyn_cast<TemplateSpecializationType>(this)) { + if (ForDisplay) + return QualType(this, 0); + + QualType Canon = Spec->getCanonicalTypeInternal(); + if (Canon->getAsTemplateSpecializationType()) + return QualType(this, 0); + return Canon->getDesugaredType(); + } + if (const QualifiedNameType *QualName = dyn_cast<QualifiedNameType>(this)) { + if (ForDisplay) { + // If desugaring the type that the qualified name is referring to + // produces something interesting, that's our desugared type. + QualType NamedType = QualName->getNamedType().getDesugaredType(); + if (NamedType != QualName->getNamedType()) + return NamedType; + } else + return QualName->getNamedType().getDesugaredType(); + } + + return QualType(this, 0); +} + +/// 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; + if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) + return AS->getBaseType()->isVoidType(); + return false; +} + +bool Type::isObjectType() const { + if (isa<FunctionType>(CanonicalType) || isa<ReferenceType>(CanonicalType) || + isa<IncompleteArrayType>(CanonicalType) || isVoidType()) + return false; + if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) + return AS->getBaseType()->isObjectType(); + return true; +} + +bool Type::isDerivedType() const { + switch (CanonicalType->getTypeClass()) { + case ExtQual: + return cast<ExtQualType>(CanonicalType)->getBaseType()->isDerivedType(); + case Pointer: + case VariableArray: + case ConstantArray: + case IncompleteArray: + case FunctionProto: + case FunctionNoProto: + case LValueReference: + case RValueReference: + case Record: + return true; + default: + return false; + } +} + +bool Type::isClassType() const { + if (const RecordType *RT = getAsRecordType()) + return RT->getDecl()->isClass(); + return false; +} +bool Type::isStructureType() const { + if (const RecordType *RT = getAsRecordType()) + return RT->getDecl()->isStruct(); + return false; +} +bool Type::isUnionType() const { + if (const RecordType *RT = getAsRecordType()) + return RT->getDecl()->isUnion(); + return false; +} + +bool Type::isComplexType() const { + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isFloatingType(); + if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) + return AS->getBaseType()->isComplexType(); + return false; +} + +bool Type::isComplexIntegerType() const { + // Check for GCC complex integer extension. + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isIntegerType(); + if (const ExtQualType *AS = dyn_cast<ExtQualType>(CanonicalType)) + return AS->getBaseType()->isComplexIntegerType(); + 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; + return 0; + } + + // If the canonical form of this type isn't what we want, reject it. + if (!isa<ComplexType>(CanonicalType)) { + // Look through type qualifiers (e.g. ExtQualType's). + if (isa<ComplexType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsComplexIntegerType(); + return 0; + } + + // If this is a typedef for a complex type, strip the typedef off without + // losing all typedef information. + return cast<ComplexType>(getDesugaredType()); +} + +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 (e.g. ExtQualType's). + 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 cast<BuiltinType>(getDesugaredType()); +} + +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 cast<FunctionType>(getDesugaredType()); +} + +const FunctionNoProtoType *Type::getAsFunctionNoProtoType() const { + return dyn_cast_or_null<FunctionNoProtoType>(getAsFunctionType()); +} + +const FunctionProtoType *Type::getAsFunctionProtoType() const { + return dyn_cast_or_null<FunctionProtoType>(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 cast<PointerType>(getDesugaredType()); +} + +const BlockPointerType *Type::getAsBlockPointerType() const { + // If this is directly a block pointer type, return it. + if (const BlockPointerType *PTy = dyn_cast<BlockPointerType>(this)) + return PTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<BlockPointerType>(CanonicalType)) { + // Look through type qualifiers + if (isa<BlockPointerType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsBlockPointerType(); + return 0; + } + + // If this is a typedef for a block pointer type, strip the typedef off + // without losing all typedef information. + return cast<BlockPointerType>(getDesugaredType()); +} + +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 cast<ReferenceType>(getDesugaredType()); +} + +const LValueReferenceType *Type::getAsLValueReferenceType() const { + // If this is directly an lvalue reference type, return it. + if (const LValueReferenceType *RTy = dyn_cast<LValueReferenceType>(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<LValueReferenceType>(CanonicalType)) { + // Look through type qualifiers + if (isa<LValueReferenceType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsLValueReferenceType(); + return 0; + } + + // If this is a typedef for an lvalue reference type, strip the typedef off + // without losing all typedef information. + return cast<LValueReferenceType>(getDesugaredType()); +} + +const RValueReferenceType *Type::getAsRValueReferenceType() const { + // If this is directly an rvalue reference type, return it. + if (const RValueReferenceType *RTy = dyn_cast<RValueReferenceType>(this)) + return RTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<RValueReferenceType>(CanonicalType)) { + // Look through type qualifiers + if (isa<RValueReferenceType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsRValueReferenceType(); + return 0; + } + + // If this is a typedef for an rvalue reference type, strip the typedef off + // without losing all typedef information. + return cast<RValueReferenceType>(getDesugaredType()); +} + +const MemberPointerType *Type::getAsMemberPointerType() const { + // If this is directly a member pointer type, return it. + if (const MemberPointerType *MTy = dyn_cast<MemberPointerType>(this)) + return MTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<MemberPointerType>(CanonicalType)) { + // Look through type qualifiers + if (isa<MemberPointerType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsMemberPointerType(); + return 0; + } + + // If this is a typedef for a member pointer type, strip the typedef off + // without losing all typedef information. + return cast<MemberPointerType>(getDesugaredType()); +} + +/// 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 variably modified type. + if (isVariableArrayType()) + return true; + + // An array can contain a variably modified type + if (const Type *T = getArrayElementTypeNoTypeQual()) + return T->isVariablyModifiedType(); + + // A pointer can point to a variably modified type. + // Also, C++ references and member pointers can point to a variably modified + // type, where VLAs appear as an extension to C++, and should be treated + // correctly. + if (const PointerType *PT = getAsPointerType()) + return PT->getPointeeType()->isVariablyModifiedType(); + if (const ReferenceType *RT = getAsReferenceType()) + return RT->getPointeeType()->isVariablyModifiedType(); + if (const MemberPointerType *PT = getAsMemberPointerType()) + 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; +} + +const RecordType *Type::getAsRecordType() const { + // If this is directly a record 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 cast<RecordType>(getDesugaredType()); +} + +const TagType *Type::getAsTagType() const { + // If this is directly a tag type, return it. + if (const TagType *TagTy = dyn_cast<TagType>(this)) + return TagTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<TagType>(CanonicalType)) { + // Look through type qualifiers + if (isa<TagType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsTagType(); + return 0; + } + + // If this is a typedef for a tag type, strip the typedef off without + // losing all typedef information. + return cast<TagType>(getDesugaredType()); +} + +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()->isStruct()) + 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()->isStruct()) + return 0; + + // If this is a typedef for a structure type, strip the typedef off without + // losing all typedef information. + return cast<RecordType>(getDesugaredType()); + } + // 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()->isUnion()) + 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()->isUnion()) + return 0; + + // If this is a typedef for a union type, strip the typedef off without + // losing all typedef information. + return cast<RecordType>(getDesugaredType()); + } + + // Look through type qualifiers + if (isa<RecordType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsUnionType(); + return 0; +} + +const EnumType *Type::getAsEnumType() const { + // Check the canonicalized unqualified type directly; the more complex + // version is unnecessary because there isn't any typedef information + // to preserve. + return dyn_cast<EnumType>(CanonicalType.getUnqualifiedType()); +} + +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 cast<ComplexType>(getDesugaredType()); +} + +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 cast<VectorType>(getDesugaredType()); +} + +const ExtVectorType *Type::getAsExtVectorType() const { + // Are we directly an OpenCU vector type? + if (const ExtVectorType *VTy = dyn_cast<ExtVectorType>(this)) + return VTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa<ExtVectorType>(CanonicalType)) { + // Look through type qualifiers + if (isa<ExtVectorType>(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsExtVectorType(); + return 0; + } + + // If this is a typedef for an extended vector type, strip the typedef off + // without losing all typedef information. + return cast<ExtVectorType>(getDesugaredType()); +} + +const ObjCInterfaceType *Type::getAsObjCInterfaceType() const { + // There is no sugar for ObjCInterfaceType's, just return the canonical + // type pointer if it is the right class. There is no typedef information to + // return and these cannot be Address-space qualified. + return dyn_cast<ObjCInterfaceType>(CanonicalType.getUnqualifiedType()); +} + +const ObjCQualifiedInterfaceType * +Type::getAsObjCQualifiedInterfaceType() const { + // There is no sugar for ObjCQualifiedInterfaceType's, just return the + // canonical type pointer if it is the right class. + return dyn_cast<ObjCQualifiedInterfaceType>(CanonicalType.getUnqualifiedType()); +} + +const ObjCQualifiedIdType *Type::getAsObjCQualifiedIdType() const { + // There is no sugar for ObjCQualifiedIdType's, just return the canonical + // type pointer if it is the right class. + return dyn_cast<ObjCQualifiedIdType>(CanonicalType.getUnqualifiedType()); +} + +const TemplateTypeParmType *Type::getAsTemplateTypeParmType() const { + // There is no sugar for template type parameters, so just return + // the canonical type pointer if it is the right class. + // FIXME: can these be address-space qualified? + return dyn_cast<TemplateTypeParmType>(CanonicalType); +} + +const TemplateSpecializationType * +Type::getAsTemplateSpecializationType() const { + // There is no sugar for class template specialization types, so + // just return the canonical type pointer if it is the right class. + return dyn_cast<TemplateSpecializationType>(CanonicalType); +} + +bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) + return true; + if (isa<FixedWidthIntType>(CanonicalType)) + return true; + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isIntegerType(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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()->isEnum() && TT->getDecl()->isDefinition()) + return true; // Complete enum types are integral. + // FIXME: In C++, enum types are never integral. + if (isa<FixedWidthIntType>(CanonicalType)) + return true; + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isIntegralType(); + return false; +} + +bool Type::isEnumeralType() const { + if (const TagType *TT = dyn_cast<TagType>(CanonicalType)) + return TT->getDecl()->isEnum(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isEnumeralType(); + return false; +} + +bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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 ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isCharType(); + return false; +} + +bool Type::isWideCharType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::WChar; + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isWideCharType(); + 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 EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + + if (const FixedWidthIntType *FWIT = + dyn_cast<FixedWidthIntType>(CanonicalType)) + return FWIT->isSigned(); + + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isSignedIntegerType(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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 EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + + if (const FixedWidthIntType *FWIT = + dyn_cast<FixedWidthIntType>(CanonicalType)) + return !FWIT->isSigned(); + + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isUnsignedIntegerType(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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 ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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 ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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()->isEnum() && TT->getDecl()->isDefinition(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isRealType(); + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isRealType(); + return false; +} + +bool Type::isArithmeticType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::LongDouble; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + // 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 ET->getDecl()->isDefinition(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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)) { + // Enums are scalar types, but only if they are defined. Incomplete enums + // are not treated as scalar types. + if (TT->getDecl()->isEnum() && TT->getDecl()->isDefinition()) + return true; + return false; + } + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isScalarType(); + if (isa<FixedWidthIntType>(CanonicalType)) + return true; + return isa<PointerType>(CanonicalType) || + isa<BlockPointerType>(CanonicalType) || + isa<MemberPointerType>(CanonicalType) || + isa<ComplexType>(CanonicalType) || + isa<ObjCQualifiedIdType>(CanonicalType); +} + +/// \brief Determines whether the type is a C++ aggregate type or C +/// aggregate or union type. +/// +/// An aggregate type is an array or a class type (struct, union, or +/// class) that has no user-declared constructors, no private or +/// protected non-static data members, no base classes, and no virtual +/// functions (C++ [dcl.init.aggr]p1). The notion of an aggregate type +/// subsumes the notion of C aggregates (C99 6.2.5p21) because it also +/// includes union types. +bool Type::isAggregateType() const { + if (const RecordType *Record = dyn_cast<RecordType>(CanonicalType)) { + if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(Record->getDecl())) + return ClassDecl->isAggregate(); + + return true; + } + + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->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 or dependent types. +bool Type::isConstantSizeType() const { + if (const ExtQualType *EXTQT = dyn_cast<ExtQualType>(CanonicalType)) + return EXTQT->getBaseType()->isConstantSizeType(); + assert(!isIncompleteType() && "This doesn't make sense for incomplete types"); + assert(!isDependentType() && "This doesn't make sense for dependent 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 ExtQual: + return cast<ExtQualType>(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 Record: + case Enum: + // 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; + case ObjCInterface: + case ObjCQualifiedInterface: + // ObjC interfaces are incomplete if they are @class, not @interface. + return cast<ObjCInterfaceType>(this)->getDecl()->isForwardDecl(); + } +} + +/// isPODType - Return true if this is a plain-old-data type (C++ 3.9p10) +bool Type::isPODType() const { + // The compiler shouldn't query this for incomplete types, but the user might. + // We return false for that case. + if (isIncompleteType()) + return false; + + switch (CanonicalType->getTypeClass()) { + // Everything not explicitly mentioned is not POD. + default: return false; + case ExtQual: + return cast<ExtQualType>(CanonicalType)->getBaseType()->isPODType(); + case VariableArray: + case ConstantArray: + // IncompleteArray is caught by isIncompleteType() above. + return cast<ArrayType>(CanonicalType)->getElementType()->isPODType(); + + case Builtin: + case Complex: + case Pointer: + case MemberPointer: + case Vector: + case ExtVector: + case ObjCQualifiedId: + return true; + + case Enum: + return true; + + case Record: + if (CXXRecordDecl *ClassDecl + = dyn_cast<CXXRecordDecl>(cast<RecordType>(CanonicalType)->getDecl())) + return ClassDecl->isPOD(); + + // C struct/union is POD. + return true; + } +} + +bool Type::isPromotableIntegerType() const { + if (const BuiltinType *BT = getAsBuiltinType()) + 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; + } + return false; +} + +bool Type::isNullPtrType() const { + if (const BuiltinType *BT = getAsBuiltinType()) + return BT->getKind() == BuiltinType::NullPtr; + return false; +} + +bool Type::isSpecifierType() const { + // Note that this intentionally does not use the canonical type. + switch (getTypeClass()) { + case Builtin: + case Record: + case Enum: + case Typedef: + case Complex: + case TypeOfExpr: + case TypeOf: + case TemplateTypeParm: + case TemplateSpecialization: + case QualifiedName: + case Typename: + case ObjCInterface: + case ObjCQualifiedInterface: + case ObjCQualifiedId: + return true; + default: + return false; + } +} + +const char *BuiltinType::getName(bool CPlusPlus) const { + switch (getKind()) { + default: assert(0 && "Unknown builtin type!"); + case Void: return "void"; + case Bool: return CPlusPlus? "bool" : "_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 Int128: return "__int128_t"; + 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 UInt128: return "__uint128_t"; + case Float: return "float"; + case Double: return "double"; + case LongDouble: return "long double"; + case WChar: return "wchar_t"; + case NullPtr: return "nullptr_t"; + case Overload: return "<overloaded function type>"; + case Dependent: return "<dependent type>"; + } +} + +void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, + arg_type_iterator ArgTys, + unsigned NumArgs, bool isVariadic, + unsigned TypeQuals, bool hasExceptionSpec, + bool anyExceptionSpec, unsigned NumExceptions, + exception_iterator Exs) { + ID.AddPointer(Result.getAsOpaquePtr()); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i].getAsOpaquePtr()); + ID.AddInteger(isVariadic); + ID.AddInteger(TypeQuals); + ID.AddInteger(hasExceptionSpec); + if (hasExceptionSpec) { + ID.AddInteger(anyExceptionSpec); + for(unsigned i = 0; i != NumExceptions; ++i) + ID.AddPointer(Exs[i].getAsOpaquePtr()); + } +} + +void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getResultType(), arg_type_begin(), NumArgs, isVariadic(), + getTypeQuals(), hasExceptionSpec(), hasAnyExceptionSpec(), + getNumExceptions(), exception_begin()); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID, + const ObjCInterfaceDecl *Decl, + ObjCProtocolDecl **protocols, + unsigned NumProtocols) { + ID.AddPointer(Decl); + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(protocols[i]); +} + +void ObjCQualifiedInterfaceType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getDecl(), &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 ExtQuals! + /// FIXME: + TypeQuals |= CurType.getCVRQualifiers(); + + TDT = dyn_cast<TypedefType>(CurType); + if (TDT == 0) + return QualType(CurType.getTypePtr(), TypeQuals); + } +} + +TypeOfExprType::TypeOfExprType(Expr *E, QualType can) + : Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) { + assert(!isa<TypedefType>(can) && "Invalid canonical type"); +} + +TagType::TagType(TypeClass TC, TagDecl *D, QualType can) + : Type(TC, can, D->isDependentType()), decl(D, 0) {} + +bool RecordType::classof(const TagType *TT) { + return isa<RecordDecl>(TT->getDecl()); +} + +bool EnumType::classof(const TagType *TT) { + return isa<EnumDecl>(TT->getDecl()); +} + +bool +TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { + switch (Args[Idx].getKind()) { + case TemplateArgument::Type: + if (Args[Idx].getAsType()->isDependentType()) + return true; + break; + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // Never dependent + break; + + case TemplateArgument::Expression: + if (Args[Idx].getAsExpr()->isTypeDependent() || + Args[Idx].getAsExpr()->isValueDependent()) + return true; + break; + } + } + + return false; +} + +TemplateSpecializationType:: +TemplateSpecializationType(TemplateName T, const TemplateArgument *Args, + unsigned NumArgs, QualType Canon) + : Type(TemplateSpecialization, + Canon.isNull()? QualType(this, 0) : Canon, + T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)), + Template(T), NumArgs(NumArgs) +{ + assert((!Canon.isNull() || + T.isDependent() || anyDependentTemplateArguments(Args, NumArgs)) && + "No canonical type for non-dependent class template specialization"); + + TemplateArgument *TemplateArgs + = reinterpret_cast<TemplateArgument *>(this + 1); + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) + new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); +} + +void TemplateSpecializationType::Destroy(ASTContext& C) { + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + // FIXME: Not all expressions get cloned, so we can't yet perform + // this destruction. + // if (Expr *E = getArg(Arg).getAsExpr()) + // E->Destroy(C); + } +} + +TemplateSpecializationType::iterator +TemplateSpecializationType::end() const { + return begin() + getNumArgs(); +} + +const TemplateArgument & +TemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; +} + +void +TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs) { + T.Profile(ID); + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + Args[Idx].Profile(ID); +} + +//===----------------------------------------------------------------------===// +// Type Printing +//===----------------------------------------------------------------------===// + +void QualType::dump(const char *msg) const { + PrintingPolicy Policy; + std::string R = "identifier"; + getAsStringInternal(R, Policy); + if (msg) + fprintf(stderr, "%s: %s\n", msg, R.c_str()); + else + fprintf(stderr, "%s\n", R.c_str()); +} +void QualType::dump() const { + dump(""); +} + +void Type::dump() const { + std::string S = "identifier"; + getAsStringInternal(S, PrintingPolicy()); + fprintf(stderr, "%s\n", S.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; +} + +std::string QualType::getAsString() const { + std::string S; + getAsStringInternal(S, PrintingPolicy()); + return S; +} + +void +QualType::getAsStringInternal(std::string &S, + const PrintingPolicy &Policy) const { + if (isNull()) { + S += "NULL TYPE"; + return; + } + + if (Policy.SuppressSpecifiers && getTypePtr()->isSpecifierType()) + 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, Policy); +} + +void BuiltinType::getAsStringInternal(std::string &S, + const PrintingPolicy &Policy) const { + if (S.empty()) { + S = getName(Policy.CPlusPlus); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = getName(Policy.CPlusPlus) + S; + } +} + +void FixedWidthIntType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + // FIXME: Once we get bitwidth attribute, write as + // "int __attribute__((bitwidth(x)))". + std::string prefix = "__clang_fixedwidth"; + prefix += llvm::utostr_32(Width); + prefix += (char)(Signed ? 'S' : 'U'); + if (S.empty()) { + S = prefix; + } else { + // Prefix the basic type, e.g. 'int X'. + S = prefix + S; + } +} + + +void ComplexType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + ElementType->getAsStringInternal(S, Policy); + S = "_Complex " + S; +} + +void ExtQualType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + bool NeedsSpace = false; + if (AddressSpace) { + S = "__attribute__((address_space("+llvm::utostr_32(AddressSpace)+")))" + S; + NeedsSpace = true; + } + if (GCAttrType != QualType::GCNone) { + if (NeedsSpace) + S += ' '; + S += "__attribute__((objc_gc("; + if (GCAttrType == QualType::Weak) + S += "weak"; + else + S += "strong"; + S += ")))"; + } + BaseType->getAsStringInternal(S, Policy); +} + +void PointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(getPointeeType())) + S = '(' + S + ')'; + + getPointeeType().getAsStringInternal(S, Policy); +} + +void BlockPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S = '^' + S; + PointeeType.getAsStringInternal(S, Policy); +} + +void LValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(getPointeeType())) + S = '(' + S + ')'; + + getPointeeType().getAsStringInternal(S, Policy); +} + +void RValueReferenceType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S = "&&" + S; + + // Handle things like 'int (&&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(getPointeeType())) + S = '(' + S + ')'; + + getPointeeType().getAsStringInternal(S, Policy); +} + +void MemberPointerType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + std::string C; + Class->getAsStringInternal(C, Policy); + C += "::*"; + S = C + S; + + // Handle things like 'int (Cls::*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(getPointeeType())) + S = '(' + S + ')'; + + getPointeeType().getAsStringInternal(S, Policy); +} + +void ConstantArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S += '['; + S += llvm::utostr(getSize().getZExtValue()); + S += ']'; + + getElementType().getAsStringInternal(S, Policy); +} + +void IncompleteArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S += "[]"; + + getElementType().getAsStringInternal(S, Policy); +} + +void VariableArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S += '['; + + if (getIndexTypeQualifier()) { + AppendTypeQualList(S, getIndexTypeQualifier()); + S += ' '; + } + + if (getSizeModifier() == Static) + S += "static"; + else if (getSizeModifier() == Star) + S += '*'; + + if (getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + getElementType().getAsStringInternal(S, Policy); +} + +void DependentSizedArrayType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S += '['; + + if (getIndexTypeQualifier()) { + AppendTypeQualList(S, getIndexTypeQualifier()); + S += ' '; + } + + if (getSizeModifier() == Static) + S += "static"; + else if (getSizeModifier() == Star) + S += '*'; + + if (getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + getElementType().getAsStringInternal(S, Policy); +} + +void VectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + S += " __attribute__((__vector_size__("; + S += llvm::utostr_32(NumElements); // convert back to bytes. + S += " * sizeof(" + ElementType.getAsString() + "))))"; + ElementType.getAsStringInternal(S, Policy); +} + +void ExtVectorType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + S += " __attribute__((ext_vector_type("; + S += llvm::utostr_32(NumElements); + S += ")))"; + ElementType.getAsStringInternal(S, Policy); +} + +void TypeOfExprType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. + InnerString = ' ' + InnerString; + std::string Str; + llvm::raw_string_ostream s(Str); + getUnderlyingExpr()->printPretty(s, 0, Policy); + InnerString = "typeof " + s.str() + InnerString; +} + +void TypeOfType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. + InnerString = ' ' + InnerString; + std::string Tmp; + getUnderlyingType().getAsStringInternal(Tmp, Policy); + InnerString = "typeof(" + Tmp + ")" + InnerString; +} + +void FunctionNoProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + getResultType().getAsStringInternal(S, Policy); +} + +void FunctionProtoType::getAsStringInternal(std::string &S, const PrintingPolicy &Policy) const { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "("; + std::string Tmp; + PrintingPolicy ParamPolicy(Policy); + ParamPolicy.SuppressSpecifiers = false; + for (unsigned i = 0, e = getNumArgs(); i != e; ++i) { + if (i) S += ", "; + getArgType(i).getAsStringInternal(Tmp, ParamPolicy); + 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, Policy); +} + + +void TypedefType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + InnerString = getDecl()->getIdentifier()->getName() + InnerString; +} + +void TemplateTypeParmType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'parmname X'. + InnerString = ' ' + InnerString; + + if (!Name) + InnerString = "type-parameter-" + llvm::utostr_32(Depth) + '-' + + llvm::utostr_32(Index) + InnerString; + else + InnerString = Name->getName() + InnerString; +} + +std::string +TemplateSpecializationType::PrintTemplateArgumentList( + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (Arg) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + switch (Args[Arg].getKind()) { + case TemplateArgument::Type: + Args[Arg].getAsType().getAsStringInternal(ArgString, Policy); + break; + + case TemplateArgument::Declaration: + ArgString = cast<NamedDecl>(Args[Arg].getAsDecl())->getNameAsString(); + break; + + case TemplateArgument::Integral: + ArgString = Args[Arg].getAsIntegral()->toString(10, true); + break; + + case TemplateArgument::Expression: { + llvm::raw_string_ostream s(ArgString); + Args[Arg].getAsExpr()->printPretty(s, 0, Policy); + break; + } + } + + // If this is the first argument and its string representation + // begins with the global scope specifier ('::foo'), add a space + // to avoid printing the diagraph '<:'. + if (!Arg && !ArgString.empty() && ArgString[0] == ':') + SpecString += ' '; + + SpecString += ArgString; + } + + // If the last character of our string is '>', add another space to + // keep the two '>''s separate tokens. We don't *have* to do this in + // C++0x, but it's still good hygiene. + if (SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + SpecString += '>'; + + return SpecString; +} + +void +TemplateSpecializationType:: +getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + std::string SpecString; + + { + llvm::raw_string_ostream OS(SpecString); + Template.print(OS, Policy); + } + + SpecString += PrintTemplateArgumentList(getArgs(), getNumArgs(), Policy); + if (InnerString.empty()) + InnerString.swap(SpecString); + else + InnerString = SpecString + ' ' + InnerString; +} + +void QualifiedNameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + NNS->print(OS, Policy); + } + + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKind = true; + NamedType.getAsStringInternal(TypeStr, InnerPolicy); + + MyString += TypeStr; + if (InnerString.empty()) + InnerString.swap(MyString); + else + InnerString = MyString + ' ' + InnerString; +} + +void TypenameType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + OS << "typename "; + NNS->print(OS, Policy); + + if (const IdentifierInfo *Ident = getIdentifier()) + OS << Ident->getName(); + else if (const TemplateSpecializationType *Spec = getTemplateId()) { + Spec->getTemplateName().print(OS, Policy, true); + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Spec->getArgs(), + Spec->getNumArgs(), + Policy); + } + } + + if (InnerString.empty()) + InnerString.swap(MyString); + else + InnerString = MyString + ' ' + InnerString; +} + +void ObjCInterfaceType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) 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 PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = getDecl()->getNameAsString(); + ObjCQIString += '<'; + bool isFirst = true; + for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { + if (isFirst) + isFirst = false; + else + ObjCQIString += ','; + ObjCQIString += (*I)->getNameAsString(); + } + ObjCQIString += '>'; + InnerString = ObjCQIString + InnerString; +} + +void ObjCQualifiedIdType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + std::string ObjCQIString = "id"; + ObjCQIString += '<'; + for (qual_iterator I = qual_begin(), E = qual_end(); I != E; ++I) { + ObjCQIString += (*I)->getNameAsString(); + if (I+1 != E) + ObjCQIString += ','; + } + ObjCQIString += '>'; + InnerString = ObjCQIString + InnerString; +} + +void TagType::getAsStringInternal(std::string &InnerString, const PrintingPolicy &Policy) const { + if (Policy.SuppressTag) + return; + + if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'. + InnerString = ' ' + InnerString; + + const char *Kind = Policy.SuppressTagKind? 0 : getDecl()->getKindName(); + const char *ID; + if (const IdentifierInfo *II = getDecl()->getIdentifier()) + ID = II->getName(); + else if (TypedefDecl *Typedef = getDecl()->getTypedefForAnonDecl()) { + Kind = 0; + assert(Typedef->getIdentifier() && "Typedef without identifier?"); + ID = Typedef->getIdentifier()->getName(); + } else + ID = "<anonymous>"; + + // If this is a class template specialization, print the template + // arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(getDecl())) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + InnerString = TemplateArgsStr + InnerString; + } + + if (Kind) { + // Compute the full nested-name-specifier for this type. In C, + // this will always be empty. + std::string ContextStr; + for (DeclContext *DC = getDecl()->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + std::string MyPart; + if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { + if (NS->getIdentifier()) + MyPart = NS->getNameAsString(); + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.getFlatArgumentList(), + TemplateArgs.flat_size(), + Policy); + MyPart = Spec->getIdentifier()->getName() + TemplateArgsStr; + } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + if (TypedefDecl *Typedef = Tag->getTypedefForAnonDecl()) + MyPart = Typedef->getIdentifier()->getName(); + else if (Tag->getIdentifier()) + MyPart = Tag->getIdentifier()->getName(); + } + + if (!MyPart.empty()) + ContextStr = MyPart + "::" + ContextStr; + } + + InnerString = std::string(Kind) + " " + ContextStr + ID + InnerString; + } else + InnerString = ID + InnerString; +} |