summaryrefslogtreecommitdiffstats
path: root/lib/AST
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST')
-rw-r--r--lib/AST/APValue.cpp108
-rw-r--r--lib/AST/ASTConsumer.cpp19
-rw-r--r--lib/AST/ASTContext.cpp3332
-rw-r--r--lib/AST/Builtins.cpp290
-rw-r--r--lib/AST/CFG.cpp1913
-rw-r--r--lib/AST/CMakeLists.txt32
-rw-r--r--lib/AST/Decl.cpp630
-rw-r--r--lib/AST/DeclBase.cpp756
-rw-r--r--lib/AST/DeclCXX.cpp462
-rw-r--r--lib/AST/DeclGroup.cpp37
-rw-r--r--lib/AST/DeclObjC.cpp693
-rw-r--r--lib/AST/DeclPrinter.cpp722
-rw-r--r--lib/AST/DeclTemplate.cpp324
-rw-r--r--lib/AST/DeclarationName.cpp355
-rw-r--r--lib/AST/Expr.cpp2059
-rw-r--r--lib/AST/ExprCXX.cpp424
-rw-r--r--lib/AST/ExprConstant.cpp1723
-rw-r--r--lib/AST/InheritViz.cpp168
-rw-r--r--lib/AST/Makefile22
-rw-r--r--lib/AST/NestedNameSpecifier.cpp160
-rw-r--r--lib/AST/ParentMap.cpp94
-rw-r--r--lib/AST/Stmt.cpp587
-rw-r--r--lib/AST/StmtDumper.cpp542
-rw-r--r--lib/AST/StmtIterator.cpp155
-rw-r--r--lib/AST/StmtPrinter.cpp1239
-rw-r--r--lib/AST/StmtViz.cpp61
-rw-r--r--lib/AST/TemplateName.cpp65
-rw-r--r--lib/AST/Type.cpp1658
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;
+}
OpenPOWER on IntegriCloud