diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST')
44 files changed, 45802 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/APValue.cpp b/contrib/llvm/tools/clang/lib/AST/APValue.cpp new file mode 100644 index 000000000000..ebe99b12cdab --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/APValue.cpp @@ -0,0 +1,142 @@ +//===--- 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 "clang/AST/CharUnits.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + struct LV { + const Expr* Base; + CharUnits Offset; + }; +} + +APValue::APValue(const Expr* B) : Kind(Uninitialized) { + MakeLValue(); setLValue(B, CharUnits::Zero()); +} + +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(((const Vec *)(const char *)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*)(char*)Data)->~APSInt(); + else if (Kind == Float) + ((APFloat*)(char*)Data)->~APFloat(); + else if (Kind == Vector) + ((Vec*)(char*)Data)->~Vec(); + else if (Kind == ComplexInt) + ((ComplexAPSInt*)(char*)Data)->~ComplexAPSInt(); + else if (Kind == ComplexFloat) + ((ComplexAPFloat*)(char*)Data)->~ComplexAPFloat(); + else if (Kind == LValue) { + ((LV*)(char*)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; + } +} + +const Expr* APValue::getLValueBase() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Base; +} + +CharUnits APValue::getLValueOffset() const { + assert(isLValue() && "Invalid accessor"); + return ((const LV*)(const void*)Data)->Offset; +} + +void APValue::setLValue(const Expr *B, const CharUnits &O) { + assert(isLValue() && "Invalid accessor"); + ((LV*)(char*)Data)->Base = B; + ((LV*)(char*)Data)->Offset = O; +} + +void APValue::MakeLValue() { + assert(isUninit() && "Bad state change"); + new ((void*)(char*)Data) LV(); + Kind = LValue; +} + diff --git a/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp b/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp new file mode 100644 index 000000000000..04a084a06a44 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTConsumer.cpp @@ -0,0 +1,22 @@ +//===--- 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) {} + +void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) { + HandleTopLevelDecl(D); +} diff --git a/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp new file mode 100644 index 000000000000..9094abad2ef1 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTContext.cpp @@ -0,0 +1,6404 @@ +//===--- 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/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Mangle.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "CXXABI.h" +#include <map> + +using namespace clang; + +unsigned ASTContext::NumImplicitDefaultConstructors; +unsigned ASTContext::NumImplicitDefaultConstructorsDeclared; +unsigned ASTContext::NumImplicitCopyConstructors; +unsigned ASTContext::NumImplicitCopyConstructorsDeclared; +unsigned ASTContext::NumImplicitMoveConstructors; +unsigned ASTContext::NumImplicitMoveConstructorsDeclared; +unsigned ASTContext::NumImplicitCopyAssignmentOperators; +unsigned ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; +unsigned ASTContext::NumImplicitMoveAssignmentOperators; +unsigned ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; +unsigned ASTContext::NumImplicitDestructors; +unsigned ASTContext::NumImplicitDestructorsDeclared; + +enum FloatingRank { + FloatRank, DoubleRank, LongDoubleRank +}; + +void +ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, + TemplateTemplateParmDecl *Parm) { + ID.AddInteger(Parm->getDepth()); + ID.AddInteger(Parm->getPosition()); + ID.AddBoolean(Parm->isParameterPack()); + + TemplateParameterList *Params = Parm->getTemplateParameters(); + ID.AddInteger(Params->size()); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + ID.AddInteger(0); + ID.AddBoolean(TTP->isParameterPack()); + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + ID.AddInteger(1); + ID.AddBoolean(NTTP->isParameterPack()); + ID.AddPointer(NTTP->getType().getAsOpaquePtr()); + if (NTTP->isExpandedParameterPack()) { + ID.AddBoolean(true); + ID.AddInteger(NTTP->getNumExpansionTypes()); + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) + ID.AddPointer(NTTP->getExpansionType(I).getAsOpaquePtr()); + } else + ID.AddBoolean(false); + continue; + } + + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P); + ID.AddInteger(2); + Profile(ID, TTP); + } +} + +TemplateTemplateParmDecl * +ASTContext::getCanonicalTemplateTemplateParmDecl( + TemplateTemplateParmDecl *TTP) const { + // Check if we already have a canonical template template parameter. + llvm::FoldingSetNodeID ID; + CanonicalTemplateTemplateParm::Profile(ID, TTP); + void *InsertPos = 0; + CanonicalTemplateTemplateParm *Canonical + = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); + if (Canonical) + return Canonical->getParam(); + + // Build a canonical template parameter list. + TemplateParameterList *Params = TTP->getTemplateParameters(); + llvm::SmallVector<NamedDecl *, 4> CanonParams; + CanonParams.reserve(Params->size()); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) + CanonParams.push_back( + TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + TTP->getDepth(), + TTP->getIndex(), 0, false, + TTP->isParameterPack())); + else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + QualType T = getCanonicalType(NTTP->getType()); + TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); + NonTypeTemplateParmDecl *Param; + if (NTTP->isExpandedParameterPack()) { + llvm::SmallVector<QualType, 2> ExpandedTypes; + llvm::SmallVector<TypeSourceInfo *, 2> ExpandedTInfos; + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { + ExpandedTypes.push_back(getCanonicalType(NTTP->getExpansionType(I))); + ExpandedTInfos.push_back( + getTrivialTypeSourceInfo(ExpandedTypes.back())); + } + + Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + NTTP->getDepth(), + NTTP->getPosition(), 0, + T, + TInfo, + ExpandedTypes.data(), + ExpandedTypes.size(), + ExpandedTInfos.data()); + } else { + Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), + SourceLocation(), + NTTP->getDepth(), + NTTP->getPosition(), 0, + T, + NTTP->isParameterPack(), + TInfo); + } + CanonParams.push_back(Param); + + } else + CanonParams.push_back(getCanonicalTemplateTemplateParmDecl( + cast<TemplateTemplateParmDecl>(*P))); + } + + TemplateTemplateParmDecl *CanonTTP + = TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(), + SourceLocation(), TTP->getDepth(), + TTP->getPosition(), + TTP->isParameterPack(), + 0, + TemplateParameterList::Create(*this, SourceLocation(), + SourceLocation(), + CanonParams.data(), + CanonParams.size(), + SourceLocation())); + + // Get the new insert position for the node we care about. + Canonical = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); + assert(Canonical == 0 && "Shouldn't be in the map!"); + (void)Canonical; + + // Create the canonical template template parameter entry. + Canonical = new (*this) CanonicalTemplateTemplateParm(CanonTTP); + CanonTemplateTemplateParms.InsertNode(Canonical, InsertPos); + return CanonTTP; +} + +CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { + if (!LangOpts.CPlusPlus) return 0; + + switch (T.getCXXABI()) { + case CXXABI_ARM: + return CreateARMCXXABI(*this); + case CXXABI_Itanium: + return CreateItaniumCXXABI(*this); + case CXXABI_Microsoft: + return CreateMicrosoftCXXABI(*this); + } + return 0; +} + +static const LangAS::Map &getAddressSpaceMap(const TargetInfo &T, + const LangOptions &LOpts) { + if (LOpts.FakeAddressSpaceMap) { + // The fake address space map must have a distinct entry for each + // language-specific address space. + static const unsigned FakeAddrSpaceMap[] = { + 1, // opencl_global + 2, // opencl_local + 3 // opencl_constant + }; + return FakeAddrSpaceMap; + } else { + return T.getAddressSpaceMap(); + } +} + +ASTContext::ASTContext(const LangOptions& LOpts, SourceManager &SM, + const TargetInfo &t, + IdentifierTable &idents, SelectorTable &sels, + Builtin::Context &builtins, + unsigned size_reserve) : + FunctionProtoTypes(this_()), + TemplateSpecializationTypes(this_()), + DependentTemplateSpecializationTypes(this_()), + GlobalNestedNameSpecifier(0), IsInt128Installed(false), + CFConstantStringTypeDecl(0), NSConstantStringTypeDecl(0), + ObjCFastEnumerationStateTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), + sigjmp_bufDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), + cudaConfigureCallDecl(0), + NullTypeSourceInfo(QualType()), + SourceMgr(SM), LangOpts(LOpts), ABI(createCXXABI(t)), + AddrSpaceMap(getAddressSpaceMap(t, LOpts)), Target(t), + Idents(idents), Selectors(sels), + BuiltinInfo(builtins), + DeclarationNames(*this), + ExternalSource(0), Listener(0), PrintingPolicy(LOpts), + LastSDM(0, 0), + UniqueBlockByRefTypeID(0) { + ObjCIdRedefinitionType = QualType(); + ObjCClassRedefinitionType = QualType(); + ObjCSelRedefinitionType = QualType(); + if (size_reserve > 0) Types.reserve(size_reserve); + TUDecl = TranslationUnitDecl::Create(*this); + InitBuiltinTypes(); +} + +ASTContext::~ASTContext() { + // Release the DenseMaps associated with DeclContext objects. + // FIXME: Is this the ideal solution? + ReleaseDeclContextMaps(); + + // Call all of the deallocation functions. + for (unsigned I = 0, N = Deallocations.size(); I != N; ++I) + Deallocations[I].first(Deallocations[I].second); + + // Release all of the memory associated with overridden C++ methods. + for (llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::iterator + OM = OverriddenMethods.begin(), OMEnd = OverriddenMethods.end(); + OM != OMEnd; ++OM) + OM->second.Destroy(); + + // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed + // because they can contain DenseMaps. + for (llvm::DenseMap<const ObjCContainerDecl*, + const ASTRecordLayout*>::iterator + I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) + // Increment in loop to prevent using deallocated memory. + if (ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second)) + R->Destroy(*this); + + for (llvm::DenseMap<const RecordDecl*, const ASTRecordLayout*>::iterator + I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { + // Increment in loop to prevent using deallocated memory. + if (ASTRecordLayout *R = const_cast<ASTRecordLayout*>((I++)->second)) + R->Destroy(*this); + } + + for (llvm::DenseMap<const Decl*, AttrVec*>::iterator A = DeclAttrs.begin(), + AEnd = DeclAttrs.end(); + A != AEnd; ++A) + A->second->~AttrVec(); +} + +void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { + Deallocations.push_back(std::make_pair(Callback, Data)); +} + +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)); + + // Implicit special member functions. + fprintf(stderr, " %u/%u implicit default constructors created\n", + NumImplicitDefaultConstructorsDeclared, + NumImplicitDefaultConstructors); + fprintf(stderr, " %u/%u implicit copy constructors created\n", + NumImplicitCopyConstructorsDeclared, + NumImplicitCopyConstructors); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move constructors created\n", + NumImplicitMoveConstructorsDeclared, + NumImplicitMoveConstructors); + fprintf(stderr, " %u/%u implicit copy assignment operators created\n", + NumImplicitCopyAssignmentOperatorsDeclared, + NumImplicitCopyAssignmentOperators); + if (getLangOptions().CPlusPlus) + fprintf(stderr, " %u/%u implicit move assignment operators created\n", + NumImplicitMoveAssignmentOperatorsDeclared, + NumImplicitMoveAssignmentOperators); + fprintf(stderr, " %u/%u implicit destructors created\n", + NumImplicitDestructorsDeclared, NumImplicitDestructors); + + if (ExternalSource.get()) { + fprintf(stderr, "\n"); + ExternalSource->PrintStats(); + } + + BumpAlloc.PrintStats(); +} + + +void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { + BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); + R = CanQualType::CreateUnsafe(QualType(Ty, 0)); + Types.push_back(Ty); +} + +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 (LangOpts.CharIsSigned) + 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 + if (TargetInfo::isTypeSigned(Target.getWCharType())) + InitBuiltinType(WCharTy, BuiltinType::WChar_S); + else // -fshort-wchar makes wchar_t be unsigned. + InitBuiltinType(WCharTy, BuiltinType::WChar_U); + } else // C99 + WCharTy = getFromTargetType(Target.getWCharType()); + + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ + InitBuiltinType(Char16Ty, BuiltinType::Char16); + else // C99 + Char16Ty = getFromTargetType(Target.getChar16Type()); + + if (LangOpts.CPlusPlus) // C++0x 3.9.1p5, extension for C++ + InitBuiltinType(Char32Ty, BuiltinType::Char32); + else // C99 + Char32Ty = getFromTargetType(Target.getChar32Type()); + + // 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); + + // Placeholder type for functions. + InitBuiltinType(OverloadTy, BuiltinType::Overload); + + // Placeholder type for bound members. + InitBuiltinType(BoundMemberTy, BuiltinType::BoundMember); + + // "any" type; useful for debugger-like clients. + InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny); + + // C99 6.2.5p11. + FloatComplexTy = getComplexType(FloatTy); + DoubleComplexTy = getComplexType(DoubleTy); + LongDoubleComplexTy = getComplexType(LongDoubleTy); + + BuiltinVaListType = QualType(); + + // "Builtin" typedefs set by Sema::ActOnTranslationUnitScope(). + ObjCIdTypedefType = QualType(); + ObjCClassTypedefType = QualType(); + ObjCSelTypedefType = QualType(); + + // Builtin types for 'id', 'Class', and 'SEL'. + InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); + InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); + InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); + + ObjCConstantStringType = QualType(); + + // void * type + VoidPtrTy = getPointerType(VoidTy); + + // nullptr type (C++0x 2.14.7) + InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); +} + +Diagnostic &ASTContext::getDiagnostics() const { + return SourceMgr.getDiagnostics(); +} + +AttrVec& ASTContext::getDeclAttrs(const Decl *D) { + AttrVec *&Result = DeclAttrs[D]; + if (!Result) { + void *Mem = Allocate(sizeof(AttrVec)); + Result = new (Mem) AttrVec; + } + + return *Result; +} + +/// \brief Erase the attributes corresponding to the given declaration. +void ASTContext::eraseDeclAttrs(const Decl *D) { + llvm::DenseMap<const Decl*, AttrVec*>::iterator Pos = DeclAttrs.find(D); + if (Pos != DeclAttrs.end()) { + Pos->second->~AttrVec(); + DeclAttrs.erase(Pos); + } +} + +MemberSpecializationInfo * +ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { + assert(Var->isStaticDataMember() && "Not a static data member"); + llvm::DenseMap<const VarDecl *, MemberSpecializationInfo *>::iterator Pos + = InstantiatedFromStaticDataMember.find(Var); + if (Pos == InstantiatedFromStaticDataMember.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl, + TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { + assert(Inst->isStaticDataMember() && "Not a static data member"); + assert(Tmpl->isStaticDataMember() && "Not a static data member"); + assert(!InstantiatedFromStaticDataMember[Inst] && + "Already noted what static data member was instantiated from"); + InstantiatedFromStaticDataMember[Inst] + = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation); +} + +NamedDecl * +ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { + llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos + = InstantiatedFromUsingDecl.find(UUD); + if (Pos == InstantiatedFromUsingDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) { + assert((isa<UsingDecl>(Pattern) || + isa<UnresolvedUsingValueDecl>(Pattern) || + isa<UnresolvedUsingTypenameDecl>(Pattern)) && + "pattern decl is not a using decl"); + assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingDecl[Inst] = Pattern; +} + +UsingShadowDecl * +ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { + llvm::DenseMap<UsingShadowDecl*, UsingShadowDecl*>::const_iterator Pos + = InstantiatedFromUsingShadowDecl.find(Inst); + if (Pos == InstantiatedFromUsingShadowDecl.end()) + return 0; + + return Pos->second; +} + +void +ASTContext::setInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst, + UsingShadowDecl *Pattern) { + assert(!InstantiatedFromUsingShadowDecl[Inst] && "pattern already exists"); + InstantiatedFromUsingShadowDecl[Inst] = Pattern; +} + +FieldDecl *ASTContext::getInstantiatedFromUnnamedFieldDecl(FieldDecl *Field) { + llvm::DenseMap<FieldDecl *, FieldDecl *>::iterator Pos + = InstantiatedFromUnnamedFieldDecl.find(Field); + if (Pos == InstantiatedFromUnnamedFieldDecl.end()) + return 0; + + return Pos->second; +} + +void ASTContext::setInstantiatedFromUnnamedFieldDecl(FieldDecl *Inst, + FieldDecl *Tmpl) { + assert(!Inst->getDeclName() && "Instantiated field decl is not unnamed"); + assert(!Tmpl->getDeclName() && "Template field decl is not unnamed"); + assert(!InstantiatedFromUnnamedFieldDecl[Inst] && + "Already noted what unnamed field was instantiated from"); + + InstantiatedFromUnnamedFieldDecl[Inst] = Tmpl; +} + +bool ASTContext::ZeroBitfieldFollowsNonBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && !LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0); + +} + +bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() == 0 && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() != 0); + +} + +bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue() && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); +} + +bool ASTContext::NoneBitfieldFollowsBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (!FD->isBitField() && LastFD && LastFD->isBitField() && + LastFD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); +} + +bool ASTContext::BitfieldFollowsNoneBitfield(const FieldDecl *FD, + const FieldDecl *LastFD) const { + return (FD->isBitField() && LastFD && !LastFD->isBitField() && + FD->getBitWidth()-> EvaluateAsInt(*this).getZExtValue()); +} + +ASTContext::overridden_cxx_method_iterator +ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos + = OverriddenMethods.find(Method); + if (Pos == OverriddenMethods.end()) + return 0; + + return Pos->second.begin(); +} + +ASTContext::overridden_cxx_method_iterator +ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos + = OverriddenMethods.find(Method); + if (Pos == OverriddenMethods.end()) + return 0; + + return Pos->second.end(); +} + +unsigned +ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { + llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos + = OverriddenMethods.find(Method); + if (Pos == OverriddenMethods.end()) + return 0; + + return Pos->second.size(); +} + +void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, + const CXXMethodDecl *Overridden) { + OverriddenMethods[Method].push_back(Overridden); +} + +//===----------------------------------------------------------------------===// +// 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->getAs<BuiltinType>(); + 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. +/// If @p RefAsPointee, references are treated like their underlying type +/// (for alignof), else they're treated like pointers (for CodeGen). +CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { + unsigned Align = Target.getCharWidth(); + + bool UseAlignAttrOnly = false; + if (unsigned AlignFromAttr = D->getMaxAlignment()) { + Align = AlignFromAttr; + + // __attribute__((aligned)) can increase or decrease alignment + // *except* on a struct or struct member, where it only increases + // alignment unless 'packed' is also specified. + // + // It is an error for [[align]] to decrease alignment, so we can + // ignore that possibility; Sema should diagnose it. + if (isa<FieldDecl>(D)) { + UseAlignAttrOnly = D->hasAttr<PackedAttr>() || + cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>(); + } else { + UseAlignAttrOnly = true; + } + } + else if (isa<FieldDecl>(D)) + UseAlignAttrOnly = + D->hasAttr<PackedAttr>() || + cast<FieldDecl>(D)->getParent()->hasAttr<PackedAttr>(); + + // If we're using the align attribute only, just ignore everything + // else about the declaration and its type. + if (UseAlignAttrOnly) { + // do nothing + + } else if (const ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + QualType T = VD->getType(); + if (const ReferenceType* RT = T->getAs<ReferenceType>()) { + if (RefAsPointee) + T = RT->getPointeeType(); + else + T = getPointerType(RT->getPointeeType()); + } + if (!T->isIncompleteType() && !T->isFunctionType()) { + // Adjust alignments of declarations with array type by the + // large-array alignment on the target. + unsigned MinWidth = Target.getLargeArrayMinWidth(); + const ArrayType *arrayType; + if (MinWidth && (arrayType = getAsArrayType(T))) { + if (isa<VariableArrayType>(arrayType)) + Align = std::max(Align, Target.getLargeArrayAlign()); + else if (isa<ConstantArrayType>(arrayType) && + MinWidth <= getTypeSize(cast<ConstantArrayType>(arrayType))) + Align = std::max(Align, Target.getLargeArrayAlign()); + + // Walk through any array types while we're at it. + T = getBaseElementType(arrayType); + } + Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); + } + + // Fields can be subject to extra alignment constraints, like if + // the field is packed, the struct is packed, or the struct has a + // a max-field-alignment constraint (#pragma pack). So calculate + // the actual alignment of the field within the struct, and then + // (as we're expected to) constrain that by the alignment of the type. + if (const FieldDecl *field = dyn_cast<FieldDecl>(VD)) { + // So calculate the alignment of the field. + const ASTRecordLayout &layout = getASTRecordLayout(field->getParent()); + + // Start with the record's overall alignment. + unsigned fieldAlign = toBits(layout.getAlignment()); + + // Use the GCD of that and the offset within the record. + uint64_t offset = layout.getFieldOffset(field->getFieldIndex()); + if (offset > 0) { + // Alignment is always a power of 2, so the GCD will be a power of 2, + // which means we get to do this crazy thing instead of Euclid's. + uint64_t lowBitOfOffset = offset & (~offset + 1); + if (lowBitOfOffset < fieldAlign) + fieldAlign = static_cast<unsigned>(lowBitOfOffset); + } + + Align = std::min(Align, fieldAlign); + } + } + + return toCharUnitsFromBits(Align); +} + +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(const Type *T) const { + std::pair<uint64_t, unsigned> Info = getTypeInfo(T); + return std::make_pair(toCharUnitsFromBits(Info.first), + toCharUnitsFromBits(Info.second)); +} + +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoInChars(QualType T) const { + return getTypeInfoInChars(T.getTypePtr()); +} + +/// getTypeSize - Return the size of the specified type, in bits. This method +/// does not work on incomplete types. +/// +/// FIXME: Pointers into different addr spaces could have different sizes and +/// alignment requirements: getPointerInfo should take an AddrSpace, this +/// should take a QualType, &c. +std::pair<uint64_t, unsigned> +ASTContext::getTypeInfo(const Type *T) const { + 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; + Width = llvm::RoundUpToAlignment(Width, Align); + break; + } + case Type::ExtVector: + case Type::Vector: { + const VectorType *VT = cast<VectorType>(T); + std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(VT->getElementType()); + Width = EltInfo.first*VT->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. + if (Align & (Align-1)) { + Align = llvm::NextPowerOf2(Align); + Width = llvm::RoundUpToAlignment(Width, 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_S: + case BuiltinType::WChar_U: + Width = Target.getWCharWidth(); + Align = Target.getWCharAlign(); + break; + case BuiltinType::Char16: + Width = Target.getChar16Width(); + Align = Target.getChar16Align(); + break; + case BuiltinType::Char32: + Width = Target.getChar32Width(); + Align = Target.getChar32Align(); + 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; + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; + } + break; + case Type::ObjCObjectPointer: + Width = Target.getPointerWidth(0); + Align = Target.getPointerAlign(0); + break; + case Type::BlockPointer: { + unsigned AS = getTargetAddressSpace( + cast<BlockPointerType>(T)->getPointeeType()); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::LValueReference: + case Type::RValueReference: { + // alignof and sizeof should never enter this code path here, so we go + // the pointer route. + unsigned AS = getTargetAddressSpace( + cast<ReferenceType>(T)->getPointeeType()); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::Pointer: { + unsigned AS = getTargetAddressSpace(cast<PointerType>(T)->getPointeeType()); + Width = Target.getPointerWidth(AS); + Align = Target.getPointerAlign(AS); + break; + } + case Type::MemberPointer: { + const MemberPointerType *MPT = cast<MemberPointerType>(T); + std::pair<uint64_t, unsigned> PtrDiffInfo = + getTypeInfo(getPointerDiffType()); + Width = PtrDiffInfo.first * ABI->getMemberPointerSize(MPT); + 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::ObjCObject: + return getTypeInfo(cast<ObjCObjectType>(T)->getBaseType().getTypePtr()); + case Type::ObjCInterface: { + const ObjCInterfaceType *ObjCI = cast<ObjCInterfaceType>(T); + const ASTRecordLayout &Layout = getASTObjCInterfaceLayout(ObjCI->getDecl()); + Width = toBits(Layout.getSize()); + Align = toBits(Layout.getAlignment()); + break; + } + case Type::Record: + case Type::Enum: { + const TagType *TT = cast<TagType>(T); + + if (TT->getDecl()->isInvalidDecl()) { + Width = 8; + Align = 8; + 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 = toBits(Layout.getSize()); + Align = toBits(Layout.getAlignment()); + break; + } + + case Type::SubstTemplateTypeParm: + return getTypeInfo(cast<SubstTemplateTypeParmType>(T)-> + getReplacementType().getTypePtr()); + + case Type::Auto: { + const AutoType *A = cast<AutoType>(T); + assert(A->isDeduced() && "Cannot request the size of a dependent type"); + return getTypeInfo(A->getDeducedType().getTypePtr()); + } + + case Type::Paren: + return getTypeInfo(cast<ParenType>(T)->getInnerType().getTypePtr()); + + case Type::Typedef: { + const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl(); + std::pair<uint64_t, unsigned> Info + = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + // If the typedef has an aligned attribute on it, it overrides any computed + // alignment we have. This violates the GCC documentation (which says that + // attribute(aligned) can only round up) but matches its implementation. + if (unsigned AttrAlign = Typedef->getMaxAlignment()) + Align = AttrAlign; + else + Align = Info.second; + Width = Info.first; + break; + } + + case Type::TypeOfExpr: + return getTypeInfo(cast<TypeOfExprType>(T)->getUnderlyingExpr()->getType() + .getTypePtr()); + + case Type::TypeOf: + return getTypeInfo(cast<TypeOfType>(T)->getUnderlyingType().getTypePtr()); + + case Type::Decltype: + return getTypeInfo(cast<DecltypeType>(T)->getUnderlyingExpr()->getType() + .getTypePtr()); + + case Type::UnaryTransform: + return getTypeInfo(cast<UnaryTransformType>(T)->getUnderlyingType()); + + case Type::Elaborated: + return getTypeInfo(cast<ElaboratedType>(T)->getNamedType().getTypePtr()); + + case Type::Attributed: + return getTypeInfo( + cast<AttributedType>(T)->getEquivalentType().getTypePtr()); + + case Type::TemplateSpecialization: { + assert(getCanonicalType(T) != T && + "Cannot request the size of a dependent type"); + const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); + // A type alias template specialization may refer to a typedef with the + // aligned attribute on it. + if (TST->isTypeAlias()) + return getTypeInfo(TST->getAliasedType().getTypePtr()); + else + return getTypeInfo(getCanonicalType(T)); + } + + } + + assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); + return std::make_pair(Width, Align); +} + +/// toCharUnitsFromBits - Convert a size in bits to a size in characters. +CharUnits ASTContext::toCharUnitsFromBits(int64_t BitSize) const { + return CharUnits::fromQuantity(BitSize / getCharWidth()); +} + +/// toBits - Convert a size in characters to a size in characters. +int64_t ASTContext::toBits(CharUnits CharSize) const { + return CharSize.getQuantity() * getCharWidth(); +} + +/// getTypeSizeInChars - Return the size of the specified type, in characters. +/// This method does not work on incomplete types. +CharUnits ASTContext::getTypeSizeInChars(QualType T) const { + return toCharUnitsFromBits(getTypeSize(T)); +} +CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { + return toCharUnitsFromBits(getTypeSize(T)); +} + +/// getTypeAlignInChars - Return the ABI-specified alignment of a type, in +/// characters. This method does not work on incomplete types. +CharUnits ASTContext::getTypeAlignInChars(QualType T) const { + return toCharUnitsFromBits(getTypeAlign(T)); +} +CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { + return toCharUnitsFromBits(getTypeAlign(T)); +} + +/// 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) const { + unsigned ABIAlign = getTypeAlign(T); + + // Double and long long should be naturally aligned if possible. + if (const ComplexType* CT = T->getAs<ComplexType>()) + T = CT->getElementType().getTypePtr(); + if (T->isSpecificBuiltinType(BuiltinType::Double) || + T->isSpecificBuiltinType(BuiltinType::LongLong)) + return std::max(ABIAlign, (unsigned)getTypeSize(T)); + + return ABIAlign; +} + +/// ShallowCollectObjCIvars - +/// Collect all ivars, including those synthesized, in the current class. +/// +void ASTContext::ShallowCollectObjCIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { + // FIXME. This need be removed but there are two many places which + // assume const-ness of ObjCInterfaceDecl + ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(OI); + for (ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; + Iv= Iv->getNextIvar()) + Ivars.push_back(Iv); +} + +/// DeepCollectObjCIvars - +/// This routine first collects all declared, but not synthesized, ivars in +/// super class and then collects all ivars, including those synthesized for +/// current class. This routine is used for implementation of current class +/// when all ivars, declared and synthesized are known. +/// +void ASTContext::DeepCollectObjCIvars(const ObjCInterfaceDecl *OI, + bool leafClass, + llvm::SmallVectorImpl<ObjCIvarDecl*> &Ivars) const { + if (const ObjCInterfaceDecl *SuperClass = OI->getSuperClass()) + DeepCollectObjCIvars(SuperClass, false, Ivars); + if (!leafClass) { + for (ObjCInterfaceDecl::ivar_iterator I = OI->ivar_begin(), + E = OI->ivar_end(); I != E; ++I) + Ivars.push_back(*I); + } + else + ShallowCollectObjCIvars(OI, Ivars); +} + +/// CollectInheritedProtocols - Collect all protocols in current class and +/// those inherited by it. +void ASTContext::CollectInheritedProtocols(const Decl *CDecl, + llvm::SmallPtrSet<ObjCProtocolDecl*, 8> &Protocols) { + if (const ObjCInterfaceDecl *OI = dyn_cast<ObjCInterfaceDecl>(CDecl)) { + // We can use protocol_iterator here instead of + // all_referenced_protocol_iterator since we are walking all categories. + for (ObjCInterfaceDecl::all_protocol_iterator P = OI->all_referenced_protocol_begin(), + PE = OI->all_referenced_protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.insert(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) { + Protocols.insert(*P); + CollectInheritedProtocols(*P, Protocols); + } + } + + // Categories of this Interface. + for (const ObjCCategoryDecl *CDeclChain = OI->getCategoryList(); + CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) + CollectInheritedProtocols(CDeclChain, Protocols); + if (ObjCInterfaceDecl *SD = OI->getSuperClass()) + while (SD) { + CollectInheritedProtocols(SD, Protocols); + SD = SD->getSuperClass(); + } + } else if (const ObjCCategoryDecl *OC = dyn_cast<ObjCCategoryDecl>(CDecl)) { + for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(), + PE = OC->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.insert(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + } else if (const ObjCProtocolDecl *OP = dyn_cast<ObjCProtocolDecl>(CDecl)) { + for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), + PE = OP->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *Proto = (*P); + Protocols.insert(Proto); + for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), + PE = Proto->protocol_end(); P != PE; ++P) + CollectInheritedProtocols(*P, Protocols); + } + } +} + +unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { + unsigned count = 0; + // Count ivars declared in class extension. + for (const ObjCCategoryDecl *CDecl = OI->getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) + count += CDecl->ivar_size(); + + // Count ivar defined in this class's implementation. This + // includes synthesized ivars. + if (ObjCImplementationDecl *ImplDecl = OI->getImplementation()) + count += ImplDecl->ivar_size(); + + return count; +} + +/// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. +ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { + llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast<ObjCImplementationDecl>(I->second); + return 0; +} +/// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. +ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { + llvm::DenseMap<ObjCContainerDecl*, ObjCImplDecl*>::iterator + I = ObjCImpls.find(D); + if (I != ObjCImpls.end()) + return cast<ObjCCategoryImplDecl>(I->second); + return 0; +} + +/// \brief Set the implementation of ObjCInterfaceDecl. +void ASTContext::setObjCImplementation(ObjCInterfaceDecl *IFaceD, + ObjCImplementationDecl *ImplD) { + assert(IFaceD && ImplD && "Passed null params"); + ObjCImpls[IFaceD] = ImplD; +} +/// \brief Set the implementation of ObjCCategoryDecl. +void ASTContext::setObjCImplementation(ObjCCategoryDecl *CatD, + ObjCCategoryImplDecl *ImplD) { + assert(CatD && ImplD && "Passed null params"); + ObjCImpls[CatD] = ImplD; +} + +/// \brief Get the copy initialization expression of VarDecl,or NULL if +/// none exists. +Expr *ASTContext::getBlockVarCopyInits(const VarDecl*VD) { + assert(VD && "Passed null params"); + assert(VD->hasAttr<BlocksAttr>() && + "getBlockVarCopyInits - not __block var"); + llvm::DenseMap<const VarDecl*, Expr*>::iterator + I = BlockVarCopyInits.find(VD); + return (I != BlockVarCopyInits.end()) ? cast<Expr>(I->second) : 0; +} + +/// \brief Set the copy inialization expression of a block var decl. +void ASTContext::setBlockVarCopyInits(VarDecl*VD, Expr* Init) { + assert(VD && Init && "Passed null params"); + assert(VD->hasAttr<BlocksAttr>() && + "setBlockVarCopyInits - not __block var"); + BlockVarCopyInits[VD] = Init; +} + +/// \brief Allocate an uninitialized TypeSourceInfo. +/// +/// The caller should initialize the memory held by TypeSourceInfo using +/// the TypeLoc wrappers. +/// +/// \param T the type that will be the basis for type source info. This type +/// should refer to how the declarator was written in source code, not to +/// what type semantic analysis resolved the declarator to. +TypeSourceInfo *ASTContext::CreateTypeSourceInfo(QualType T, + unsigned DataSize) const { + if (!DataSize) + DataSize = TypeLoc::getFullDataSizeForType(T); + else + assert(DataSize == TypeLoc::getFullDataSizeForType(T) && + "incorrect data size provided to CreateTypeSourceInfo!"); + + TypeSourceInfo *TInfo = + (TypeSourceInfo*)BumpAlloc.Allocate(sizeof(TypeSourceInfo) + DataSize, 8); + new (TInfo) TypeSourceInfo(T); + return TInfo; +} + +TypeSourceInfo *ASTContext::getTrivialTypeSourceInfo(QualType T, + SourceLocation L) const { + TypeSourceInfo *DI = CreateTypeSourceInfo(T); + DI->getTypeLoc().initialize(const_cast<ASTContext &>(*this), L); + return DI; +} + +const ASTRecordLayout & +ASTContext::getASTObjCInterfaceLayout(const ObjCInterfaceDecl *D) const { + return getObjCLayout(D, 0); +} + +const ASTRecordLayout & +ASTContext::getASTObjCImplementationLayout( + const ObjCImplementationDecl *D) const { + return getObjCLayout(D->getClassInterface(), D); +} + +//===----------------------------------------------------------------------===// +// Type creation/memoization methods +//===----------------------------------------------------------------------===// + +QualType +ASTContext::getExtQualType(const Type *baseType, Qualifiers quals) const { + unsigned fastQuals = quals.getFastQualifiers(); + quals.removeFastQualifiers(); + + // Check if we've already instantiated this type. + llvm::FoldingSetNodeID ID; + ExtQuals::Profile(ID, baseType, quals); + void *insertPos = 0; + if (ExtQuals *eq = ExtQualNodes.FindNodeOrInsertPos(ID, insertPos)) { + assert(eq->getQualifiers() == quals); + return QualType(eq, fastQuals); + } + + // If the base type is not canonical, make the appropriate canonical type. + QualType canon; + if (!baseType->isCanonicalUnqualified()) { + SplitQualType canonSplit = baseType->getCanonicalTypeInternal().split(); + canonSplit.second.addConsistentQualifiers(quals); + canon = getExtQualType(canonSplit.first, canonSplit.second); + + // Re-find the insert position. + (void) ExtQualNodes.FindNodeOrInsertPos(ID, insertPos); + } + + ExtQuals *eq = new (*this, TypeAlignment) ExtQuals(baseType, canon, quals); + ExtQualNodes.InsertNode(eq, insertPos); + return QualType(eq, fastQuals); +} + +QualType +ASTContext::getAddrSpaceQualType(QualType T, unsigned AddressSpace) const { + QualType CanT = getCanonicalType(T); + if (CanT.getAddressSpace() == AddressSpace) + return T; + + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an address space specified, it cannot get + // another one. + assert(!Quals.hasAddressSpace() && + "Type cannot be in multiple addr spaces!"); + Quals.addAddressSpace(AddressSpace); + + return getExtQualType(TypeNode, Quals); +} + +QualType ASTContext::getObjCGCQualType(QualType T, + Qualifiers::GC GCAttr) const { + QualType CanT = getCanonicalType(T); + if (CanT.getObjCGCAttr() == GCAttr) + return T; + + if (const PointerType *ptr = T->getAs<PointerType>()) { + QualType Pointee = ptr->getPointeeType(); + if (Pointee->isAnyPointerType()) { + QualType ResultType = getObjCGCQualType(Pointee, GCAttr); + return getPointerType(ResultType); + } + } + + // If we are composing extended qualifiers together, merge together + // into one ExtQuals node. + QualifierCollector Quals; + const Type *TypeNode = Quals.strip(T); + + // If this type already has an ObjCGC specified, it cannot get + // another one. + assert(!Quals.hasObjCGCAttr() && + "Type cannot have multiple ObjCGCs!"); + Quals.addObjCGCAttr(GCAttr); + + return getExtQualType(TypeNode, Quals); +} + +const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, + FunctionType::ExtInfo Info) { + if (T->getExtInfo() == Info) + return T; + + QualType Result; + if (const FunctionNoProtoType *FNPT = dyn_cast<FunctionNoProtoType>(T)) { + Result = getFunctionNoProtoType(FNPT->getResultType(), Info); + } else { + const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = Info; + Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); + } + + return cast<FunctionType>(Result.getTypePtr()); +} + +/// getComplexType - Return the uniqued reference to the type for a complex +/// number with the specified element type. +QualType ASTContext::getComplexType(QualType T) const { + // 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!"); (void)NewIP; + } + ComplexType *New = new (*this, TypeAlignment) ComplexType(T, Canonical); + Types.push_back(New); + ComplexTypes.InsertNode(New, InsertPos); + return QualType(New, 0); +} + +/// getPointerType - Return the uniqued reference to the type for a pointer to +/// the specified type. +QualType ASTContext::getPointerType(QualType T) const { + // 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!"); (void)NewIP; + } + PointerType *New = new (*this, TypeAlignment) 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) const { + 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!"); (void)NewIP; + } + BlockPointerType *New + = new (*this, TypeAlignment) 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, bool SpelledAsLValue) const { + assert(getCanonicalType(T) != OverloadTy && + "Unresolved overloaded function type"); + + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ReferenceType::Profile(ID, T, SpelledAsLValue); + + void *InsertPos = 0; + if (LValueReferenceType *RT = + LValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(RT, 0); + + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + + // 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 (!SpelledAsLValue || InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getLValueReferenceType(getCanonicalType(PointeeType)); + + // 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!"); (void)NewIP; + } + + LValueReferenceType *New + = new (*this, TypeAlignment) LValueReferenceType(T, Canonical, + SpelledAsLValue); + 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) const { + // Unique pointers, to guarantee there is only one pointer of a particular + // structure. + llvm::FoldingSetNodeID ID; + ReferenceType::Profile(ID, T, false); + + void *InsertPos = 0; + if (RValueReferenceType *RT = + RValueReferenceTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(RT, 0); + + const ReferenceType *InnerRef = T->getAs<ReferenceType>(); + + // 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 (InnerRef || !T.isCanonical()) { + QualType PointeeType = (InnerRef ? InnerRef->getPointeeType() : T); + Canonical = getRValueReferenceType(getCanonicalType(PointeeType)); + + // 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!"); (void)NewIP; + } + + RValueReferenceType *New + = new (*this, TypeAlignment) 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) const { + // 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() || !Cls->isCanonicalUnqualified()) { + 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!"); (void)NewIP; + } + MemberPointerType *New + = new (*this, TypeAlignment) 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 IndexTypeQuals) const { + assert((EltTy->isDependentType() || + EltTy->isIncompleteType() || 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 = + ArySize.zextOrTrunc(Target.getPointerWidth(getTargetAddressSpace(EltTy))); + + llvm::FoldingSetNodeID ID; + ConstantArrayType::Profile(ID, EltTy, ArySize, ASM, IndexTypeQuals); + + void *InsertPos = 0; + if (ConstantArrayType *ATP = + ConstantArrayTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(ATP, 0); + + // If the element type isn't canonical or has qualifiers, this won't + // be a canonical type either, so fill in the canonical type field. + QualType Canon; + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getConstantArrayType(QualType(canonSplit.first, 0), ArySize, + ASM, IndexTypeQuals); + Canon = getQualifiedType(Canon, canonSplit.second); + + // 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!"); (void)NewIP; + } + + ConstantArrayType *New = new(*this,TypeAlignment) + ConstantArrayType(EltTy, Canon, ArySize, ASM, IndexTypeQuals); + ConstantArrayTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +/// getVariableArrayDecayedType - Turns the given type, which may be +/// variably-modified, into the corresponding type with all the known +/// sizes replaced with [*]. +QualType ASTContext::getVariableArrayDecayedType(QualType type) const { + // Vastly most common case. + if (!type->isVariablyModifiedType()) return type; + + QualType result; + + SplitQualType split = type.getSplitDesugaredType(); + const Type *ty = split.first; + switch (ty->getTypeClass()) { +#define TYPE(Class, Base) +#define ABSTRACT_TYPE(Class, Base) +#define NON_CANONICAL_TYPE(Class, Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("didn't desugar past all non-canonical types?"); + + // These types should never be variably-modified. + case Type::Builtin: + case Type::Complex: + case Type::Vector: + case Type::ExtVector: + case Type::DependentSizedExtVector: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Record: + case Type::Enum: + case Type::UnresolvedUsing: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::UnaryTransform: + case Type::DependentName: + case Type::InjectedClassName: + case Type::TemplateSpecialization: + case Type::DependentTemplateSpecialization: + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + case Type::Auto: + case Type::PackExpansion: + llvm_unreachable("type should never be variably-modified"); + + // These types can be variably-modified but should never need to + // further decay. + case Type::FunctionNoProto: + case Type::FunctionProto: + case Type::BlockPointer: + case Type::MemberPointer: + return type; + + // These types can be variably-modified. All these modifications + // preserve structure except as noted by comments. + // TODO: if we ever care about optimizing VLAs, there are no-op + // optimizations available here. + case Type::Pointer: + result = getPointerType(getVariableArrayDecayedType( + cast<PointerType>(ty)->getPointeeType())); + break; + + case Type::LValueReference: { + const LValueReferenceType *lv = cast<LValueReferenceType>(ty); + result = getLValueReferenceType( + getVariableArrayDecayedType(lv->getPointeeType()), + lv->isSpelledAsLValue()); + break; + } + + case Type::RValueReference: { + const RValueReferenceType *lv = cast<RValueReferenceType>(ty); + result = getRValueReferenceType( + getVariableArrayDecayedType(lv->getPointeeType())); + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *cat = cast<ConstantArrayType>(ty); + result = getConstantArrayType( + getVariableArrayDecayedType(cat->getElementType()), + cat->getSize(), + cat->getSizeModifier(), + cat->getIndexTypeCVRQualifiers()); + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *dat = cast<DependentSizedArrayType>(ty); + result = getDependentSizedArrayType( + getVariableArrayDecayedType(dat->getElementType()), + dat->getSizeExpr(), + dat->getSizeModifier(), + dat->getIndexTypeCVRQualifiers(), + dat->getBracketsRange()); + break; + } + + // Turn incomplete types into [*] types. + case Type::IncompleteArray: { + const IncompleteArrayType *iat = cast<IncompleteArrayType>(ty); + result = getVariableArrayType( + getVariableArrayDecayedType(iat->getElementType()), + /*size*/ 0, + ArrayType::Normal, + iat->getIndexTypeCVRQualifiers(), + SourceRange()); + break; + } + + // Turn VLA types into [*] types. + case Type::VariableArray: { + const VariableArrayType *vat = cast<VariableArrayType>(ty); + result = getVariableArrayType( + getVariableArrayDecayedType(vat->getElementType()), + /*size*/ 0, + ArrayType::Star, + vat->getIndexTypeCVRQualifiers(), + vat->getBracketsRange()); + break; + } + } + + // Apply the top-level qualifiers from the original. + return getQualifiedType(result, split.second); +} + +/// 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 IndexTypeQuals, + SourceRange Brackets) const { + // Since we don't unique expressions, it isn't possible to unique VLA's + // that have an expression provided for their size. + QualType Canon; + + // Be sure to pull qualifiers off the element type. + if (!EltTy.isCanonical() || EltTy.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(EltTy).split(); + Canon = getVariableArrayType(QualType(canonSplit.first, 0), NumElts, ASM, + IndexTypeQuals, Brackets); + Canon = getQualifiedType(Canon, canonSplit.second); + } + + VariableArrayType *New = new(*this, TypeAlignment) + VariableArrayType(EltTy, Canon, NumElts, ASM, IndexTypeQuals, Brackets); + + 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. +QualType ASTContext::getDependentSizedArrayType(QualType elementType, + Expr *numElements, + ArrayType::ArraySizeModifier ASM, + unsigned elementTypeQuals, + SourceRange brackets) const { + assert((!numElements || numElements->isTypeDependent() || + numElements->isValueDependent()) && + "Size must be type- or value-dependent!"); + + // Dependently-sized array types that do not have a specified number + // of elements will have their sizes deduced from a dependent + // initializer. We do no canonicalization here at all, which is okay + // because they can't be used in most locations. + if (!numElements) { + DependentSizedArrayType *newType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, QualType(), + numElements, ASM, elementTypeQuals, + brackets); + Types.push_back(newType); + return QualType(newType, 0); + } + + // Otherwise, we actually build a new type every time, but we + // also build a canonical type. + + SplitQualType canonElementType = getCanonicalType(elementType).split(); + + void *insertPos = 0; + llvm::FoldingSetNodeID ID; + DependentSizedArrayType::Profile(ID, *this, + QualType(canonElementType.first, 0), + ASM, elementTypeQuals, numElements); + + // Look for an existing type with these properties. + DependentSizedArrayType *canonTy = + DependentSizedArrayTypes.FindNodeOrInsertPos(ID, insertPos); + + // If we don't have one, build one. + if (!canonTy) { + canonTy = new (*this, TypeAlignment) + DependentSizedArrayType(*this, QualType(canonElementType.first, 0), + QualType(), numElements, ASM, elementTypeQuals, + brackets); + DependentSizedArrayTypes.InsertNode(canonTy, insertPos); + Types.push_back(canonTy); + } + + // Apply qualifiers from the element type to the array. + QualType canon = getQualifiedType(QualType(canonTy,0), + canonElementType.second); + + // If we didn't need extra canonicalization for the element type, + // then just use that as our result. + if (QualType(canonElementType.first, 0) == elementType) + return canon; + + // Otherwise, we need to build a type which follows the spelling + // of the element type. + DependentSizedArrayType *sugaredType + = new (*this, TypeAlignment) + DependentSizedArrayType(*this, elementType, canon, numElements, + ASM, elementTypeQuals, brackets); + Types.push_back(sugaredType); + return QualType(sugaredType, 0); +} + +QualType ASTContext::getIncompleteArrayType(QualType elementType, + ArrayType::ArraySizeModifier ASM, + unsigned elementTypeQuals) const { + llvm::FoldingSetNodeID ID; + IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals); + + void *insertPos = 0; + if (IncompleteArrayType *iat = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos)) + return QualType(iat, 0); + + // If the element type isn't canonical, this won't be a canonical type + // either, so fill in the canonical type field. We also have to pull + // qualifiers off the element type. + QualType canon; + + if (!elementType.isCanonical() || elementType.hasLocalQualifiers()) { + SplitQualType canonSplit = getCanonicalType(elementType).split(); + canon = getIncompleteArrayType(QualType(canonSplit.first, 0), + ASM, elementTypeQuals); + canon = getQualifiedType(canon, canonSplit.second); + + // Get the new insert position for the node we care about. + IncompleteArrayType *existing = + IncompleteArrayTypes.FindNodeOrInsertPos(ID, insertPos); + assert(!existing && "Shouldn't be in the map!"); (void) existing; + } + + IncompleteArrayType *newType = new (*this, TypeAlignment) + IncompleteArrayType(elementType, canon, ASM, elementTypeQuals); + + IncompleteArrayTypes.InsertNode(newType, insertPos); + Types.push_back(newType); + return QualType(newType, 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, + VectorType::VectorKind VecKind) const { + assert(vecType->isBuiltinType()); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::Vector, VecKind); + + 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, VecKind); + + // 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!"); (void)NewIP; + } + VectorType *New = new (*this, TypeAlignment) + VectorType(vecType, NumElts, Canonical, VecKind); + 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) const { + assert(vecType->isBuiltinType()); + + // Check if we've already instantiated a vector of this type. + llvm::FoldingSetNodeID ID; + VectorType::Profile(ID, vecType, NumElts, Type::ExtVector, + VectorType::GenericVector); + 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!"); (void)NewIP; + } + ExtVectorType *New = new (*this, TypeAlignment) + ExtVectorType(vecType, NumElts, Canonical); + VectorTypes.InsertNode(New, InsertPos); + Types.push_back(New); + return QualType(New, 0); +} + +QualType +ASTContext::getDependentSizedExtVectorType(QualType vecType, + Expr *SizeExpr, + SourceLocation AttrLoc) const { + llvm::FoldingSetNodeID ID; + DependentSizedExtVectorType::Profile(ID, *this, getCanonicalType(vecType), + SizeExpr); + + void *InsertPos = 0; + DependentSizedExtVectorType *Canon + = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + DependentSizedExtVectorType *New; + if (Canon) { + // We already have a canonical version of this array type; use it as + // the canonical type for a newly-built type. + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(Canon, 0), + SizeExpr, AttrLoc); + } else { + QualType CanonVecTy = getCanonicalType(vecType); + if (CanonVecTy == vecType) { + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, QualType(), SizeExpr, + AttrLoc); + + DependentSizedExtVectorType *CanonCheck + = DependentSizedExtVectorTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CanonCheck && "Dependent-sized ext_vector canonical type broken"); + (void)CanonCheck; + DependentSizedExtVectorTypes.InsertNode(New, InsertPos); + } else { + QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); + New = new (*this, TypeAlignment) + DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc); + } + } + + Types.push_back(New); + return QualType(New, 0); +} + +/// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. +/// +QualType +ASTContext::getFunctionNoProtoType(QualType ResultTy, + const FunctionType::ExtInfo &Info) const { + const CallingConv DefaultCC = Info.getCC(); + const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? + CC_X86StdCall : DefaultCC; + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionNoProtoType::Profile(ID, ResultTy, Info); + + void *InsertPos = 0; + if (FunctionNoProtoType *FT = + FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(FT, 0); + + QualType Canonical; + if (!ResultTy.isCanonical() || + getCanonicalCallConv(CallConv) != CallConv) { + Canonical = + getFunctionNoProtoType(getCanonicalType(ResultTy), + Info.withCallingConv(getCanonicalCallConv(CallConv))); + + // 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!"); (void)NewIP; + } + + FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv); + FunctionNoProtoType *New = new (*this, TypeAlignment) + FunctionNoProtoType(ResultTy, Canonical, newInfo); + 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, + const FunctionProtoType::ExtProtoInfo &EPI) const { + // Unique functions, to guarantee there is only one function of a particular + // structure. + llvm::FoldingSetNodeID ID; + FunctionProtoType::Profile(ID, ResultTy, ArgArray, NumArgs, EPI, *this); + + 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= EPI.ExceptionSpecType == EST_None && ResultTy.isCanonical(); + for (unsigned i = 0; i != NumArgs && isCanonical; ++i) + if (!ArgArray[i].isCanonicalAsParam()) + isCanonical = false; + + const CallingConv DefaultCC = EPI.ExtInfo.getCC(); + const CallingConv CallConv = (LangOpts.MRTD && DefaultCC == CC_Default) ? + CC_X86StdCall : DefaultCC; + + // 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 || getCanonicalCallConv(CallConv) != CallConv) { + llvm::SmallVector<QualType, 16> CanonicalArgs; + CanonicalArgs.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); + + FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI; + CanonicalEPI.ExceptionSpecType = EST_None; + CanonicalEPI.NumExceptions = 0; + CanonicalEPI.ExtInfo + = CanonicalEPI.ExtInfo.withCallingConv(getCanonicalCallConv(CallConv)); + + Canonical = getFunctionType(getCanonicalType(ResultTy), + CanonicalArgs.data(), NumArgs, + CanonicalEPI); + + // 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!"); (void)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. Instead of the exception types, there could be a noexcept + // expression and a context pointer. + size_t Size = sizeof(FunctionProtoType) + + NumArgs * sizeof(QualType); + if (EPI.ExceptionSpecType == EST_Dynamic) + Size += EPI.NumExceptions * sizeof(QualType); + else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + Size += sizeof(Expr*); + } + FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); + FunctionProtoType::ExtProtoInfo newEPI = EPI; + newEPI.ExtInfo = EPI.ExtInfo.withCallingConv(CallConv); + new (FTP) FunctionProtoType(ResultTy, ArgArray, NumArgs, Canonical, newEPI); + Types.push_back(FTP); + FunctionProtoTypes.InsertNode(FTP, InsertPos); + return QualType(FTP, 0); +} + +#ifndef NDEBUG +static bool NeedsInjectedClassNameType(const RecordDecl *D) { + if (!isa<CXXRecordDecl>(D)) return false; + const CXXRecordDecl *RD = cast<CXXRecordDecl>(D); + if (isa<ClassTemplatePartialSpecializationDecl>(RD)) + return true; + if (RD->getDescribedClassTemplate() && + !isa<ClassTemplateSpecializationDecl>(RD)) + return true; + return false; +} +#endif + +/// getInjectedClassNameType - Return the unique reference to the +/// injected class name type for the specified templated declaration. +QualType ASTContext::getInjectedClassNameType(CXXRecordDecl *Decl, + QualType TST) const { + assert(NeedsInjectedClassNameType(Decl)); + if (Decl->TypeForDecl) { + assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); + } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDeclaration()) { + assert(PrevDecl->TypeForDecl && "previous declaration has no type"); + Decl->TypeForDecl = PrevDecl->TypeForDecl; + assert(isa<InjectedClassNameType>(Decl->TypeForDecl)); + } else { + Type *newType = + new (*this, TypeAlignment) InjectedClassNameType(Decl, TST); + Decl->TypeForDecl = newType; + Types.push_back(newType); + } + return QualType(Decl->TypeForDecl, 0); +} + +/// getTypeDeclType - Return the unique reference to the type for the +/// specified type declaration. +QualType ASTContext::getTypeDeclTypeSlow(const TypeDecl *Decl) const { + assert(Decl && "Passed null for Decl param"); + assert(!Decl->TypeForDecl && "TypeForDecl present in slow case"); + + if (const TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Decl)) + return getTypedefType(Typedef); + + assert(!isa<TemplateTypeParmDecl>(Decl) && + "Template type parameter types are always available."); + + if (const RecordDecl *Record = dyn_cast<RecordDecl>(Decl)) { + assert(!Record->getPreviousDeclaration() && + "struct/union has previous declaration"); + assert(!NeedsInjectedClassNameType(Record)); + return getRecordType(Record); + } else if (const EnumDecl *Enum = dyn_cast<EnumDecl>(Decl)) { + assert(!Enum->getPreviousDeclaration() && + "enum has previous declaration"); + return getEnumType(Enum); + } else if (const UnresolvedUsingTypenameDecl *Using = + dyn_cast<UnresolvedUsingTypenameDecl>(Decl)) { + Type *newType = new (*this, TypeAlignment) UnresolvedUsingType(Using); + Decl->TypeForDecl = newType; + Types.push_back(newType); + } else + llvm_unreachable("TypeDecl without a type?"); + + return QualType(Decl->TypeForDecl, 0); +} + +/// getTypedefType - Return the unique reference to the type for the +/// specified typedef name decl. +QualType +ASTContext::getTypedefType(const TypedefNameDecl *Decl, + QualType Canonical) const { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (Canonical.isNull()) + Canonical = getCanonicalType(Decl->getUnderlyingType()); + TypedefType *newType = new(*this, TypeAlignment) + TypedefType(Type::Typedef, Decl, Canonical); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); +} + +QualType ASTContext::getRecordType(const RecordDecl *Decl) const { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (const RecordDecl *PrevDecl = Decl->getPreviousDeclaration()) + if (PrevDecl->TypeForDecl) + return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + + RecordType *newType = new (*this, TypeAlignment) RecordType(Decl); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); +} + +QualType ASTContext::getEnumType(const EnumDecl *Decl) const { + if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); + + if (const EnumDecl *PrevDecl = Decl->getPreviousDeclaration()) + if (PrevDecl->TypeForDecl) + return QualType(Decl->TypeForDecl = PrevDecl->TypeForDecl, 0); + + EnumType *newType = new (*this, TypeAlignment) EnumType(Decl); + Decl->TypeForDecl = newType; + Types.push_back(newType); + return QualType(newType, 0); +} + +QualType ASTContext::getAttributedType(AttributedType::Kind attrKind, + QualType modifiedType, + QualType equivalentType) { + llvm::FoldingSetNodeID id; + AttributedType::Profile(id, attrKind, modifiedType, equivalentType); + + void *insertPos = 0; + AttributedType *type = AttributedTypes.FindNodeOrInsertPos(id, insertPos); + if (type) return QualType(type, 0); + + QualType canon = getCanonicalType(equivalentType); + type = new (*this, TypeAlignment) + AttributedType(canon, attrKind, modifiedType, equivalentType); + + Types.push_back(type); + AttributedTypes.InsertNode(type, insertPos); + + return QualType(type, 0); +} + + +/// \brief Retrieve a substitution-result type. +QualType +ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, + QualType Replacement) const { + assert(Replacement.isCanonical() + && "replacement types must always be canonical"); + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmType::Profile(ID, Parm, Replacement); + void *InsertPos = 0; + SubstTemplateTypeParmType *SubstParm + = SubstTemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!SubstParm) { + SubstParm = new (*this, TypeAlignment) + SubstTemplateTypeParmType(Parm, Replacement); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + } + + return QualType(SubstParm, 0); +} + +/// \brief Retrieve a +QualType ASTContext::getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Parm, + const TemplateArgument &ArgPack) { +#ifndef NDEBUG + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) { + assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type"); + assert(P->getAsType().isCanonical() && "Pack contains non-canonical type"); + } +#endif + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); + void *InsertPos = 0; + if (SubstTemplateTypeParmPackType *SubstParm + = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(SubstParm, 0); + + QualType Canon; + if (!Parm->isCanonicalUnqualified()) { + Canon = getCanonicalType(QualType(Parm, 0)); + Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon), + ArgPack); + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + SubstTemplateTypeParmPackType *SubstParm + = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, + ArgPack); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + return QualType(SubstParm, 0); +} + +/// \brief Retrieve the template type parameter type for a template +/// parameter or parameter pack with the given depth, index, and (optionally) +/// name. +QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, + bool ParameterPack, + TemplateTypeParmDecl *TTPDecl) const { + llvm::FoldingSetNodeID ID; + TemplateTypeParmType::Profile(ID, Depth, Index, ParameterPack, TTPDecl); + void *InsertPos = 0; + TemplateTypeParmType *TypeParm + = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (TypeParm) + return QualType(TypeParm, 0); + + if (TTPDecl) { + QualType Canon = getTemplateTypeParmType(Depth, Index, ParameterPack); + TypeParm = new (*this, TypeAlignment) TemplateTypeParmType(TTPDecl, Canon); + + TemplateTypeParmType *TypeCheck + = TemplateTypeParmTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!TypeCheck && "Template type parameter canonical type broken"); + (void)TypeCheck; + } else + TypeParm = new (*this, TypeAlignment) + TemplateTypeParmType(Depth, Index, ParameterPack); + + Types.push_back(TypeParm); + TemplateTypeParmTypes.InsertNode(TypeParm, InsertPos); + + return QualType(TypeParm, 0); +} + +TypeSourceInfo * +ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, + SourceLocation NameLoc, + const TemplateArgumentListInfo &Args, + QualType Underlying) const { + assert(!Name.getAsDependentTemplateName() && + "No dependent template names here!"); + QualType TST = getTemplateSpecializationType(Name, Args, Underlying); + + TypeSourceInfo *DI = CreateTypeSourceInfo(TST); + TemplateSpecializationTypeLoc TL + = cast<TemplateSpecializationTypeLoc>(DI->getTypeLoc()); + TL.setTemplateNameLoc(NameLoc); + TL.setLAngleLoc(Args.getLAngleLoc()); + TL.setRAngleLoc(Args.getRAngleLoc()); + for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) + TL.setArgLocInfo(i, Args[i].getLocInfo()); + return DI; +} + +QualType +ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgumentListInfo &Args, + QualType Underlying) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + + unsigned NumArgs = Args.size(); + + llvm::SmallVector<TemplateArgument, 4> ArgVec; + ArgVec.reserve(NumArgs); + for (unsigned i = 0; i != NumArgs; ++i) + ArgVec.push_back(Args[i].getArgument()); + + return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, + Underlying); +} + +QualType +ASTContext::getTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs, + QualType Underlying) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + // Look through qualified template names. + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Template = TemplateName(QTN->getTemplateDecl()); + + bool isTypeAlias = + Template.getAsTemplateDecl() && + isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); + + QualType CanonType; + if (!Underlying.isNull()) + CanonType = getCanonicalType(Underlying); + else { + assert(!isTypeAlias && + "Underlying type for template alias must be computed by caller"); + CanonType = getCanonicalTemplateSpecializationType(Template, Args, + NumArgs); + } + + // Allocate the (non-canonical) template specialization type, but don't + // try to unique it: these types typically have location information that + // we don't unique and don't want to lose. + void *Mem = Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs + + (isTypeAlias ? sizeof(QualType) : 0), + TypeAlignment); + TemplateSpecializationType *Spec + = new (Mem) TemplateSpecializationType(Template, + Args, NumArgs, + CanonType, + isTypeAlias ? Underlying : QualType()); + + Types.push_back(Spec); + return QualType(Spec, 0); +} + +QualType +ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, + const TemplateArgument *Args, + unsigned NumArgs) const { + assert(!Template.getAsDependentTemplateName() && + "No dependent template names here!"); + assert((!Template.getAsTemplateDecl() || + !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) && + "Underlying type for template alias must be computed by caller"); + + // Look through qualified template names. + if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Template = TemplateName(QTN->getTemplateDecl()); + + // Build the canonical template specialization type. + TemplateName CanonTemplate = getCanonicalTemplateName(Template); + llvm::SmallVector<TemplateArgument, 4> CanonArgs; + CanonArgs.reserve(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) + CanonArgs.push_back(getCanonicalTemplateArgument(Args[I])); + + // Determine whether this canonical template specialization type already + // exists. + llvm::FoldingSetNodeID ID; + TemplateSpecializationType::Profile(ID, CanonTemplate, + CanonArgs.data(), NumArgs, *this); + + void *InsertPos = 0; + TemplateSpecializationType *Spec + = TemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + + if (!Spec) { + // Allocate a new canonical template specialization type. + void *Mem = Allocate((sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + TypeAlignment); + Spec = new (Mem) TemplateSpecializationType(CanonTemplate, + CanonArgs.data(), NumArgs, + QualType(), QualType()); + Types.push_back(Spec); + TemplateSpecializationTypes.InsertNode(Spec, InsertPos); + } + + assert(Spec->isDependentType() && + "Non-dependent template-id type must have a canonical type"); + return QualType(Spec, 0); +} + +QualType +ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + QualType NamedType) const { + llvm::FoldingSetNodeID ID; + ElaboratedType::Profile(ID, Keyword, NNS, NamedType); + + void *InsertPos = 0; + ElaboratedType *T = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon = NamedType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(NamedType); + ElaboratedType *CheckT = ElaboratedTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Elaborated canonical type broken"); + (void)CheckT; + } + + T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon); + Types.push_back(T); + ElaboratedTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType +ASTContext::getParenType(QualType InnerType) const { + llvm::FoldingSetNodeID ID; + ParenType::Profile(ID, InnerType); + + void *InsertPos = 0; + ParenType *T = ParenTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon = InnerType; + if (!Canon.isCanonical()) { + Canon = getCanonicalType(InnerType); + ParenType *CheckT = ParenTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckT && "Paren canonical type broken"); + (void)CheckT; + } + + T = new (*this) ParenType(InnerType, Canon); + Types.push_back(T); + ParenTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + QualType Canon) const { + assert(NNS->isDependent() && "nested-name-specifier must be dependent"); + + if (Canon.isNull()) { + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + ElaboratedTypeKeyword CanonKeyword = Keyword; + if (Keyword == ETK_None) + CanonKeyword = ETK_Typename; + + if (CanonNNS != NNS || CanonKeyword != Keyword) + Canon = getDependentNameType(CanonKeyword, CanonNNS, Name); + } + + llvm::FoldingSetNodeID ID; + DependentNameType::Profile(ID, Keyword, NNS, Name); + + void *InsertPos = 0; + DependentNameType *T + = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + T = new (*this) DependentNameType(Keyword, NNS, Name, Canon); + Types.push_back(T); + DependentNameTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType +ASTContext::getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + const TemplateArgumentListInfo &Args) const { + // TODO: avoid this copy + llvm::SmallVector<TemplateArgument, 16> ArgCopy; + for (unsigned I = 0, E = Args.size(); I != E; ++I) + ArgCopy.push_back(Args[I].getArgument()); + return getDependentTemplateSpecializationType(Keyword, NNS, Name, + ArgCopy.size(), + ArgCopy.data()); +} + +QualType +ASTContext::getDependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args) const { + assert((!NNS || NNS->isDependent()) && + "nested-name-specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS, + Name, NumArgs, Args); + + void *InsertPos = 0; + DependentTemplateSpecializationType *T + = DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS); + + ElaboratedTypeKeyword CanonKeyword = Keyword; + if (Keyword == ETK_None) CanonKeyword = ETK_Typename; + + bool AnyNonCanonArgs = false; + llvm::SmallVector<TemplateArgument, 16> CanonArgs(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) { + CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); + if (!CanonArgs[I].structurallyEquals(Args[I])) + AnyNonCanonArgs = true; + } + + QualType Canon; + if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { + Canon = getDependentTemplateSpecializationType(CanonKeyword, CanonNNS, + Name, NumArgs, + CanonArgs.data()); + + // Find the insert position again. + DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + TypeAlignment); + T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, + Name, NumArgs, Args, Canon); + Types.push_back(T); + DependentTemplateSpecializationTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +QualType ASTContext::getPackExpansionType(QualType Pattern, + llvm::Optional<unsigned> NumExpansions) { + llvm::FoldingSetNodeID ID; + PackExpansionType::Profile(ID, Pattern, NumExpansions); + + assert(Pattern->containsUnexpandedParameterPack() && + "Pack expansions must expand one or more parameter packs"); + void *InsertPos = 0; + PackExpansionType *T + = PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon; + if (!Pattern.isCanonical()) { + Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions); + + // Find the insert position again. + PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions); + Types.push_back(T); + PackExpansionTypes.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 bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) { + if (NumProtocols == 0) return true; + + for (unsigned i = 1; i != NumProtocols; ++i) + if (!CmpProtocolNames(Protocols[i-1], Protocols[i])) + return false; + return true; +} + +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; +} + +QualType ASTContext::getObjCObjectType(QualType BaseType, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) const { + // If the base type is an interface and there aren't any protocols + // to add, then the interface type will do just fine. + if (!NumProtocols && isa<ObjCInterfaceType>(BaseType)) + return BaseType; + + // Look in the folding set for an existing type. + llvm::FoldingSetNodeID ID; + ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); + void *InsertPos = 0; + if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // Build the canonical type, which has the canonical base type and + // a sorted-and-uniqued list of protocols. + QualType Canonical; + bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); + if (!ProtocolsSorted || !BaseType.isCanonical()) { + if (!ProtocolsSorted) { + llvm::SmallVector<ObjCProtocolDecl*, 8> Sorted(Protocols, + Protocols + NumProtocols); + unsigned UniqueCount = NumProtocols; + + SortAndUniqueProtocols(&Sorted[0], UniqueCount); + Canonical = getObjCObjectType(getCanonicalType(BaseType), + &Sorted[0], UniqueCount); + } else { + Canonical = getObjCObjectType(getCanonicalType(BaseType), + Protocols, NumProtocols); + } + + // Regenerate InsertPos. + ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + unsigned Size = sizeof(ObjCObjectTypeImpl); + Size += NumProtocols * sizeof(ObjCProtocolDecl *); + void *Mem = Allocate(Size, TypeAlignment); + ObjCObjectTypeImpl *T = + new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); + + Types.push_back(T); + ObjCObjectTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + +/// getObjCObjectPointerType - Return a ObjCObjectPointerType type for +/// the given object type. +QualType ASTContext::getObjCObjectPointerType(QualType ObjectT) const { + llvm::FoldingSetNodeID ID; + ObjCObjectPointerType::Profile(ID, ObjectT); + + void *InsertPos = 0; + if (ObjCObjectPointerType *QT = + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(QT, 0); + + // Find the canonical object type. + QualType Canonical; + if (!ObjectT.isCanonical()) { + Canonical = getObjCObjectPointerType(getCanonicalType(ObjectT)); + + // Regenerate InsertPos. + ObjCObjectPointerTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + // No match. + void *Mem = Allocate(sizeof(ObjCObjectPointerType), TypeAlignment); + ObjCObjectPointerType *QType = + new (Mem) ObjCObjectPointerType(Canonical, ObjectT); + + Types.push_back(QType); + ObjCObjectPointerTypes.InsertNode(QType, InsertPos); + return QualType(QType, 0); +} + +/// getObjCInterfaceType - Return the unique reference to the type for the +/// specified ObjC interface decl. The list of protocols is optional. +QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl) const { + if (Decl->TypeForDecl) + return QualType(Decl->TypeForDecl, 0); + + // FIXME: redeclarations? + void *Mem = Allocate(sizeof(ObjCInterfaceType), TypeAlignment); + ObjCInterfaceType *T = new (Mem) ObjCInterfaceType(Decl); + Decl->TypeForDecl = T; + Types.push_back(T); + return QualType(T, 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) const { + TypeOfExprType *toe; + if (tofExpr->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentTypeOfExprType::Profile(ID, *this, tofExpr); + + void *InsertPos = 0; + DependentTypeOfExprType *Canon + = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos); + if (Canon) { + // We already have a "canonical" version of an identical, dependent + // typeof(expr) type. Use that as our canonical type. + toe = new (*this, TypeAlignment) TypeOfExprType(tofExpr, + QualType((TypeOfExprType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon + = new (*this, TypeAlignment) DependentTypeOfExprType(*this, tofExpr); + DependentTypeOfExprTypes.InsertNode(Canon, InsertPos); + toe = Canon; + } + } else { + QualType Canonical = getCanonicalType(tofExpr->getType()); + toe = new (*this, TypeAlignment) 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) const { + QualType Canonical = getCanonicalType(tofType); + TypeOfType *tot = new (*this, TypeAlignment) TypeOfType(tofType, Canonical); + Types.push_back(tot); + return QualType(tot, 0); +} + +/// getDecltypeForExpr - Given an expr, will return the decltype for that +/// expression, according to the rules in C++0x [dcl.type.simple]p4 +static QualType getDecltypeForExpr(const Expr *e, const ASTContext &Context) { + if (e->isTypeDependent()) + return Context.DependentTy; + + // If e is an id expression or a class member access, decltype(e) is defined + // as the type of the entity named by e. + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(e)) { + if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) + return VD->getType(); + } + if (const MemberExpr *ME = dyn_cast<MemberExpr>(e)) { + if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) + return FD->getType(); + } + // If e is a function call or an invocation of an overloaded operator, + // (parentheses around e are ignored), decltype(e) is defined as the + // return type of that function. + if (const CallExpr *CE = dyn_cast<CallExpr>(e->IgnoreParens())) + return CE->getCallReturnType(); + + QualType T = e->getType(); + + // Otherwise, where T is the type of e, if e is an lvalue, decltype(e) is + // defined as T&, otherwise decltype(e) is defined as T. + if (e->isLValue()) + T = Context.getLValueReferenceType(T); + + return T; +} + +/// getDecltypeType - Unlike many "get<Type>" functions, we don't unique +/// DecltypeType AST's. The only motivation to unique these nodes would be +/// memory savings. Since decltype(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::getDecltypeType(Expr *e) const { + DecltypeType *dt; + if (e->isTypeDependent()) { + llvm::FoldingSetNodeID ID; + DependentDecltypeType::Profile(ID, *this, e); + + void *InsertPos = 0; + DependentDecltypeType *Canon + = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos); + if (Canon) { + // We already have a "canonical" version of an equivalent, dependent + // decltype type. Use that as our canonical type. + dt = new (*this, TypeAlignment) DecltypeType(e, DependentTy, + QualType((DecltypeType*)Canon, 0)); + } + else { + // Build a new, canonical typeof(expr) type. + Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); + DependentDecltypeTypes.InsertNode(Canon, InsertPos); + dt = Canon; + } + } else { + QualType T = getDecltypeForExpr(e, *this); + dt = new (*this, TypeAlignment) DecltypeType(e, T, getCanonicalType(T)); + } + Types.push_back(dt); + return QualType(dt, 0); +} + +/// getUnaryTransformationType - We don't unique these, since the memory +/// savings are minimal and these are rare. +QualType ASTContext::getUnaryTransformType(QualType BaseType, + QualType UnderlyingType, + UnaryTransformType::UTTKind Kind) + const { + UnaryTransformType *Ty = + new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType, + Kind, + UnderlyingType->isDependentType() ? + QualType() : UnderlyingType); + Types.push_back(Ty); + return QualType(Ty, 0); +} + +/// getAutoType - We only unique auto types after they've been deduced. +QualType ASTContext::getAutoType(QualType DeducedType) const { + void *InsertPos = 0; + if (!DeducedType.isNull()) { + // Look in the folding set for an existing type. + llvm::FoldingSetNodeID ID; + AutoType::Profile(ID, DeducedType); + if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(AT, 0); + } + + AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType); + Types.push_back(AT); + if (InsertPos) + AutoTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); +} + +/// getAutoDeductType - Get type pattern for deducing against 'auto'. +QualType ASTContext::getAutoDeductType() const { + if (AutoDeductTy.isNull()) + AutoDeductTy = getAutoType(QualType()); + assert(!AutoDeductTy.isNull() && "can't build 'auto' pattern"); + return AutoDeductTy; +} + +/// getAutoRRefDeductType - Get type pattern for deducing against 'auto &&'. +QualType ASTContext::getAutoRRefDeductType() const { + if (AutoRRefDeductTy.isNull()) + AutoRRefDeductTy = getRValueReferenceType(getAutoDeductType()); + assert(!AutoRRefDeductTy.isNull() && "can't build 'auto &&' pattern"); + return AutoRRefDeductTy; +} + +/// getTagDeclType - Return the unique reference to the type for the +/// specified TagDecl (struct/union/class/enum) decl. +QualType ASTContext::getTagDeclType(const TagDecl *Decl) const { + assert (Decl); + // FIXME: What is the design on getTagDeclType when it requires casting + // away const? mutable? + return getTypeDeclType(const_cast<TagDecl*>(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>. +CanQualType 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 +//===----------------------------------------------------------------------===// + +CanQualType ASTContext::getCanonicalParamType(QualType T) const { + // Push qualifiers into arrays, and then discard any remaining + // qualifiers. + T = getCanonicalType(T); + T = getVariableArrayDecayedType(T); + const Type *Ty = T.getTypePtr(); + QualType Result; + if (isa<ArrayType>(Ty)) { + Result = getArrayDecayedType(QualType(Ty,0)); + } else if (isa<FunctionType>(Ty)) { + Result = getPointerType(QualType(Ty, 0)); + } else { + Result = QualType(Ty, 0); + } + + return CanQualType::CreateUnsafe(Result); +} + + +QualType ASTContext::getUnqualifiedArrayType(QualType type, + Qualifiers &quals) { + SplitQualType splitType = type.getSplitUnqualifiedType(); + + // FIXME: getSplitUnqualifiedType() actually walks all the way to + // the unqualified desugared type and then drops it on the floor. + // We then have to strip that sugar back off with + // getUnqualifiedDesugaredType(), which is silly. + const ArrayType *AT = + dyn_cast<ArrayType>(splitType.first->getUnqualifiedDesugaredType()); + + // If we don't have an array, just use the results in splitType. + if (!AT) { + quals = splitType.second; + return QualType(splitType.first, 0); + } + + // Otherwise, recurse on the array's element type. + QualType elementType = AT->getElementType(); + QualType unqualElementType = getUnqualifiedArrayType(elementType, quals); + + // If that didn't change the element type, AT has no qualifiers, so we + // can just use the results in splitType. + if (elementType == unqualElementType) { + assert(quals.empty()); // from the recursive call + quals = splitType.second; + return QualType(splitType.first, 0); + } + + // Otherwise, add in the qualifiers from the outermost type, then + // build the type back up. + quals.addConsistentQualifiers(splitType.second); + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(AT)) { + return getConstantArrayType(unqualElementType, CAT->getSize(), + CAT->getSizeModifier(), 0); + } + + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(AT)) { + return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0); + } + + if (const VariableArrayType *VAT = dyn_cast<VariableArrayType>(AT)) { + return getVariableArrayType(unqualElementType, + VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange()); + } + + const DependentSizedArrayType *DSAT = cast<DependentSizedArrayType>(AT); + return getDependentSizedArrayType(unqualElementType, DSAT->getSizeExpr(), + DSAT->getSizeModifier(), 0, + SourceRange()); +} + +/// UnwrapSimilarPointerTypes - If T1 and T2 are pointer types that +/// may be similar (C++ 4.4), replaces T1 and T2 with the type that +/// they point to and return true. If T1 and T2 aren't pointer types +/// or pointer-to-member types, or if they are not similar at this +/// level, returns false and leaves T1 and T2 unchanged. Top-level +/// qualifiers on T1 and T2 are ignored. This function will typically +/// be called in a loop that successively "unwraps" pointer and +/// pointer-to-member types to compare them at each level. +bool ASTContext::UnwrapSimilarPointerTypes(QualType &T1, QualType &T2) { + const PointerType *T1PtrType = T1->getAs<PointerType>(), + *T2PtrType = T2->getAs<PointerType>(); + if (T1PtrType && T2PtrType) { + T1 = T1PtrType->getPointeeType(); + T2 = T2PtrType->getPointeeType(); + return true; + } + + const MemberPointerType *T1MPType = T1->getAs<MemberPointerType>(), + *T2MPType = T2->getAs<MemberPointerType>(); + if (T1MPType && T2MPType && + hasSameUnqualifiedType(QualType(T1MPType->getClass(), 0), + QualType(T2MPType->getClass(), 0))) { + T1 = T1MPType->getPointeeType(); + T2 = T2MPType->getPointeeType(); + return true; + } + + if (getLangOptions().ObjC1) { + const ObjCObjectPointerType *T1OPType = T1->getAs<ObjCObjectPointerType>(), + *T2OPType = T2->getAs<ObjCObjectPointerType>(); + if (T1OPType && T2OPType) { + T1 = T1OPType->getPointeeType(); + T2 = T2OPType->getPointeeType(); + return true; + } + } + + // FIXME: Block pointers, too? + + return false; +} + +DeclarationNameInfo +ASTContext::getNameForTemplate(TemplateName Name, + SourceLocation NameLoc) const { + if (TemplateDecl *TD = Name.getAsTemplateDecl()) + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo(TD->getDeclName(), NameLoc); + + if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) { + DeclarationName DName; + if (DTN->isIdentifier()) { + DName = DeclarationNames.getIdentifier(DTN->getIdentifier()); + return DeclarationNameInfo(DName, NameLoc); + } else { + DName = DeclarationNames.getCXXOperatorName(DTN->getOperator()); + // DNInfo work in progress: FIXME: source locations? + DeclarationNameLoc DNLoc; + DNLoc.CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); + DNLoc.CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); + return DeclarationNameInfo(DName, NameLoc, DNLoc); + } + } + + OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); + assert(Storage); + // DNInfo work in progress: CHECKME: what about DNLoc? + return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); +} + +TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) + Template = getCanonicalTemplateTemplateParmDecl(TTP); + + // The canonical template name is the canonical template declaration. + return TemplateName(cast<TemplateDecl>(Template->getCanonicalDecl())); + } + + if (SubstTemplateTemplateParmPackStorage *SubstPack + = Name.getAsSubstTemplateTemplateParmPack()) { + TemplateTemplateParmDecl *CanonParam + = getCanonicalTemplateTemplateParmDecl(SubstPack->getParameterPack()); + TemplateArgument CanonArgPack + = getCanonicalTemplateArgument(SubstPack->getArgumentPack()); + return getSubstTemplateTemplateParmPack(CanonParam, CanonArgPack); + } + + assert(!Name.getAsOverloadedTemplate()); + + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + assert(DTN && "Non-dependent template names must refer to template decls."); + return DTN->CanonicalTemplateName; +} + +bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { + X = getCanonicalTemplateName(X); + Y = getCanonicalTemplateName(Y); + return X.getAsVoidPointer() == Y.getAsVoidPointer(); +} + +TemplateArgument +ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { + switch (Arg.getKind()) { + case TemplateArgument::Null: + return Arg; + + case TemplateArgument::Expression: + return Arg; + + case TemplateArgument::Declaration: + return TemplateArgument(Arg.getAsDecl()->getCanonicalDecl()); + + case TemplateArgument::Template: + return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); + + case TemplateArgument::TemplateExpansion: + return TemplateArgument(getCanonicalTemplateName( + Arg.getAsTemplateOrTemplatePattern()), + Arg.getNumTemplateExpansions()); + + case TemplateArgument::Integral: + return TemplateArgument(*Arg.getAsIntegral(), + getCanonicalType(Arg.getIntegralType())); + + case TemplateArgument::Type: + return TemplateArgument(getCanonicalType(Arg.getAsType())); + + case TemplateArgument::Pack: { + if (Arg.pack_size() == 0) + return Arg; + + TemplateArgument *CanonArgs + = new (*this) TemplateArgument[Arg.pack_size()]; + unsigned Idx = 0; + for (TemplateArgument::pack_iterator A = Arg.pack_begin(), + AEnd = Arg.pack_end(); + A != AEnd; (void)++A, ++Idx) + CanonArgs[Idx] = getCanonicalTemplateArgument(*A); + + return TemplateArgument(CanonArgs, Arg.pack_size()); + } + } + + // Silence GCC warning + assert(false && "Unhandled template argument kind"); + return TemplateArgument(); +} + +NestedNameSpecifier * +ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { + 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()->getOriginalNamespace()); + + case NestedNameSpecifier::NamespaceAlias: + // A namespace is canonical; build a nested-name-specifier with + // this namespace and no prefix. + return NestedNameSpecifier::Create(*this, 0, + NNS->getAsNamespaceAlias()->getNamespace() + ->getOriginalNamespace()); + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); + + // If we have some kind of dependent-named type (e.g., "typename T::type"), + // break it apart into its prefix and identifier, then reconsititute those + // as the canonical nested-name-specifier. This is required to canonicalize + // a dependent nested-name-specifier involving typedefs of dependent-name + // types, e.g., + // typedef typename T::type T1; + // typedef typename T1::type T2; + if (const DependentNameType *DNT = T->getAs<DependentNameType>()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DNT->getQualifier()); + return NestedNameSpecifier::Create(*this, Prefix, + const_cast<IdentifierInfo *>(DNT->getIdentifier())); + } + + // Do the same thing as above, but with dependent-named specializations. + if (const DependentTemplateSpecializationType *DTST + = T->getAs<DependentTemplateSpecializationType>()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DTST->getQualifier()); + + T = getDependentTemplateSpecializationType(DTST->getKeyword(), + Prefix, DTST->getIdentifier(), + DTST->getNumArgs(), + DTST->getArgs()); + T = getCanonicalType(T); + } + + return NestedNameSpecifier::Create(*this, 0, false, + const_cast<Type*>(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) const { + // Handle the non-qualified case efficiently. + if (!T.hasLocalQualifiers()) { + // Handle the common positive case fast. + if (const ArrayType *AT = dyn_cast<ArrayType>(T)) + return AT; + } + + // Handle the common negative case fast. + if (!isa<ArrayType>(T.getCanonicalType())) + return 0; + + // Apply any 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 element type. + + SplitQualType split = T.getSplitDesugaredType(); + Qualifiers qs = split.second; + + // If we have a simple case, just return now. + const ArrayType *ATy = dyn_cast<ArrayType>(split.first); + if (ATy == 0 || qs.empty()) + 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. + QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs); + + if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(ATy)) + return cast<ArrayType>(getConstantArrayType(NewEltTy, CAT->getSize(), + CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers())); + if (const IncompleteArrayType *IAT = dyn_cast<IncompleteArrayType>(ATy)) + return cast<ArrayType>(getIncompleteArrayType(NewEltTy, + IAT->getSizeModifier(), + IAT->getIndexTypeCVRQualifiers())); + + if (const DependentSizedArrayType *DSAT + = dyn_cast<DependentSizedArrayType>(ATy)) + return cast<ArrayType>( + getDependentSizedArrayType(NewEltTy, + DSAT->getSizeExpr(), + DSAT->getSizeModifier(), + DSAT->getIndexTypeCVRQualifiers(), + DSAT->getBracketsRange())); + + const VariableArrayType *VAT = cast<VariableArrayType>(ATy); + return cast<ArrayType>(getVariableArrayType(NewEltTy, + VAT->getSizeExpr(), + VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), + VAT->getBracketsRange())); +} + +/// 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) const { + // 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 getQualifiedType(PtrTy, PrettyArrayType->getIndexTypeQualifiers()); +} + +QualType ASTContext::getBaseElementType(const ArrayType *array) const { + return getBaseElementType(array->getElementType()); +} + +QualType ASTContext::getBaseElementType(QualType type) const { + Qualifiers qs; + while (true) { + SplitQualType split = type.getSplitDesugaredType(); + const ArrayType *array = split.first->getAsArrayTypeUnsafe(); + if (!array) break; + + type = array->getElementType(); + qs.addConsistentQualifiers(split.second); + } + + return getQualifiedType(type, qs); +} + +/// getConstantArrayElementCount - Returns number of constant array elements. +uint64_t +ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { + uint64_t ElementCount = 1; + do { + ElementCount *= CA->getSize().getZExtValue(); + CA = dyn_cast<ConstantArrayType>(CA->getElementType()); + } while (CA); + return ElementCount; +} + +/// 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->getAs<ComplexType>()) + return getFloatingRank(CT->getElementType()); + + assert(T->getAs<BuiltinType>() && "getFloatingRank(): not a floating type"); + switch (T->getAs<BuiltinType>()->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) const { + 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(const Type *T) const { + assert(T->isCanonicalUnqualified() && "T should be canonicalized"); + if (const EnumType* ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getPromotionType().getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::WChar_S) || + T->isSpecificBuiltinType(BuiltinType::WChar_U)) + T = getFromTargetType(Target.getWCharType()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char16)) + T = getFromTargetType(Target.getChar16Type()).getTypePtr(); + + if (T->isSpecificBuiltinType(BuiltinType::Char32)) + T = getFromTargetType(Target.getChar32Type()).getTypePtr(); + + 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); + } +} + +/// \brief Whether this is a promotable bitfield reference according +/// to C99 6.3.1.1p2, bullet 2 (and GCC extensions). +/// +/// \returns the type this bit-field will promote to, or NULL if no +/// promotion occurs. +QualType ASTContext::isPromotableBitField(Expr *E) const { + if (E->isTypeDependent() || E->isValueDependent()) + return QualType(); + + FieldDecl *Field = E->getBitField(); + if (!Field) + return QualType(); + + QualType FT = Field->getType(); + + llvm::APSInt BitWidthAP = Field->getBitWidth()->EvaluateAsInt(*this); + uint64_t BitWidth = BitWidthAP.getZExtValue(); + uint64_t IntSize = getTypeSize(IntTy); + // GCC extension compatibility: if the bit-field size is less than or equal + // to the size of int, it gets promoted no matter what its type is. + // For instance, unsigned long bf : 4 gets promoted to signed int. + if (BitWidth < IntSize) + return IntTy; + + if (BitWidth == IntSize) + return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy; + + // Types bigger than int are not subject to promotions, and therefore act + // like the base type. + // FIXME: This doesn't quite match what gcc does, but what gcc does here + // is ridiculous. + return QualType(); +} + +/// getPromotedIntegerType - Returns the type that Promotable will +/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable +/// integer type. +QualType ASTContext::getPromotedIntegerType(QualType Promotable) const { + assert(!Promotable.isNull()); + assert(Promotable->isPromotableIntegerType()); + if (const EnumType *ET = Promotable->getAs<EnumType>()) + return ET->getDecl()->getPromotionType(); + if (Promotable->isSignedIntegerType()) + return IntTy; + uint64_t PromotableSize = getTypeSize(Promotable); + uint64_t IntSize = getTypeSize(IntTy); + assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize); + return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy; +} + +/// 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) const { + const Type *LHSC = getCanonicalType(LHS).getTypePtr(); + const 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; +} + +static RecordDecl * +CreateRecordDecl(const ASTContext &Ctx, RecordDecl::TagKind TK, + DeclContext *DC, IdentifierInfo *Id) { + SourceLocation Loc; + if (Ctx.getLangOptions().CPlusPlus) + return CXXRecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); + else + return RecordDecl::Create(Ctx, TK, DC, Loc, Loc, Id); +} + +// getCFConstantStringType - Return the type used for constant CFStrings. +QualType ASTContext::getCFConstantStringType() const { + if (!CFConstantStringTypeDecl) { + CFConstantStringTypeDecl = + CreateRecordDecl(*this, TTK_Struct, TUDecl, + &Idents.get("NSConstantString")); + CFConstantStringTypeDecl->startDefinition(); + + QualType FieldTypes[4]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.withConst()); + // int flags; + FieldTypes[1] = IntTy; + // const char *str; + FieldTypes[2] = getPointerType(CharTy.withConst()); + // long length; + FieldTypes[3] = LongTy; + + // Create fields + for (unsigned i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, CFConstantStringTypeDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + CFConstantStringTypeDecl->addDecl(Field); + } + + CFConstantStringTypeDecl->completeDefinition(); + } + + return getTagDeclType(CFConstantStringTypeDecl); +} + +void ASTContext::setCFConstantStringType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid CFConstantStringType"); + CFConstantStringTypeDecl = Rec->getDecl(); +} + +// getNSConstantStringType - Return the type used for constant NSStrings. +QualType ASTContext::getNSConstantStringType() const { + if (!NSConstantStringTypeDecl) { + NSConstantStringTypeDecl = + CreateRecordDecl(*this, TTK_Struct, TUDecl, + &Idents.get("__builtin_NSString")); + NSConstantStringTypeDecl->startDefinition(); + + QualType FieldTypes[3]; + + // const int *isa; + FieldTypes[0] = getPointerType(IntTy.withConst()); + // const char *str; + FieldTypes[1] = getPointerType(CharTy.withConst()); + // unsigned int length; + FieldTypes[2] = UnsignedIntTy; + + // Create fields + for (unsigned i = 0; i < 3; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, NSConstantStringTypeDecl, + SourceLocation(), + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + NSConstantStringTypeDecl->addDecl(Field); + } + + NSConstantStringTypeDecl->completeDefinition(); + } + + return getTagDeclType(NSConstantStringTypeDecl); +} + +void ASTContext::setNSConstantStringType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid NSConstantStringType"); + NSConstantStringTypeDecl = Rec->getDecl(); +} + +QualType ASTContext::getObjCFastEnumerationStateType() const { + if (!ObjCFastEnumerationStateTypeDecl) { + ObjCFastEnumerationStateTypeDecl = + CreateRecordDecl(*this, TTK_Struct, TUDecl, + &Idents.get("__objcFastEnumerationState")); + ObjCFastEnumerationStateTypeDecl->startDefinition(); + + QualType FieldTypes[] = { + UnsignedLongTy, + getPointerType(ObjCIdTypedefType), + 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(), + SourceLocation(), 0, + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + ObjCFastEnumerationStateTypeDecl->addDecl(Field); + } + + ObjCFastEnumerationStateTypeDecl->completeDefinition(); + } + + return getTagDeclType(ObjCFastEnumerationStateTypeDecl); +} + +QualType ASTContext::getBlockDescriptorType() const { + if (BlockDescriptorType) + return getTagDeclType(BlockDescriptorType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, + &Idents.get("__block_descriptor")); + T->startDefinition(); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + }; + + const char *FieldNames[] = { + "reserved", + "Size" + }; + + for (size_t i = 0; i < 2; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + T->addDecl(Field); + } + + T->completeDefinition(); + + BlockDescriptorType = T; + + return getTagDeclType(BlockDescriptorType); +} + +void ASTContext::setBlockDescriptorType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorType = Rec->getDecl(); +} + +QualType ASTContext::getBlockDescriptorExtendedType() const { + if (BlockDescriptorExtendedType) + return getTagDeclType(BlockDescriptorExtendedType); + + RecordDecl *T; + // FIXME: Needs the FlagAppleBlock bit. + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, + &Idents.get("__block_descriptor_withcopydispose")); + T->startDefinition(); + + QualType FieldTypes[] = { + UnsignedLongTy, + UnsignedLongTy, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy) + }; + + const char *FieldNames[] = { + "reserved", + "Size", + "CopyFuncPtr", + "DestroyFuncPtr" + }; + + for (size_t i = 0; i < 4; ++i) { + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + T->addDecl(Field); + } + + T->completeDefinition(); + + BlockDescriptorExtendedType = T; + + return getTagDeclType(BlockDescriptorExtendedType); +} + +void ASTContext::setBlockDescriptorExtendedType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + assert(Rec && "Invalid BlockDescriptorType"); + BlockDescriptorExtendedType = Rec->getDecl(); +} + +bool ASTContext::BlockRequiresCopying(QualType Ty) const { + if (Ty->isBlockPointerType()) + return true; + if (isObjCNSObjectType(Ty)) + return true; + if (Ty->isObjCObjectPointerType()) + return true; + if (getLangOptions().CPlusPlus) { + if (const RecordType *RT = Ty->getAs<RecordType>()) { + CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + return RD->hasConstCopyConstructor(); + + } + } + return false; +} + +QualType +ASTContext::BuildByRefType(llvm::StringRef DeclName, QualType Ty) const { + // type = struct __Block_byref_1_X { + // void *__isa; + // struct __Block_byref_1_X *__forwarding; + // unsigned int __flags; + // unsigned int __size; + // void *__copy_helper; // as needed + // void *__destroy_help // as needed + // int X; + // } * + + bool HasCopyAndDispose = BlockRequiresCopying(Ty); + + // FIXME: Move up + llvm::SmallString<36> Name; + llvm::raw_svector_ostream(Name) << "__Block_byref_" << + ++UniqueBlockByRefTypeID << '_' << DeclName; + RecordDecl *T; + T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str())); + T->startDefinition(); + QualType Int32Ty = IntTy; + assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); + QualType FieldTypes[] = { + getPointerType(VoidPtrTy), + getPointerType(getTagDeclType(T)), + Int32Ty, + Int32Ty, + getPointerType(VoidPtrTy), + getPointerType(VoidPtrTy), + Ty + }; + + llvm::StringRef FieldNames[] = { + "__isa", + "__forwarding", + "__flags", + "__size", + "__copy_helper", + "__destroy_helper", + DeclName, + }; + + for (size_t i = 0; i < 7; ++i) { + if (!HasCopyAndDispose && i >=4 && i <= 5) + continue; + FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), + SourceLocation(), + &Idents.get(FieldNames[i]), + FieldTypes[i], /*TInfo=*/0, + /*BitWidth=*/0, /*Mutable=*/false, + /*HasInit=*/false); + Field->setAccess(AS_public); + T->addDecl(Field); + } + + T->completeDefinition(); + + return getPointerType(getTagDeclType(T)); +} + +void ASTContext::setObjCFastEnumerationStateType(QualType T) { + const RecordType *Rec = T->getAs<RecordType>(); + 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. +CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const { + if (!type->isIncompleteArrayType() && type->isIncompleteType()) + return CharUnits::Zero(); + + CharUnits sz = getTypeSizeInChars(type); + + // Make all integer and enum types at least as large as an int + if (sz.isPositive() && type->isIntegralOrEnumerationType()) + sz = std::max(sz, getTypeSizeInChars(IntTy)); + // Treat arrays as pointers, since that's how they're passed in. + else if (type->isArrayType()) + sz = getTypeSizeInChars(VoidPtrTy); + return sz; +} + +static inline +std::string charUnitsToString(const CharUnits &CU) { + return llvm::itostr(CU.getQuantity()); +} + +/// getObjCEncodingForBlock - Return the encoded type for this block +/// declaration. +std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { + std::string S; + + const BlockDecl *Decl = Expr->getBlockDecl(); + QualType BlockTy = + Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); + // Encode result type. + getObjCEncodingForType(BlockTy->getAs<FunctionType>()->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; + CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); + CharUnits ParmOffset = PtrSize; + for (BlockDecl::param_const_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + QualType PType = (*PI)->getType(); + CharUnits sz = getObjCEncodingTypeSize(PType); + assert (sz.isPositive() && "BlockExpr - Incomplete param type"); + ParmOffset += sz; + } + // Size of the argument frame + S += charUnitsToString(ParmOffset); + // Block pointer and offset. + S += "@?0"; + ParmOffset = PtrSize; + + // Argument types. + ParmOffset = PtrSize; + for (BlockDecl::param_const_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(); + getObjCEncodingForType(PType, S); + S += charUnitsToString(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } + + return S; +} + +bool ASTContext::getObjCEncodingForFunctionDecl(const FunctionDecl *Decl, + std::string& S) { + // Encode result type. + getObjCEncodingForType(Decl->getResultType(), S); + CharUnits ParmOffset; + // Compute size of all parameters. + for (FunctionDecl::param_const_iterator PI = Decl->param_begin(), + E = Decl->param_end(); PI != E; ++PI) { + QualType PType = (*PI)->getType(); + CharUnits sz = getObjCEncodingTypeSize(PType); + if (sz.isZero()) + return true; + + assert (sz.isPositive() && + "getObjCEncodingForFunctionDecl - Incomplete param type"); + ParmOffset += sz; + } + S += charUnitsToString(ParmOffset); + ParmOffset = CharUnits::Zero(); + + // Argument types. + for (FunctionDecl::param_const_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(); + getObjCEncodingForType(PType, S); + S += charUnitsToString(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } + + return false; +} + +/// getObjCEncodingForMethodDecl - Return the encoded type for this method +/// declaration. +bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, + std::string& S) const { + // 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; + CharUnits PtrSize = getTypeSizeInChars(VoidPtrTy); + // The first two arguments (self and _cmd) are pointers; account for + // their size. + CharUnits ParmOffset = 2 * PtrSize; + for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + E = Decl->sel_param_end(); PI != E; ++PI) { + QualType PType = (*PI)->getType(); + CharUnits sz = getObjCEncodingTypeSize(PType); + if (sz.isZero()) + return true; + + assert (sz.isPositive() && + "getObjCEncodingForMethodDecl - Incomplete param type"); + ParmOffset += sz; + } + S += charUnitsToString(ParmOffset); + S += "@0:"; + S += charUnitsToString(PtrSize); + + // Argument types. + ParmOffset = 2 * PtrSize; + for (ObjCMethodDecl::param_iterator PI = Decl->param_begin(), + E = Decl->sel_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 += charUnitsToString(ParmOffset); + ParmOffset += getObjCEncodingTypeSize(PType); + } + + return false; +} + +/// 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) const { + // 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(), e = CID->propimpl_end(); + 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(), e = OID->propimpl_end(); + 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 (isa<TypedefType>(PointeeTy.getTypePtr())) { + if (const BuiltinType *BT = PointeeTy->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::ULong && getIntWidth(PointeeTy) == 32) + PointeeTy = UnsignedIntTy; + else + if (BT->getKind() == BuiltinType::Long && getIntWidth(PointeeTy) == 32) + PointeeTy = IntTy; + } + } +} + +void ASTContext::getObjCEncodingForType(QualType T, std::string& S, + const FieldDecl *Field) const { + // We follow the behavior of gcc, expanding structures which are + // directly pointed to, and expanding embedded structures. Note that + // these rules are sufficient to prevent recursive encoding of the + // same type. + getObjCEncodingForTypeImpl(T, S, true, true, Field, + true /* outermost type */); +} + +static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) { + switch (T->getAs<BuiltinType>()->getKind()) { + default: assert(0 && "Unhandled builtin type kind"); + case BuiltinType::Void: return 'v'; + case BuiltinType::Bool: return 'B'; + case BuiltinType::Char_U: + case BuiltinType::UChar: return 'C'; + case BuiltinType::UShort: return 'S'; + case BuiltinType::UInt: return 'I'; + case BuiltinType::ULong: + return C->getIntWidth(T) == 32 ? 'L' : 'Q'; + case BuiltinType::UInt128: return 'T'; + case BuiltinType::ULongLong: return 'Q'; + case BuiltinType::Char_S: + case BuiltinType::SChar: return 'c'; + case BuiltinType::Short: return 's'; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + case BuiltinType::Int: return 'i'; + case BuiltinType::Long: + return C->getIntWidth(T) == 32 ? 'l' : 'q'; + case BuiltinType::LongLong: return 'q'; + case BuiltinType::Int128: return 't'; + case BuiltinType::Float: return 'f'; + case BuiltinType::Double: return 'd'; + case BuiltinType::LongDouble: return 'D'; + } +} + +static void EncodeBitField(const ASTContext *Ctx, std::string& S, + QualType T, const FieldDecl *FD) { + const Expr *E = FD->getBitWidth(); + assert(E && "bitfield width not there - getObjCEncodingForTypeImpl"); + S += 'b'; + // The NeXT runtime encodes bit fields as b followed by the number of bits. + // The GNU runtime requires more information; bitfields are encoded as b, + // then the offset (in bits) of the first element, then the type of the + // bitfield, then the size in bits. For example, in this structure: + // + // struct + // { + // int integer; + // int flags:2; + // }; + // On a 32-bit system, the encoding for flags would be b2 for the NeXT + // runtime, but b32i2 for the GNU runtime. The reason for this extra + // information is not especially sensible, but we're stuck with it for + // compatibility with GCC, although providing it breaks anything that + // actually uses runtime introspection and wants to work on both runtimes... + if (!Ctx->getLangOptions().NeXTRuntime) { + const RecordDecl *RD = FD->getParent(); + const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); + // FIXME: This same linear search is also used in ExprConstant - it might + // be better if the FieldDecl stored its offset. We'd be increasing the + // size of the object slightly, but saving some time every time it is used. + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) + break; + } + S += llvm::utostr(RL.getFieldOffset(i)); + if (T->isEnumeralType()) + S += 'i'; + else + S += ObjCEncodingForPrimitiveKind(Ctx, T); + } + unsigned N = E->EvaluateAsInt(*Ctx).getZExtValue(); + S += llvm::utostr(N); +} + +// FIXME: Use SmallString for accumulating string. +void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, + bool ExpandPointedToStructures, + bool ExpandStructures, + const FieldDecl *FD, + bool OutermostType, + bool EncodingProperty, + bool StructField) const { + if (T->getAs<BuiltinType>()) { + if (FD && FD->isBitField()) + return EncodeBitField(this, S, T, FD); + S += ObjCEncodingForPrimitiveKind(this, T); + return; + } + + if (const ComplexType *CT = T->getAs<ComplexType>()) { + S += 'j'; + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false, + false); + return; + } + + // encoding for pointer or r3eference types. + QualType PointeeTy; + if (const PointerType *PT = T->getAs<PointerType>()) { + if (PT->isObjCSelType()) { + S += ':'; + return; + } + PointeeTy = PT->getPointeeType(); + } + else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + PointeeTy = RT->getPointeeType(); + if (!PointeeTy.isNull()) { + 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 (isa<TypedefType>(T.getTypePtr())) { + if (OutermostType && T.isConstQualified()) { + isReadOnly = true; + S += 'r'; + } + } else if (OutermostType) { + QualType P = PointeeTy; + while (P->getAs<PointerType>()) + P = P->getAs<PointerType>()->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" + if (llvm::StringRef(S).endswith("nr")) + S.replace(S.end()-2, S.end(), "rn"); + } + + 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; + } + } else if (const RecordType *RTy = PointeeTy->getAs<RecordType>()) { + // GCC binary compat: Need to convert "struct objc_class *" to "#". + if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_class")) { + S += '#'; + return; + } + // GCC binary compat: Need to convert "struct objc_object *" to "@". + if (RTy->getDecl()->getIdentifier() == &Idents.get("objc_object")) { + S += '@'; + return; + } + // fall through... + } + S += '^'; + getLegacyIntegralTypeEncoding(PointeeTy); + + getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, + NULL); + return; + } + + if (const ArrayType *AT = + // Ignore type qualifiers etc. + dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) { + if (isa<IncompleteArrayType>(AT) && !StructField) { + // 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)) { + if (getTypeSize(CAT->getElementType()) == 0) + S += '0'; + else + S += llvm::utostr(CAT->getSize().getZExtValue()); + } else { + //Variable length arrays are encoded as a regular array with 0 elements. + assert((isa<VariableArrayType>(AT) || isa<IncompleteArrayType>(AT)) && + "Unknown array type!"); + S += '0'; + } + + getObjCEncodingForTypeImpl(AT->getElementType(), S, + false, ExpandStructures, FD); + S += ']'; + } + return; + } + + if (T->getAs<FunctionType>()) { + S += '?'; + return; + } + + if (const RecordType *RTy = T->getAs<RecordType>()) { + RecordDecl *RDecl = RTy->getDecl(); + S += RDecl->isUnion() ? '(' : '{'; + // Anonymous structures print as '?' + if (const IdentifierInfo *II = RDecl->getIdentifier()) { + S += II->getName(); + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(RDecl)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.data(), + TemplateArgs.size(), + (*this).PrintingPolicy); + + S += TemplateArgsStr; + } + } else { + S += '?'; + } + if (ExpandStructures) { + S += '='; + if (!RDecl->isUnion()) { + getObjCEncodingForStructureImpl(RDecl, S, FD); + } else { + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + 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, /*OutermostType*/false, + /*EncodingProperty*/false, + /*StructField*/true); + } + } + } + } + S += RDecl->isUnion() ? ')' : '}'; + return; + } + + if (T->isEnumeralType()) { + if (FD && FD->isBitField()) + EncodeBitField(this, S, T, FD); + else + S += 'i'; + return; + } + + if (T->isBlockPointerType()) { + S += "@?"; // Unlike a pointer-to-function, which is "^?". + return; + } + + // Ignore protocol qualifiers when mangling at this level. + if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>()) + T = OT->getBaseType(); + + if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) { + // @encode(class_name) + ObjCInterfaceDecl *OI = OIT->getDecl(); + S += '{'; + const IdentifierInfo *II = OI->getIdentifier(); + S += II->getName(); + S += '='; + llvm::SmallVector<ObjCIvarDecl*, 32> Ivars; + DeepCollectObjCIvars(OI, true, Ivars); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) { + FieldDecl *Field = cast<FieldDecl>(Ivars[i]); + if (Field->isBitField()) + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, Field); + else + getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD); + } + S += '}'; + return; + } + + if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) { + if (OPT->isObjCIdType()) { + S += '@'; + return; + } + + if (OPT->isObjCClassType() || OPT->isObjCQualifiedClassType()) { + // FIXME: Consider if we need to output qualifiers for 'Class<p>'. + // Since this is a binary compatibility issue, need to consult with runtime + // folks. Fortunately, this is a *very* obsure construct. + S += '#'; + return; + } + + if (OPT->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. + S += '"'; + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + QualType PointeeTy = OPT->getPointeeType(); + 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 (OPT->getInterfaceDecl() && (FD || EncodingProperty)) { + S += '"'; + S += OPT->getInterfaceDecl()->getIdentifier()->getName(); + for (ObjCObjectPointerType::qual_iterator I = OPT->qual_begin(), + E = OPT->qual_end(); I != E; ++I) { + S += '<'; + S += (*I)->getNameAsString(); + S += '>'; + } + S += '"'; + } + return; + } + + // gcc just blithely ignores member pointers. + // TODO: maybe there should be a mangling for these + if (T->getAs<MemberPointerType>()) + return; + + if (T->isVectorType()) { + // This matches gcc's encoding, even though technically it is + // insufficient. + // FIXME. We should do a better job than gcc. + return; + } + + assert(0 && "@encode for type not implemented!"); +} + +void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, + std::string &S, + const FieldDecl *FD, + bool includeVBases) const { + assert(RDecl && "Expected non-null RecordDecl"); + assert(!RDecl->isUnion() && "Should not be called for unions"); + if (!RDecl->getDefinition()) + return; + + CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(RDecl); + std::multimap<uint64_t, NamedDecl *> FieldOrBaseOffsets; + const ASTRecordLayout &layout = getASTRecordLayout(RDecl); + + if (CXXRec) { + for (CXXRecordDecl::base_class_iterator + BI = CXXRec->bases_begin(), + BE = CXXRec->bases_end(); BI != BE; ++BI) { + if (!BI->isVirtual()) { + CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + uint64_t offs = layout.getBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + } + + unsigned i = 0; + for (RecordDecl::field_iterator Field = RDecl->field_begin(), + FieldEnd = RDecl->field_end(); + Field != FieldEnd; ++Field, ++i) { + uint64_t offs = layout.getFieldOffset(i); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, *Field)); + } + + if (CXXRec && includeVBases) { + for (CXXRecordDecl::base_class_iterator + BI = CXXRec->vbases_begin(), + BE = CXXRec->vbases_end(); BI != BE; ++BI) { + CXXRecordDecl *base = BI->getType()->getAsCXXRecordDecl(); + uint64_t offs = layout.getVBaseClassOffsetInBits(base); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, base)); + } + } + + CharUnits size; + if (CXXRec) { + size = includeVBases ? layout.getSize() : layout.getNonVirtualSize(); + } else { + size = layout.getSize(); + } + + uint64_t CurOffs = 0; + std::multimap<uint64_t, NamedDecl *>::iterator + CurLayObj = FieldOrBaseOffsets.begin(); + + if (CurLayObj != FieldOrBaseOffsets.end() && CurLayObj->first != 0) { + assert(CXXRec && CXXRec->isDynamicClass() && + "Offset 0 was empty but no VTable ?"); + if (FD) { + S += "\"_vptr$"; + std::string recname = CXXRec->getNameAsString(); + if (recname.empty()) recname = "?"; + S += recname; + S += '"'; + } + S += "^^?"; + CurOffs += getTypeSize(VoidPtrTy); + } + + if (!RDecl->hasFlexibleArrayMember()) { + // Mark the end of the structure. + uint64_t offs = toBits(size); + FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), + std::make_pair(offs, (NamedDecl*)0)); + } + + for (; CurLayObj != FieldOrBaseOffsets.end(); ++CurLayObj) { + assert(CurOffs <= CurLayObj->first); + + if (CurOffs < CurLayObj->first) { + uint64_t padding = CurLayObj->first - CurOffs; + // FIXME: There doesn't seem to be a way to indicate in the encoding that + // packing/alignment of members is different that normal, in which case + // the encoding will be out-of-sync with the real layout. + // If the runtime switches to just consider the size of types without + // taking into account alignment, we could make padding explicit in the + // encoding (e.g. using arrays of chars). The encoding strings would be + // longer then though. + CurOffs += padding; + } + + NamedDecl *dcl = CurLayObj->second; + if (dcl == 0) + break; // reached end of structure. + + if (CXXRecordDecl *base = dyn_cast<CXXRecordDecl>(dcl)) { + // We expand the bases without their virtual bases since those are going + // in the initial structure. Note that this differs from gcc which + // expands virtual bases each time one is encountered in the hierarchy, + // making the encoding type bigger than it really is. + getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false); + if (!base->isEmpty()) + CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); + } else { + FieldDecl *field = cast<FieldDecl>(dcl); + if (FD) { + S += '"'; + S += field->getNameAsString(); + S += '"'; + } + + if (field->isBitField()) { + EncodeBitField(this, S, field->getType(), field); + CurOffs += field->getBitWidth()->EvaluateAsInt(*this).getZExtValue(); + } else { + QualType qt = field->getType(); + getLegacyIntegralTypeEncoding(qt); + getObjCEncodingForTypeImpl(qt, S, false, true, FD, + /*OutermostType*/false, + /*EncodingProperty*/false, + /*StructField*/true); + CurOffs += getTypeSize(field->getType()); + } + } + } +} + +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) { + ObjCIdTypedefType = T; +} + +void ASTContext::setObjCSelType(QualType T) { + ObjCSelTypedefType = T; +} + +void ASTContext::setObjCProtoType(QualType QT) { + ObjCProtoType = QT; +} + +void ASTContext::setObjCClassType(QualType T) { + ObjCClassTypedefType = T; +} + +void ASTContext::setObjCConstantStringInterface(ObjCInterfaceDecl *Decl) { + assert(ObjCConstantStringType.isNull() && + "'NSConstantString' type already set!"); + + ObjCConstantStringType = getObjCInterfaceType(Decl); +} + +/// \brief Retrieve the template name that corresponds to a non-empty +/// lookup. +TemplateName +ASTContext::getOverloadedTemplateName(UnresolvedSetIterator Begin, + UnresolvedSetIterator End) const { + unsigned size = End - Begin; + assert(size > 1 && "set is not overloaded!"); + + void *memory = Allocate(sizeof(OverloadedTemplateStorage) + + size * sizeof(FunctionTemplateDecl*)); + OverloadedTemplateStorage *OT = new(memory) OverloadedTemplateStorage(size); + + NamedDecl **Storage = OT->getStorage(); + for (UnresolvedSetIterator I = Begin; I != End; ++I) { + NamedDecl *D = *I; + assert(isa<FunctionTemplateDecl>(D) || + (isa<UsingShadowDecl>(D) && + isa<FunctionTemplateDecl>(D->getUnderlyingDecl()))); + *Storage++ = D; + } + + return TemplateName(OT); +} + +/// \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) const { + assert(NNS && "Missing nested-name-specifier in qualified template name"); + + // FIXME: Canonicalization? + 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) const { + assert((!NNS || 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); + DependentTemplateName *CheckQTN = + DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent type name canonicalization broken"); + (void)CheckQTN; + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + +/// \brief Retrieve the template name that represents a dependent +/// template name such as \c MetaFun::template operator+. +TemplateName +ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS, + OverloadedOperatorKind Operator) const { + assert((!NNS || NNS->isDependent()) && + "Nested name specifier must be dependent"); + + llvm::FoldingSetNodeID ID; + DependentTemplateName::Profile(ID, NNS, Operator); + + 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, Operator); + } else { + TemplateName Canon = getDependentTemplateName(CanonNNS, Operator); + QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon); + + DependentTemplateName *CheckQTN + = DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos); + assert(!CheckQTN && "Dependent template name canonicalization broken"); + (void)CheckQTN; + } + + DependentTemplateNames.InsertNode(QTN, InsertPos); + return TemplateName(QTN); +} + +TemplateName +ASTContext::getSubstTemplateTemplateParmPack(TemplateTemplateParmDecl *Param, + const TemplateArgument &ArgPack) const { + ASTContext &Self = const_cast<ASTContext &>(*this); + llvm::FoldingSetNodeID ID; + SubstTemplateTemplateParmPackStorage::Profile(ID, Self, Param, ArgPack); + + void *InsertPos = 0; + SubstTemplateTemplateParmPackStorage *Subst + = SubstTemplateTemplateParmPacks.FindNodeOrInsertPos(ID, InsertPos); + + if (!Subst) { + Subst = new (*this) SubstTemplateTemplateParmPackStorage(Self, Param, + ArgPack.pack_size(), + ArgPack.pack_begin()); + SubstTemplateTemplateParmPacks.InsertNode(Subst, InsertPos); + } + + return TemplateName(Subst); +} + +/// 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. +CanQualType ASTContext::getFromTargetType(unsigned Type) const { + switch (Type) { + case TargetInfo::NoInt: return CanQualType(); + 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 CanQualType(); +} + +//===----------------------------------------------------------------------===// +// 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. +/// FIXME: Move to Type. +/// +bool ASTContext::isObjCNSObjectType(QualType Ty) const { + if (const TypedefType *TDT = dyn_cast<TypedefType>(Ty)) { + if (TypedefNameDecl *TD = TDT->getDecl()) + if (TD->getAttr<ObjCNSObjectAttr>()) + return true; + } + return false; +} + +/// getObjCGCAttr - Returns one of GCNone, Weak or Strong objc's +/// garbage collection attribute. +/// +Qualifiers::GC ASTContext::getObjCGCAttrKind(QualType Ty) const { + if (getLangOptions().getGCMode() == LangOptions::NonGC) + return Qualifiers::GCNone; + + assert(getLangOptions().ObjC1); + Qualifiers::GC GCAttrs = Ty.getObjCGCAttr(); + + // Default behaviour under objective-C's gc is for ObjC pointers + // (or pointers to them) be treated as though they were declared + // as __strong. + if (GCAttrs == Qualifiers::GCNone) { + if (Ty->isObjCObjectPointerType() || Ty->isBlockPointerType()) + return Qualifiers::Strong; + else if (Ty->isPointerType()) + return getObjCGCAttrKind(Ty->getAs<PointerType>()->getPointeeType()); + } else { + // It's not valid to set GC attributes on anything that isn't a + // pointer. +#ifndef NDEBUG + QualType CT = Ty->getCanonicalTypeInternal(); + while (const ArrayType *AT = dyn_cast<ArrayType>(CT)) + CT = AT->getElementType(); + assert(CT->isAnyPointerType() || CT->isBlockPointerType()); +#endif + } + return GCAttrs; +} + +//===----------------------------------------------------------------------===// +// Type Compatibility Testing +//===----------------------------------------------------------------------===// + +/// areCompatVectorTypes - Return true if the two specified vector types are +/// compatible. +static bool areCompatVectorTypes(const VectorType *LHS, + const VectorType *RHS) { + assert(LHS->isCanonicalUnqualified() && RHS->isCanonicalUnqualified()); + return LHS->getElementType() == RHS->getElementType() && + LHS->getNumElements() == RHS->getNumElements(); +} + +bool ASTContext::areCompatibleVectorTypes(QualType FirstVec, + QualType SecondVec) { + assert(FirstVec->isVectorType() && "FirstVec should be a vector type"); + assert(SecondVec->isVectorType() && "SecondVec should be a vector type"); + + if (hasSameUnqualifiedType(FirstVec, SecondVec)) + return true; + + // Treat Neon vector types and most AltiVec vector types as if they are the + // equivalent GCC vector types. + const VectorType *First = FirstVec->getAs<VectorType>(); + const VectorType *Second = SecondVec->getAs<VectorType>(); + if (First->getNumElements() == Second->getNumElements() && + hasSameType(First->getElementType(), Second->getElementType()) && + First->getVectorKind() != VectorType::AltiVecPixel && + First->getVectorKind() != VectorType::AltiVecBool && + Second->getVectorKind() != VectorType::AltiVecPixel && + Second->getVectorKind() != VectorType::AltiVecBool) + return true; + + return false; +} + +//===----------------------------------------------------------------------===// +// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. +//===----------------------------------------------------------------------===// + +/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the +/// inheritance hierarchy of 'rProto'. +bool +ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, + ObjCProtocolDecl *rProto) const { + if (lProto == rProto) + return true; + for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), + E = rProto->protocol_end(); PI != E; ++PI) + if (ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + return false; +} + +/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...> +/// return true if lhs's protocols conform to rhs's protocol; false +/// otherwise. +bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { + if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false); + return false; +} + +/// ObjCQualifiedClassTypesAreCompatible - compare Class<p,...> and +/// Class<p1, ...>. +bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, + QualType rhs) { + const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + assert ((lhsQID && rhsOPT) && "ObjCQualifiedClassTypesAreCompatible"); + + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + bool match = false; + ObjCProtocolDecl *lhsProto = *I; + for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto)) { + match = true; + break; + } + } + if (!match) + return false; + } + return true; +} + +/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an +/// ObjCQualifiedIDType. +bool ASTContext::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, + bool compare) { + // Allow id<P..> and an 'id' or void* type in all cases. + if (lhs->isVoidPointerType() || + lhs->isObjCIdType() || lhs->isObjCClassType()) + return true; + else if (rhs->isVoidPointerType() || + rhs->isObjCIdType() || rhs->isObjCClassType()) + return true; + + if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) { + const ObjCObjectPointerType *rhsOPT = rhs->getAs<ObjCObjectPointerType>(); + + if (!rhsOPT) return false; + + if (rhsOPT->qual_empty()) { + // If the RHS is a unqualified interface pointer "NSString*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (!rhsID->ClassImplementsProtocol(*I, true)) + return false; + } + } + // If there are no qualifiers and no interface, we have an 'id'. + return true; + } + // Both the right and left sides have qualifiers. + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + ObjCProtocolDecl *lhsProto = *I; + bool match = false; + + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(), + E = rhsOPT->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + // If the RHS is a qualified interface pointer "NSString<P>*", + // make sure we check the class hierarchy. + if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) { + for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(), + E = lhsQID->qual_end(); I != E; ++I) { + // when comparing an id<P> on lhs with a static type on rhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + if (rhsID->ClassImplementsProtocol(*I, true)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + + return true; + } + + const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType(); + assert(rhsQID && "One of the LHS/RHS should be id<x>"); + + if (const ObjCObjectPointerType *lhsOPT = + lhs->getAsObjCInterfacePointerType()) { + // If both the right and left sides have qualifiers. + for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(), + E = lhsOPT->qual_end(); I != E; ++I) { + ObjCProtocolDecl *lhsProto = *I; + bool match = false; + + // when comparing an id<P> on rhs with a static type on lhs, + // see if static class implements all of id's protocols, directly or + // through its super class and categories. + // First, lhs protocols in the qualifier list must be found, direct + // or indirect in rhs's qualifier list or it is a mismatch. + for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), + E = rhsQID->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + + // Static class's protocols, or its super class or category protocols + // must be found, direct or indirect in rhs's qualifier list or it is a mismatch. + if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) { + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + CollectInheritedProtocols(lhsID, LHSInheritedProtocols); + // This is rather dubious but matches gcc's behavior. If lhs has + // no type qualifier and its class has no static protocol(s) + // assume that it is mismatch. + if (LHSInheritedProtocols.empty() && lhsOPT->qual_empty()) + return false; + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + LHSInheritedProtocols.begin(), + E = LHSInheritedProtocols.end(); I != E; ++I) { + bool match = false; + ObjCProtocolDecl *lhsProto = (*I); + for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(), + E = rhsQID->qual_end(); J != E; ++J) { + ObjCProtocolDecl *rhsProto = *J; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { + match = true; + break; + } + } + if (!match) + return false; + } + } + return true; + } + return false; +} + +/// 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 ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT) { + const ObjCObjectType* LHS = LHSOPT->getObjectType(); + const ObjCObjectType* RHS = RHSOPT->getObjectType(); + + // If either type represents the built-in 'id' or 'Class' types, return true. + if (LHS->isObjCUnqualifiedIdOrClass() || + RHS->isObjCUnqualifiedIdOrClass()) + return true; + + if (LHS->isObjCQualifiedId() || RHS->isObjCQualifiedId()) + return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false); + + if (LHS->isObjCQualifiedClass() && RHS->isObjCQualifiedClass()) + return ObjCQualifiedClassTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0)); + + // If we have 2 user-defined types, fall into that path. + if (LHS->getInterface() && RHS->getInterface()) + return canAssignObjCInterfaces(LHS, RHS); + + return false; +} + +/// canAssignObjCInterfacesInBlockPointer - This routine is specifically written +/// for providing type-safety for objective-c pointers used to pass/return +/// arguments in block literals. When passed as arguments, passing 'A*' where +/// 'id' is expected is not OK. Passing 'Sub *" where 'Super *" is expected is +/// not OK. For the return type, the opposite is not OK. +bool ASTContext::canAssignObjCInterfacesInBlockPointer( + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + bool BlockReturnType) { + if (RHSOPT->isObjCBuiltinType() || LHSOPT->isObjCIdType()) + return true; + + if (LHSOPT->isObjCBuiltinType()) { + return RHSOPT->isObjCBuiltinType() || RHSOPT->isObjCQualifiedIdType(); + } + + if (LHSOPT->isObjCQualifiedIdType() || RHSOPT->isObjCQualifiedIdType()) + return ObjCQualifiedIdTypesAreCompatible(QualType(LHSOPT,0), + QualType(RHSOPT,0), + false); + + const ObjCInterfaceType* LHS = LHSOPT->getInterfaceType(); + const ObjCInterfaceType* RHS = RHSOPT->getInterfaceType(); + if (LHS && RHS) { // We have 2 user-defined types. + if (LHS != RHS) { + if (LHS->getDecl()->isSuperClassOf(RHS->getDecl())) + return BlockReturnType; + if (RHS->getDecl()->isSuperClassOf(LHS->getDecl())) + return !BlockReturnType; + } + else + return true; + } + return false; +} + +/// getIntersectionOfProtocols - This routine finds the intersection of set +/// of protocols inherited from two distinct objective-c pointer objects. +/// It is used to build composite qualifier list of the composite type of +/// the conditional expression involving two objective-c pointer objects. +static +void getIntersectionOfProtocols(ASTContext &Context, + const ObjCObjectPointerType *LHSOPT, + const ObjCObjectPointerType *RHSOPT, + llvm::SmallVectorImpl<ObjCProtocolDecl *> &IntersectionOfProtocols) { + + const ObjCObjectType* LHS = LHSOPT->getObjectType(); + const ObjCObjectType* RHS = RHSOPT->getObjectType(); + assert(LHS->getInterface() && "LHS must have an interface base"); + assert(RHS->getInterface() && "RHS must have an interface base"); + + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> InheritedProtocolSet; + unsigned LHSNumProtocols = LHS->getNumProtocols(); + if (LHSNumProtocols > 0) + InheritedProtocolSet.insert(LHS->qual_begin(), LHS->qual_end()); + else { + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> LHSInheritedProtocols; + Context.CollectInheritedProtocols(LHS->getInterface(), + LHSInheritedProtocols); + InheritedProtocolSet.insert(LHSInheritedProtocols.begin(), + LHSInheritedProtocols.end()); + } + + unsigned RHSNumProtocols = RHS->getNumProtocols(); + if (RHSNumProtocols > 0) { + ObjCProtocolDecl **RHSProtocols = + const_cast<ObjCProtocolDecl **>(RHS->qual_begin()); + for (unsigned i = 0; i < RHSNumProtocols; ++i) + if (InheritedProtocolSet.count(RHSProtocols[i])) + IntersectionOfProtocols.push_back(RHSProtocols[i]); + } + else { + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; + Context.CollectInheritedProtocols(RHS->getInterface(), + RHSInheritedProtocols); + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + RHSInheritedProtocols.begin(), + E = RHSInheritedProtocols.end(); I != E; ++I) + if (InheritedProtocolSet.count((*I))) + IntersectionOfProtocols.push_back((*I)); + } +} + +/// areCommonBaseCompatible - Returns common base class of the two classes if +/// one found. Note that this is O'2 algorithm. But it will be called as the +/// last type comparison in a ?-exp of ObjC pointer types before a +/// warning is issued. So, its invokation is extremely rare. +QualType ASTContext::areCommonBaseCompatible( + const ObjCObjectPointerType *Lptr, + const ObjCObjectPointerType *Rptr) { + const ObjCObjectType *LHS = Lptr->getObjectType(); + const ObjCObjectType *RHS = Rptr->getObjectType(); + const ObjCInterfaceDecl* LDecl = LHS->getInterface(); + const ObjCInterfaceDecl* RDecl = RHS->getInterface(); + if (!LDecl || !RDecl || (LDecl == RDecl)) + return QualType(); + + do { + LHS = cast<ObjCInterfaceType>(getObjCInterfaceType(LDecl)); + if (canAssignObjCInterfaces(LHS, RHS)) { + llvm::SmallVector<ObjCProtocolDecl *, 8> Protocols; + getIntersectionOfProtocols(*this, Lptr, Rptr, Protocols); + + QualType Result = QualType(LHS, 0); + if (!Protocols.empty()) + Result = getObjCObjectType(Result, Protocols.data(), Protocols.size()); + Result = getObjCObjectPointerType(Result); + return Result; + } + } while ((LDecl = LDecl->getSuperClass())); + + return QualType(); +} + +bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, + const ObjCObjectType *RHS) { + assert(LHS->getInterface() && "LHS is not an interface type"); + assert(RHS->getInterface() && "RHS is not an interface type"); + + // Verify that the base decls are compatible: the RHS must be a subclass of + // the LHS. + if (!LHS->getInterface()->isSuperClassOf(RHS->getInterface())) + 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 (LHS->getNumProtocols() == 0) + return true; + + // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, + // more detailed analysis is required. + if (RHS->getNumProtocols() == 0) { + // OK, if LHS is a superclass of RHS *and* + // this superclass is assignment compatible with LHS. + // false otherwise. + bool IsSuperClass = + LHS->getInterface()->isSuperClassOf(RHS->getInterface()); + if (IsSuperClass) { + // OK if conversion of LHS to SuperClass results in narrowing of types + // ; i.e., SuperClass may implement at least one of the protocols + // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. + // But not SuperObj<P1,P2,P3> = lhs<P1,P2>. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols; + CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols); + // If super class has no protocols, it is not a match. + if (SuperClassInheritedProtocols.empty()) + return false; + + for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); + LHSPI != LHSPE; LHSPI++) { + bool SuperImplementsProtocol = false; + ObjCProtocolDecl *LHSProto = (*LHSPI); + + for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = + SuperClassInheritedProtocols.begin(), + E = SuperClassInheritedProtocols.end(); I != E; ++I) { + ObjCProtocolDecl *SuperClassProto = (*I); + if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) { + SuperImplementsProtocol = true; + break; + } + } + if (!SuperImplementsProtocol) + return false; + } + return true; + } + return false; + } + + for (ObjCObjectType::qual_iterator LHSPI = LHS->qual_begin(), + LHSPE = LHS->qual_end(); + LHSPI != LHSPE; LHSPI++) { + bool RHSImplementsProtocol = false; + + // If the RHS doesn't implement the protocol on the left, the types + // are incompatible. + for (ObjCObjectType::qual_iterator RHSPI = RHS->qual_begin(), + RHSPE = RHS->qual_end(); + RHSPI != RHSPE; RHSPI++) { + if ((*RHSPI)->lookupProtocolNamed((*LHSPI)->getIdentifier())) { + RHSImplementsProtocol = true; + break; + } + } + // 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 ObjCObjectPointerType *LHSOPT = LHS->getAs<ObjCObjectPointerType>(); + const ObjCObjectPointerType *RHSOPT = RHS->getAs<ObjCObjectPointerType>(); + + if (!LHSOPT || !RHSOPT) + return false; + + return canAssignObjCInterfaces(LHSOPT, RHSOPT) || + canAssignObjCInterfaces(RHSOPT, LHSOPT); +} + +bool ASTContext::canBindObjCObjectType(QualType To, QualType From) { + return canAssignObjCInterfaces( + getObjCObjectPointerType(To)->getAs<ObjCObjectPointerType>(), + getObjCObjectPointerType(From)->getAs<ObjCObjectPointerType>()); +} + +/// 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, + bool CompareUnqualified) { + if (getLangOptions().CPlusPlus) + return hasSameType(LHS, RHS); + + return !mergeTypes(LHS, RHS, false, CompareUnqualified).isNull(); +} + +bool ASTContext::typesAreBlockPointerCompatible(QualType LHS, QualType RHS) { + return !mergeTypes(LHS, RHS, true).isNull(); +} + +/// mergeTransparentUnionType - if T is a transparent union type and a member +/// of T is compatible with SubType, return the merged type, else return +/// QualType() +QualType ASTContext::mergeTransparentUnionType(QualType T, QualType SubType, + bool OfBlockPointer, + bool Unqualified) { + if (const RecordType *UT = T->getAsUnionType()) { + RecordDecl *UD = UT->getDecl(); + if (UD->hasAttr<TransparentUnionAttr>()) { + for (RecordDecl::field_iterator it = UD->field_begin(), + itend = UD->field_end(); it != itend; ++it) { + QualType ET = it->getType().getUnqualifiedType(); + QualType MT = mergeTypes(ET, SubType, OfBlockPointer, Unqualified); + if (!MT.isNull()) + return MT; + } + } + } + + return QualType(); +} + +/// mergeFunctionArgumentTypes - merge two types which appear as function +/// argument types +QualType ASTContext::mergeFunctionArgumentTypes(QualType lhs, QualType rhs, + bool OfBlockPointer, + bool Unqualified) { + // GNU extension: two types are compatible if they appear as a function + // argument, one of the types is a transparent union type and the other + // type is compatible with a union member + QualType lmerge = mergeTransparentUnionType(lhs, rhs, OfBlockPointer, + Unqualified); + if (!lmerge.isNull()) + return lmerge; + + QualType rmerge = mergeTransparentUnionType(rhs, lhs, OfBlockPointer, + Unqualified); + if (!rmerge.isNull()) + return rmerge; + + return mergeTypes(lhs, rhs, OfBlockPointer, Unqualified); +} + +QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, + bool OfBlockPointer, + bool Unqualified) { + const FunctionType *lbase = lhs->getAs<FunctionType>(); + const FunctionType *rbase = rhs->getAs<FunctionType>(); + 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; + if (OfBlockPointer) { + QualType RHS = rbase->getResultType(); + QualType LHS = lbase->getResultType(); + bool UnqualifiedResult = Unqualified; + if (!UnqualifiedResult) + UnqualifiedResult = (!RHS.hasQualifiers() && LHS.hasQualifiers()); + retType = mergeTypes(LHS, RHS, true, UnqualifiedResult, true); + } + else + retType = mergeTypes(lbase->getResultType(), rbase->getResultType(), false, + Unqualified); + if (retType.isNull()) return QualType(); + + if (Unqualified) + retType = retType.getUnqualifiedType(); + + CanQualType LRetType = getCanonicalType(lbase->getResultType()); + CanQualType RRetType = getCanonicalType(rbase->getResultType()); + if (Unqualified) { + LRetType = LRetType.getUnqualifiedType(); + RRetType = RRetType.getUnqualifiedType(); + } + + if (getCanonicalType(retType) != LRetType) + allLTypes = false; + if (getCanonicalType(retType) != RRetType) + allRTypes = false; + + // FIXME: double check this + // FIXME: should we error if lbase->getRegParmAttr() != 0 && + // rbase->getRegParmAttr() != 0 && + // lbase->getRegParmAttr() != rbase->getRegParmAttr()? + FunctionType::ExtInfo lbaseInfo = lbase->getExtInfo(); + FunctionType::ExtInfo rbaseInfo = rbase->getExtInfo(); + + // Compatible functions must have compatible calling conventions + if (!isSameCallConv(lbaseInfo.getCC(), rbaseInfo.getCC())) + return QualType(); + + // Regparm is part of the calling convention. + if (lbaseInfo.getHasRegParm() != rbaseInfo.getHasRegParm()) + return QualType(); + if (lbaseInfo.getRegParm() != rbaseInfo.getRegParm()) + return QualType(); + + // It's noreturn if either type is. + // FIXME: some uses, e.g. conditional exprs, really want this to be 'both'. + bool NoReturn = lbaseInfo.getNoReturn() || rbaseInfo.getNoReturn(); + if (NoReturn != lbaseInfo.getNoReturn()) + allLTypes = false; + if (NoReturn != rbaseInfo.getNoReturn()) + allRTypes = false; + + FunctionType::ExtInfo einfo(NoReturn, + lbaseInfo.getHasRegParm(), + lbaseInfo.getRegParm(), + lbaseInfo.getCC()); + + 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 = mergeFunctionArgumentTypes(largtype, rargtype, + OfBlockPointer, + Unqualified); + if (argtype.isNull()) return QualType(); + + if (Unqualified) + argtype = argtype.getUnqualifiedType(); + + types.push_back(argtype); + if (Unqualified) { + largtype = largtype.getUnqualifiedType(); + rargtype = rargtype.getUnqualifiedType(); + } + + if (getCanonicalType(argtype) != getCanonicalType(largtype)) + allLTypes = false; + if (getCanonicalType(argtype) != getCanonicalType(rargtype)) + allRTypes = false; + } + if (allLTypes) return lhs; + if (allRTypes) return rhs; + + FunctionProtoType::ExtProtoInfo EPI = lproto->getExtProtoInfo(); + EPI.ExtInfo = einfo; + return getFunctionType(retType, types.begin(), types.size(), EPI); + } + + 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); + + // Look at the promotion type of enum types, since that is the type used + // to pass enum values. + if (const EnumType *Enum = argTy->getAs<EnumType>()) + argTy = Enum->getDecl()->getPromotionType(); + + if (argTy->isPromotableIntegerType() || + getCanonicalType(argTy).getUnqualifiedType() == FloatTy) + return QualType(); + } + + if (allLTypes) return lhs; + if (allRTypes) return rhs; + + FunctionProtoType::ExtProtoInfo EPI = proto->getExtProtoInfo(); + EPI.ExtInfo = einfo; + return getFunctionType(retType, proto->arg_type_begin(), + proto->getNumArgs(), EPI); + } + + if (allLTypes) return lhs; + if (allRTypes) return rhs; + return getFunctionNoProtoType(retType, einfo); +} + +QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, + bool OfBlockPointer, + bool Unqualified, bool BlockReturnType) { + // 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). + assert(!LHS->getAs<ReferenceType>() && "LHS is a reference type?"); + assert(!RHS->getAs<ReferenceType>() && "RHS is a reference type?"); + + if (Unqualified) { + LHS = LHS.getUnqualifiedType(); + RHS = RHS.getUnqualifiedType(); + } + + 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... mostly. + Qualifiers LQuals = LHSCan.getLocalQualifiers(); + Qualifiers RQuals = RHSCan.getLocalQualifiers(); + if (LQuals != RQuals) { + // If any of these qualifiers are different, we have a type + // mismatch. + if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || + LQuals.getAddressSpace() != RQuals.getAddressSpace()) + return QualType(); + + // Exactly one GC qualifier difference is allowed: __strong is + // okay if the other type has no GC qualifier but is an Objective + // C object pointer (i.e. implicitly strong by default). We fix + // this by pretending that the unqualified type was actually + // qualified __strong. + Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); + Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); + assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); + + if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) + return QualType(); + + if (GC_L == Qualifiers::Strong && RHSCan->isObjCObjectPointerType()) { + return mergeTypes(LHS, getObjCGCQualType(RHS, Qualifiers::Strong)); + } + if (GC_R == Qualifiers::Strong && LHSCan->isObjCObjectPointerType()) { + return mergeTypes(getObjCGCQualType(LHS, Qualifiers::Strong), RHS); + } + return QualType(); + } + + // Okay, qualifiers are equal. + + 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; + + // 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; + + // ObjCInterfaces are just specialized ObjCObjects. + if (LHSClass == Type::ObjCInterface) LHSClass = Type::ObjCObject; + if (RHSClass == Type::ObjCInterface) RHSClass = Type::ObjCObject; + + // Canonicalize ExtVector -> Vector. + if (LHSClass == Type::ExtVector) LHSClass = Type::Vector; + if (RHSClass == Type::ExtVector) RHSClass = Type::Vector; + + // If the canonical type classes don't match. + if (LHSClass != RHSClass) { + // C99 6.7.2.2p4: Each enumerated type shall be compatible with char, + // a signed integer type, or an unsigned integer type. + // Compatibility is based on the underlying type, not the promotion + // type. + if (const EnumType* ETy = LHS->getAs<EnumType>()) { + if (ETy->getDecl()->getIntegerType() == RHSCan.getUnqualifiedType()) + return RHS; + } + if (const EnumType* ETy = RHS->getAs<EnumType>()) { + 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_UNLESS_DEPENDENT_TYPE(Class, Base) case Type::Class: +#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::ObjCInterface: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::FunctionProto: + case Type::ExtVector: + assert(false && "Types are eliminated above"); + return QualType(); + + case Type::Pointer: + { + // Merge two pointer types, while trying to preserve typedef info + QualType LHSPointee = LHS->getAs<PointerType>()->getPointeeType(); + QualType RHSPointee = RHS->getAs<PointerType>()->getPointeeType(); + if (Unqualified) { + LHSPointee = LHSPointee.getUnqualifiedType(); + RHSPointee = RHSPointee.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSPointee, RHSPointee, false, + Unqualified); + 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->getAs<BlockPointerType>()->getPointeeType(); + QualType RHSPointee = RHS->getAs<BlockPointerType>()->getPointeeType(); + if (Unqualified) { + LHSPointee = LHSPointee.getUnqualifiedType(); + RHSPointee = RHSPointee.getUnqualifiedType(); + } + QualType ResultType = mergeTypes(LHSPointee, RHSPointee, OfBlockPointer, + Unqualified); + 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(); + if (Unqualified) { + LHSElem = LHSElem.getUnqualifiedType(); + RHSElem = RHSElem.getUnqualifiedType(); + } + + QualType ResultType = mergeTypes(LHSElem, RHSElem, false, Unqualified); + 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, OfBlockPointer, Unqualified); + case Type::Record: + case Type::Enum: + 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(LHSCan->getAs<VectorType>(), + RHSCan->getAs<VectorType>())) + return LHS; + return QualType(); + case Type::ObjCObject: { + // Check if the types are assignment compatible. + // FIXME: This should be type compatibility, e.g. whether + // "LHS x; RHS x;" at global scope is legal. + const ObjCObjectType* LHSIface = LHS->getAs<ObjCObjectType>(); + const ObjCObjectType* RHSIface = RHS->getAs<ObjCObjectType>(); + if (canAssignObjCInterfaces(LHSIface, RHSIface)) + return LHS; + + return QualType(); + } + case Type::ObjCObjectPointer: { + if (OfBlockPointer) { + if (canAssignObjCInterfacesInBlockPointer( + LHS->getAs<ObjCObjectPointerType>(), + RHS->getAs<ObjCObjectPointerType>(), + BlockReturnType)) + return LHS; + return QualType(); + } + if (canAssignObjCInterfaces(LHS->getAs<ObjCObjectPointerType>(), + RHS->getAs<ObjCObjectPointerType>())) + return LHS; + + return QualType(); + } + } + + return QualType(); +} + +/// mergeObjCGCQualifiers - This routine merges ObjC's GC attribute of 'LHS' and +/// 'RHS' attributes and returns the merged version; including for function +/// return types. +QualType ASTContext::mergeObjCGCQualifiers(QualType LHS, QualType RHS) { + QualType LHSCan = getCanonicalType(LHS), + RHSCan = getCanonicalType(RHS); + // If two types are identical, they are compatible. + if (LHSCan == RHSCan) + return LHS; + if (RHSCan->isFunctionType()) { + if (!LHSCan->isFunctionType()) + return QualType(); + QualType OldReturnType = + cast<FunctionType>(RHSCan.getTypePtr())->getResultType(); + QualType NewReturnType = + cast<FunctionType>(LHSCan.getTypePtr())->getResultType(); + QualType ResReturnType = + mergeObjCGCQualifiers(NewReturnType, OldReturnType); + if (ResReturnType.isNull()) + return QualType(); + if (ResReturnType == NewReturnType || ResReturnType == OldReturnType) { + // id foo(); ... __strong id foo(); or: __strong id foo(); ... id foo(); + // In either case, use OldReturnType to build the new function type. + const FunctionType *F = LHS->getAs<FunctionType>(); + if (const FunctionProtoType *FPT = cast<FunctionProtoType>(F)) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExtInfo = getFunctionExtInfo(LHS); + QualType ResultType + = getFunctionType(OldReturnType, FPT->arg_type_begin(), + FPT->getNumArgs(), EPI); + return ResultType; + } + } + return QualType(); + } + + // If the qualifiers are different, the types can still be merged. + Qualifiers LQuals = LHSCan.getLocalQualifiers(); + Qualifiers RQuals = RHSCan.getLocalQualifiers(); + if (LQuals != RQuals) { + // If any of these qualifiers are different, we have a type mismatch. + if (LQuals.getCVRQualifiers() != RQuals.getCVRQualifiers() || + LQuals.getAddressSpace() != RQuals.getAddressSpace()) + return QualType(); + + // Exactly one GC qualifier difference is allowed: __strong is + // okay if the other type has no GC qualifier but is an Objective + // C object pointer (i.e. implicitly strong by default). We fix + // this by pretending that the unqualified type was actually + // qualified __strong. + Qualifiers::GC GC_L = LQuals.getObjCGCAttr(); + Qualifiers::GC GC_R = RQuals.getObjCGCAttr(); + assert((GC_L != GC_R) && "unequal qualifier sets had only equal elements"); + + if (GC_L == Qualifiers::Weak || GC_R == Qualifiers::Weak) + return QualType(); + + if (GC_L == Qualifiers::Strong) + return LHS; + if (GC_R == Qualifiers::Strong) + return RHS; + return QualType(); + } + + if (LHSCan->isObjCObjectPointerType() && RHSCan->isObjCObjectPointerType()) { + QualType LHSBaseQT = LHS->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType RHSBaseQT = RHS->getAs<ObjCObjectPointerType>()->getPointeeType(); + QualType ResQT = mergeObjCGCQualifiers(LHSBaseQT, RHSBaseQT); + if (ResQT == LHSBaseQT) + return LHS; + if (ResQT == RHSBaseQT) + return RHS; + } + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Integer Predicates +//===----------------------------------------------------------------------===// + +unsigned ASTContext::getIntWidth(QualType T) const { + if (const EnumType *ET = dyn_cast<EnumType>(T)) + T = ET->getDecl()->getIntegerType(); + if (T->isBooleanType()) + return 1; + // For builtin types, just use the standard type sizing method + return (unsigned)getTypeSize(T); +} + +QualType ASTContext::getCorrespondingUnsignedType(QualType T) { + assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); + + // Turn <4 x signed int> -> <4 x unsigned int> + if (const VectorType *VTy = T->getAs<VectorType>()) + return getVectorType(getCorrespondingUnsignedType(VTy->getElementType()), + VTy->getNumElements(), VTy->getVectorKind()); + + // For enums, we return the unsigned version of the base type. + if (const EnumType *ETy = T->getAs<EnumType>()) + T = ETy->getDecl()->getIntegerType(); + + const BuiltinType *BTy = T->getAs<BuiltinType>(); + 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(); + } +} + +ASTMutationListener::~ASTMutationListener() { } + + +//===----------------------------------------------------------------------===// +// Builtin Type Computation +//===----------------------------------------------------------------------===// + +/// DecodeTypeFromStr - This decodes one type descriptor from Str, advancing the +/// pointer over the consumed characters. This returns the resultant type. If +/// AllowTypeModifiers is false then modifier like * are not parsed, just basic +/// types. This allows "v2i*" to be parsed as a pointer to a v2i instead of +/// a vector of "i*". +/// +/// RequiresICE is filled in on return to indicate whether the value is required +/// to be an Integer Constant Expression. +static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, + ASTContext::GetBuiltinTypeError &Error, + bool &RequiresICE, + bool AllowTypeModifiers) { + // Modifiers. + int HowLong = 0; + bool Signed = false, Unsigned = false; + RequiresICE = false; + + // Read the prefixed modifiers first. + bool Done = false; + while (!Done) { + switch (*Str++) { + default: Done = true; --Str; break; + case 'I': + RequiresICE = true; + 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 'G': + Type = Context.getObjCIdType(); + break; + case 'H': + Type = Context.getObjCSelType(); + 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, + RequiresICE, false); + assert(!RequiresICE && "Can't require vector ICE"); + + // TODO: No way to make AltiVec vectors in builtins yet. + Type = Context.getVectorType(ElementType, NumElements, + VectorType::GenericVector); + break; + } + case 'X': { + QualType ElementType = DecodeTypeFromStr(Str, Context, Error, RequiresICE, + false); + assert(!RequiresICE && "Can't require complex ICE"); + Type = Context.getComplexType(ElementType); + break; + } + case 'P': + Type = Context.getFILEType(); + if (Type.isNull()) { + Error = ASTContext::GE_Missing_stdio; + return QualType(); + } + break; + case 'J': + if (Signed) + Type = Context.getsigjmp_bufType(); + else + Type = Context.getjmp_bufType(); + + if (Type.isNull()) { + Error = ASTContext::GE_Missing_setjmp; + return QualType(); + } + break; + } + + // If there are modifiers and if we're allowed to parse them, go for it. + Done = !AllowTypeModifiers; + while (!Done) { + switch (char c = *Str++) { + default: Done = true; --Str; break; + case '*': + case '&': { + // Both pointers and references can have their pointee types + // qualified with an address space. + char *End; + unsigned AddrSpace = strtoul(Str, &End, 10); + if (End != Str && AddrSpace != 0) { + Type = Context.getAddrSpaceQualType(Type, AddrSpace); + Str = End; + } + if (c == '*') + Type = Context.getPointerType(Type); + else + Type = Context.getLValueReferenceType(Type); + break; + } + // FIXME: There's no way to have a built-in with an rvalue ref arg. + case 'C': + Type = Type.withConst(); + break; + case 'D': + Type = Context.getVolatileType(Type); + break; + } + } + + assert((!RequiresICE || Type->isIntegralOrEnumerationType()) && + "Integer constant 'I' type must be an integer"); + + return Type; +} + +/// GetBuiltinType - Return the type for the specified builtin. +QualType ASTContext::GetBuiltinType(unsigned Id, + GetBuiltinTypeError &Error, + unsigned *IntegerConstantArgs) const { + const char *TypeStr = BuiltinInfo.GetTypeString(Id); + + llvm::SmallVector<QualType, 8> ArgTypes; + + bool RequiresICE = false; + Error = GE_None; + QualType ResType = DecodeTypeFromStr(TypeStr, *this, Error, + RequiresICE, true); + if (Error != GE_None) + return QualType(); + + assert(!RequiresICE && "Result of intrinsic cannot be required to be an ICE"); + + while (TypeStr[0] && TypeStr[0] != '.') { + QualType Ty = DecodeTypeFromStr(TypeStr, *this, Error, RequiresICE, true); + if (Error != GE_None) + return QualType(); + + // If this argument is required to be an IntegerConstantExpression and the + // caller cares, fill in the bitmask we return. + if (RequiresICE && IntegerConstantArgs) + *IntegerConstantArgs |= 1 << ArgTypes.size(); + + // Do array -> pointer decay. The builtin should use the decayed type. + if (Ty->isArrayType()) + Ty = getArrayDecayedType(Ty); + + ArgTypes.push_back(Ty); + } + + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && + "'.' should only occur at end of builtin type list!"); + + FunctionType::ExtInfo EI; + if (BuiltinInfo.isNoReturn(Id)) EI = EI.withNoReturn(true); + + bool Variadic = (TypeStr[0] == '.'); + + // We really shouldn't be making a no-proto type here, especially in C++. + if (ArgTypes.empty() && Variadic) + return getFunctionNoProtoType(ResType, EI); + + FunctionProtoType::ExtProtoInfo EPI; + EPI.ExtInfo = EI; + EPI.Variadic = Variadic; + + return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(), EPI); +} + +GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { + GVALinkage External = GVA_StrongExternal; + + Linkage L = FD->getLinkage(); + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (FD->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + External = GVA_StrongExternal; + break; + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ExplicitInstantiationDeclaration: + case TSK_ImplicitInstantiation: + External = GVA_TemplateInstantiation; + break; + } + } + + if (!FD->isInlined()) + return External; + + if (!getLangOptions().CPlusPlus || FD->hasAttr<GNUInlineAttr>()) { + // GNU or C99 inline semantics. Determine whether this symbol should be + // externally visible. + if (FD->isInlineDefinitionExternallyVisible()) + return External; + + // C99 inline semantics, where the symbol is not externally visible. + return GVA_C99Inline; + } + + // C++0x [temp.explicit]p9: + // [ Note: The intent is that an inline function that is the subject of + // an explicit instantiation declaration will still be implicitly + // instantiated when used so that the body can be considered for + // inlining, but that no out-of-line copy of the inline function would be + // generated in the translation unit. -- end note ] + if (FD->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration) + return GVA_C99Inline; + + return GVA_CXXInline; +} + +GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) { + // If this is a static data member, compute the kind of template + // specialization. Otherwise, this variable is not part of a + // template. + TemplateSpecializationKind TSK = TSK_Undeclared; + if (VD->isStaticDataMember()) + TSK = VD->getTemplateSpecializationKind(); + + Linkage L = VD->getLinkage(); + if (L == ExternalLinkage && getLangOptions().CPlusPlus && + VD->getType()->getLinkage() == UniqueExternalLinkage) + L = UniqueExternalLinkage; + + switch (L) { + case NoLinkage: + case InternalLinkage: + case UniqueExternalLinkage: + return GVA_Internal; + + case ExternalLinkage: + switch (TSK) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return GVA_StrongExternal; + + case TSK_ExplicitInstantiationDeclaration: + llvm_unreachable("Variable should not be instantiated"); + // Fall through to treat this like any other instantiation. + + case TSK_ExplicitInstantiationDefinition: + return GVA_ExplicitTemplateInstantiation; + + case TSK_ImplicitInstantiation: + return GVA_TemplateInstantiation; + } + } + + return GVA_StrongExternal; +} + +bool ASTContext::DeclMustBeEmitted(const Decl *D) { + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (!VD->isFileVarDecl()) + return false; + } else if (!isa<FunctionDecl>(D)) + return false; + + // Weak references don't produce any output by themselves. + if (D->hasAttr<WeakRefAttr>()) + return false; + + // Aliases and used decls are required. + if (D->hasAttr<AliasAttr>() || D->hasAttr<UsedAttr>()) + return true; + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Forward declarations aren't required. + if (!FD->doesThisDeclarationHaveABody()) + return false; + + // Constructors and destructors are required. + if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>()) + return true; + + // The key function for a class is required. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + const CXXRecordDecl *RD = MD->getParent(); + if (MD->isOutOfLine() && RD->isDynamicClass()) { + const CXXMethodDecl *KeyFunc = getKeyFunction(RD); + if (KeyFunc && KeyFunc->getCanonicalDecl() == MD->getCanonicalDecl()) + return true; + } + } + + GVALinkage Linkage = GetGVALinkageForFunction(FD); + + // static, static inline, always_inline, and extern inline functions can + // always be deferred. Normal inline functions can be deferred in C99/C++. + // Implicit template instantiations can also be deferred in C++. + if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || + Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) + return false; + return true; + } + + const VarDecl *VD = cast<VarDecl>(D); + assert(VD->isFileVarDecl() && "Expected file scoped var"); + + if (VD->isThisDeclarationADefinition() == VarDecl::DeclarationOnly) + return false; + + // Structs that have non-trivial constructors or destructors are required. + + // FIXME: Handle references. + // FIXME: Be more selective about which constructors we care about. + if (const RecordType *RT = VD->getType()->getAs<RecordType>()) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (RD->hasDefinition() && !(RD->hasTrivialDefaultConstructor() && + RD->hasTrivialCopyConstructor() && + RD->hasTrivialMoveConstructor() && + RD->hasTrivialDestructor())) + return true; + } + } + + GVALinkage L = GetGVALinkageForVariable(VD); + if (L == GVA_Internal || L == GVA_TemplateInstantiation) { + if (!(VD->getInit() && VD->getInit()->HasSideEffects(*this))) + return false; + } + + return true; +} + +CallingConv ASTContext::getDefaultMethodCallConv() { + // Pass through to the C++ ABI object + return ABI->getDefaultMethodCallConv(); +} + +bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { + // Pass through to the C++ ABI object + return ABI->isNearlyEmpty(RD); +} + +MangleContext *ASTContext::createMangleContext() { + switch (Target.getCXXABI()) { + case CXXABI_ARM: + case CXXABI_Itanium: + return createItaniumMangleContext(*this, getDiagnostics()); + case CXXABI_Microsoft: + return createMicrosoftMangleContext(*this, getDiagnostics()); + } + assert(0 && "Unsupported ABI"); + return 0; +} + +CXXABI::~CXXABI() {} + +size_t ASTContext::getSideTableAllocatedMemory() const { + size_t bytes = 0; + bytes += ASTRecordLayouts.getMemorySize(); + bytes += ObjCLayouts.getMemorySize(); + bytes += KeyFunctions.getMemorySize(); + bytes += ObjCImpls.getMemorySize(); + bytes += BlockVarCopyInits.getMemorySize(); + bytes += DeclAttrs.getMemorySize(); + bytes += InstantiatedFromStaticDataMember.getMemorySize(); + bytes += InstantiatedFromUsingDecl.getMemorySize(); + bytes += InstantiatedFromUsingShadowDecl.getMemorySize(); + bytes += InstantiatedFromUnnamedFieldDecl.getMemorySize(); + return bytes; +} + diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp new file mode 100644 index 000000000000..16d2f853606e --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp @@ -0,0 +1,287 @@ +//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for 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 a diagnostic formatting hook for AST elements. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTDiagnostic.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// Returns a desugared version of the QualType, and marks ShouldAKA as true +// whenever we remove significant sugar from the type. +static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { + QualifierCollector QC; + + while (true) { + const Type *Ty = QC.strip(QT); + + // Don't aka just because we saw an elaborated type... + if (const ElaboratedType *ET = dyn_cast<ElaboratedType>(Ty)) { + QT = ET->desugar(); + continue; + } + // ... or a paren type ... + if (const ParenType *PT = dyn_cast<ParenType>(Ty)) { + QT = PT->desugar(); + continue; + } + // ...or a substituted template type parameter ... + if (const SubstTemplateTypeParmType *ST = + dyn_cast<SubstTemplateTypeParmType>(Ty)) { + QT = ST->desugar(); + continue; + } + // ...or an attributed type... + if (const AttributedType *AT = dyn_cast<AttributedType>(Ty)) { + QT = AT->desugar(); + continue; + } + // ... or an auto type. + if (const AutoType *AT = dyn_cast<AutoType>(Ty)) { + if (!AT->isSugared()) + break; + QT = AT->desugar(); + continue; + } + + // Don't desugar template specializations, unless it's an alias template. + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(Ty)) + if (!TST->isTypeAlias()) + break; + + // Don't desugar magic Objective-C types. + if (QualType(Ty,0) == Context.getObjCIdType() || + QualType(Ty,0) == Context.getObjCClassType() || + QualType(Ty,0) == Context.getObjCSelType() || + QualType(Ty,0) == Context.getObjCProtoType()) + break; + + // Don't desugar va_list. + if (QualType(Ty,0) == Context.getBuiltinVaListType()) + break; + + // Otherwise, do a single-step desugar. + QualType Underlying; + bool IsSugar = false; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ +case Type::Class: { \ +const Class##Type *CTy = cast<Class##Type>(Ty); \ +if (CTy->isSugared()) { \ +IsSugar = true; \ +Underlying = CTy->desugar(); \ +} \ +break; \ +} +#include "clang/AST/TypeNodes.def" + } + + // If it wasn't sugared, we're done. + if (!IsSugar) + break; + + // If the desugared type is a vector type, we don't want to expand + // it, it will turn into an attribute mess. People want their "vec4". + if (isa<VectorType>(Underlying)) + break; + + // Don't desugar through the primary typedef of an anonymous type. + if (const TagType *UTT = Underlying->getAs<TagType>()) + if (const TypedefType *QTT = dyn_cast<TypedefType>(QT)) + if (UTT->getDecl()->getTypedefNameForAnonDecl() == QTT->getDecl()) + break; + + // Record that we actually looked through an opaque type here. + ShouldAKA = true; + QT = Underlying; + } + + // If we have a pointer-like type, desugar the pointee as well. + // FIXME: Handle other pointer-like types. + if (const PointerType *Ty = QT->getAs<PointerType>()) { + QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { + QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } else if (const RValueReferenceType *Ty = QT->getAs<RValueReferenceType>()) { + QT = Context.getRValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } + + return QC.apply(Context, QT); +} + +/// \brief Convert the given type to a string suitable for printing as part of +/// a diagnostic. +/// +/// There are three main criteria when determining whether we should have an +/// a.k.a. clause when pretty-printing a type: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +/// 3) Some types may have already been desugared previously in this diagnostic. +/// if this is the case, doing another "aka" would just be clutter. +/// +/// \param Context the context in which the type was allocated +/// \param Ty the type to print +static std::string +ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // Check to see if we already desugared this type in this + // diagnostic. If so, don't do it again. + bool Repeated = false; + for (unsigned i = 0; i != NumPrevArgs; ++i) { + // TODO: Handle ak_declcontext case. + if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + void *Ptr = (void*)PrevArgs[i].second; + QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); + if (PrevTy == Ty) { + Repeated = true; + break; + } + } + } + + // Consider producing an a.k.a. clause if removing all the direct + // sugar gives us something "significantly different". + if (!Repeated) { + bool ShouldAKA = false; + QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); + if (ShouldAKA) { + S = "'" + S + "' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } + } + + S = "'" + S + "'"; + return S; +} + +void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl<char> &Output, + void *Cookie) { + ASTContext &Context = *static_cast<ASTContext*>(Cookie); + + std::string S; + bool NeedQuotes = true; + + switch (Kind) { + default: assert(0 && "unknown ArgumentKind"); + case Diagnostic::ak_qualtype: { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for QualType argument"); + + QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declarationname: { + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + S = N.getAsString(); + + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) + S = '+' + S; + else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) + && ArgLen==0) + S = '-' + S; + else + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for DeclarationName argument"); + break; + } + case Diagnostic::ak_nameddecl: { + bool Qualified; + if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) + Qualified = true; + else { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for NamedDecl* argument"); + Qualified = false; + } + reinterpret_cast<NamedDecl*>(Val)-> + getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); + break; + } + case Diagnostic::ak_nestednamespec: { + llvm::raw_string_ostream OS(S); + reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, + Context.PrintingPolicy); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declcontext: { + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + assert(DC && "Should never have a null declaration context"); + + if (DC->isTranslationUnit()) { + // FIXME: Get these strings from some localized place + if (Context.getLangOptions().CPlusPlus) + S = "the global namespace"; + else + S = "the global scope"; + } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { + S = ConvertTypeToDiagnosticString(Context, + Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs); + } else { + // FIXME: Get these strings from some localized place + NamedDecl *ND = cast<NamedDecl>(DC); + if (isa<NamespaceDecl>(ND)) + S += "namespace "; + else if (isa<ObjCMethodDecl>(ND)) + S += "method "; + else if (isa<FunctionDecl>(ND)) + S += "function "; + + S += "'"; + ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + S += "'"; + } + NeedQuotes = false; + break; + } + } + + if (NeedQuotes) + Output.push_back('\''); + + Output.append(S.begin(), S.end()); + + if (NeedQuotes) + Output.push_back('\''); +} diff --git a/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp new file mode 100644 index 000000000000..100e604d1c46 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTImporter.cpp @@ -0,0 +1,4403 @@ +//===--- ASTImporter.cpp - Importing ASTs from other Contexts ---*- 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 ASTImporter class which imports AST nodes from one +// context into another context. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTImporter.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/Support/MemoryBuffer.h" +#include <deque> + +using namespace clang; + +namespace { + class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, QualType>, + public DeclVisitor<ASTNodeImporter, Decl *>, + public StmtVisitor<ASTNodeImporter, Stmt *> { + ASTImporter &Importer; + + public: + explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) { } + + using TypeVisitor<ASTNodeImporter, QualType>::Visit; + using DeclVisitor<ASTNodeImporter, Decl *>::Visit; + using StmtVisitor<ASTNodeImporter, Stmt *>::Visit; + + // Importing types + QualType VisitType(const Type *T); + QualType VisitBuiltinType(const BuiltinType *T); + QualType VisitComplexType(const ComplexType *T); + QualType VisitPointerType(const PointerType *T); + QualType VisitBlockPointerType(const BlockPointerType *T); + QualType VisitLValueReferenceType(const LValueReferenceType *T); + QualType VisitRValueReferenceType(const RValueReferenceType *T); + QualType VisitMemberPointerType(const MemberPointerType *T); + QualType VisitConstantArrayType(const ConstantArrayType *T); + QualType VisitIncompleteArrayType(const IncompleteArrayType *T); + QualType VisitVariableArrayType(const VariableArrayType *T); + // FIXME: DependentSizedArrayType + // FIXME: DependentSizedExtVectorType + QualType VisitVectorType(const VectorType *T); + QualType VisitExtVectorType(const ExtVectorType *T); + QualType VisitFunctionNoProtoType(const FunctionNoProtoType *T); + QualType VisitFunctionProtoType(const FunctionProtoType *T); + // FIXME: UnresolvedUsingType + QualType VisitTypedefType(const TypedefType *T); + QualType VisitTypeOfExprType(const TypeOfExprType *T); + // FIXME: DependentTypeOfExprType + QualType VisitTypeOfType(const TypeOfType *T); + QualType VisitDecltypeType(const DecltypeType *T); + QualType VisitUnaryTransformType(const UnaryTransformType *T); + QualType VisitAutoType(const AutoType *T); + // FIXME: DependentDecltypeType + QualType VisitRecordType(const RecordType *T); + QualType VisitEnumType(const EnumType *T); + // FIXME: TemplateTypeParmType + // FIXME: SubstTemplateTypeParmType + QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T); + QualType VisitElaboratedType(const ElaboratedType *T); + // FIXME: DependentNameType + // FIXME: DependentTemplateSpecializationType + QualType VisitObjCInterfaceType(const ObjCInterfaceType *T); + QualType VisitObjCObjectType(const ObjCObjectType *T); + QualType VisitObjCObjectPointerType(const ObjCObjectPointerType *T); + + // Importing declarations + bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, DeclarationName &Name, + SourceLocation &Loc); + void ImportDeclarationNameLoc(const DeclarationNameInfo &From, + DeclarationNameInfo& To); + void ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); + bool ImportDefinition(RecordDecl *From, RecordDecl *To); + TemplateParameterList *ImportTemplateParameterList( + TemplateParameterList *Params); + TemplateArgument ImportTemplateArgument(const TemplateArgument &From); + bool ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs); + bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord); + bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); + bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); + Decl *VisitDecl(Decl *D); + Decl *VisitNamespaceDecl(NamespaceDecl *D); + Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias); + Decl *VisitTypedefDecl(TypedefDecl *D); + Decl *VisitTypeAliasDecl(TypeAliasDecl *D); + Decl *VisitEnumDecl(EnumDecl *D); + Decl *VisitRecordDecl(RecordDecl *D); + Decl *VisitEnumConstantDecl(EnumConstantDecl *D); + Decl *VisitFunctionDecl(FunctionDecl *D); + Decl *VisitCXXMethodDecl(CXXMethodDecl *D); + Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D); + Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D); + Decl *VisitCXXConversionDecl(CXXConversionDecl *D); + Decl *VisitFieldDecl(FieldDecl *D); + Decl *VisitIndirectFieldDecl(IndirectFieldDecl *D); + Decl *VisitObjCIvarDecl(ObjCIvarDecl *D); + Decl *VisitVarDecl(VarDecl *D); + Decl *VisitImplicitParamDecl(ImplicitParamDecl *D); + Decl *VisitParmVarDecl(ParmVarDecl *D); + Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); + Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); + Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); + Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); + Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); + Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); + Decl *VisitObjCPropertyDecl(ObjCPropertyDecl *D); + Decl *VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); + Decl *VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D); + Decl *VisitObjCClassDecl(ObjCClassDecl *D); + Decl *VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); + Decl *VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + Decl *VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + Decl *VisitClassTemplateDecl(ClassTemplateDecl *D); + Decl *VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D); + + // Importing statements + Stmt *VisitStmt(Stmt *S); + + // Importing expressions + Expr *VisitExpr(Expr *E); + Expr *VisitDeclRefExpr(DeclRefExpr *E); + Expr *VisitIntegerLiteral(IntegerLiteral *E); + Expr *VisitCharacterLiteral(CharacterLiteral *E); + Expr *VisitParenExpr(ParenExpr *E); + Expr *VisitUnaryOperator(UnaryOperator *E); + Expr *VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); + Expr *VisitBinaryOperator(BinaryOperator *E); + Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E); + Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); + Expr *VisitCStyleCastExpr(CStyleCastExpr *E); + }; +} + +//---------------------------------------------------------------------------- +// Structural Equivalence +//---------------------------------------------------------------------------- + +namespace { + struct StructuralEquivalenceContext { + /// \brief AST contexts for which we are checking structural equivalence. + ASTContext &C1, &C2; + + /// \brief The set of "tentative" equivalences between two canonical + /// declarations, mapping from a declaration in the first context to the + /// declaration in the second context that we believe to be equivalent. + llvm::DenseMap<Decl *, Decl *> TentativeEquivalences; + + /// \brief Queue of declarations in the first context whose equivalence + /// with a declaration in the second context still needs to be verified. + std::deque<Decl *> DeclsToCheck; + + /// \brief Declaration (from, to) pairs that are known not to be equivalent + /// (which we have already complained about). + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls; + + /// \brief Whether we're being strict about the spelling of types when + /// unifying two types. + bool StrictTypeSpelling; + + StructuralEquivalenceContext(ASTContext &C1, ASTContext &C2, + llvm::DenseSet<std::pair<Decl *, Decl *> > &NonEquivalentDecls, + bool StrictTypeSpelling = false) + : C1(C1), C2(C2), NonEquivalentDecls(NonEquivalentDecls), + StrictTypeSpelling(StrictTypeSpelling) { } + + /// \brief Determine whether the two declarations are structurally + /// equivalent. + bool IsStructurallyEquivalent(Decl *D1, Decl *D2); + + /// \brief Determine whether the two types are structurally equivalent. + bool IsStructurallyEquivalent(QualType T1, QualType T2); + + private: + /// \brief Finish checking all of the structural equivalences. + /// + /// \returns true if an error occurred, false otherwise. + bool Finish(); + + public: + DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { + return C1.getDiagnostics().Report(Loc, DiagID); + } + + DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { + return C2.getDiagnostics().Report(Loc, DiagID); + } + }; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2); +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2); + +/// \brief Determine if two APInts have the same value, after zero-extending +/// one of them (if needed!) to ensure that the bit-widths match. +static bool IsSameValue(const llvm::APInt &I1, const llvm::APInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth()) + return I1 == I2; + + if (I1.getBitWidth() > I2.getBitWidth()) + return I1 == I2.zext(I1.getBitWidth()); + + return I1.zext(I2.getBitWidth()) == I2; +} + +/// \brief Determine if two APSInts have the same value, zero- or sign-extending +/// as needed. +static bool IsSameValue(const llvm::APSInt &I1, const llvm::APSInt &I2) { + if (I1.getBitWidth() == I2.getBitWidth() && I1.isSigned() == I2.isSigned()) + return I1 == I2; + + // Check for a bit-width mismatch. + if (I1.getBitWidth() > I2.getBitWidth()) + return IsSameValue(I1, I2.extend(I1.getBitWidth())); + else if (I2.getBitWidth() > I1.getBitWidth()) + return IsSameValue(I1.extend(I2.getBitWidth()), I2); + + // We have a signedness mismatch. Turn the signed value into an unsigned + // value. + if (I1.isSigned()) { + if (I1.isNegative()) + return false; + + return llvm::APSInt(I1, true) == I2; + } + + if (I2.isNegative()) + return false; + + return I1 == llvm::APSInt(I2, true); +} + +/// \brief Determine structural equivalence of two expressions. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Expr *E1, Expr *E2) { + if (!E1 || !E2) + return E1 == E2; + + // FIXME: Actually perform a structural comparison! + return true; +} + +/// \brief Determine whether two identifiers are equivalent. +static bool IsStructurallyEquivalent(const IdentifierInfo *Name1, + const IdentifierInfo *Name2) { + if (!Name1 || !Name2) + return Name1 == Name2; + + return Name1->getName() == Name2->getName(); +} + +/// \brief Determine whether two nested-name-specifiers are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NestedNameSpecifier *NNS1, + NestedNameSpecifier *NNS2) { + // FIXME: Implement! + return true; +} + +/// \brief Determine whether two template arguments are equivalent. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + const TemplateArgument &Arg1, + const TemplateArgument &Arg2) { + if (Arg1.getKind() != Arg2.getKind()) + return false; + + switch (Arg1.getKind()) { + case TemplateArgument::Null: + return true; + + case TemplateArgument::Type: + return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); + + case TemplateArgument::Integral: + if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), + Arg2.getIntegralType())) + return false; + + return IsSameValue(*Arg1.getAsIntegral(), *Arg2.getAsIntegral()); + + case TemplateArgument::Declaration: + return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); + + case TemplateArgument::Template: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplate(), + Arg2.getAsTemplate()); + + case TemplateArgument::TemplateExpansion: + return IsStructurallyEquivalent(Context, + Arg1.getAsTemplateOrTemplatePattern(), + Arg2.getAsTemplateOrTemplatePattern()); + + case TemplateArgument::Expression: + return IsStructurallyEquivalent(Context, + Arg1.getAsExpr(), Arg2.getAsExpr()); + + case TemplateArgument::Pack: + if (Arg1.pack_size() != Arg2.pack_size()) + return false; + + for (unsigned I = 0, N = Arg1.pack_size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Arg1.pack_begin()[I], + Arg2.pack_begin()[I])) + return false; + + return true; + } + + llvm_unreachable("Invalid template argument kind"); + return true; +} + +/// \brief Determine structural equivalence for the common part of array +/// types. +static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, + const ArrayType *Array1, + const ArrayType *Array2) { + if (!IsStructurallyEquivalent(Context, + Array1->getElementType(), + Array2->getElementType())) + return false; + if (Array1->getSizeModifier() != Array2->getSizeModifier()) + return false; + if (Array1->getIndexTypeQualifiers() != Array2->getIndexTypeQualifiers()) + return false; + + return true; +} + +/// \brief Determine structural equivalence of two types. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + QualType T1, QualType T2) { + if (T1.isNull() || T2.isNull()) + return T1.isNull() && T2.isNull(); + + if (!Context.StrictTypeSpelling) { + // We aren't being strict about token-to-token equivalence of types, + // so map down to the canonical type. + T1 = Context.C1.getCanonicalType(T1); + T2 = Context.C2.getCanonicalType(T2); + } + + if (T1.getQualifiers() != T2.getQualifiers()) + return false; + + Type::TypeClass TC = T1->getTypeClass(); + + if (T1->getTypeClass() != T2->getTypeClass()) { + // Compare function types with prototypes vs. without prototypes as if + // both did not have prototypes. + if (T1->getTypeClass() == Type::FunctionProto && + T2->getTypeClass() == Type::FunctionNoProto) + TC = Type::FunctionNoProto; + else if (T1->getTypeClass() == Type::FunctionNoProto && + T2->getTypeClass() == Type::FunctionProto) + TC = Type::FunctionNoProto; + else + return false; + } + + switch (TC) { + case Type::Builtin: + // FIXME: Deal with Char_S/Char_U. + if (cast<BuiltinType>(T1)->getKind() != cast<BuiltinType>(T2)->getKind()) + return false; + break; + + case Type::Complex: + if (!IsStructurallyEquivalent(Context, + cast<ComplexType>(T1)->getElementType(), + cast<ComplexType>(T2)->getElementType())) + return false; + break; + + case Type::Pointer: + if (!IsStructurallyEquivalent(Context, + cast<PointerType>(T1)->getPointeeType(), + cast<PointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::BlockPointer: + if (!IsStructurallyEquivalent(Context, + cast<BlockPointerType>(T1)->getPointeeType(), + cast<BlockPointerType>(T2)->getPointeeType())) + return false; + break; + + case Type::LValueReference: + case Type::RValueReference: { + const ReferenceType *Ref1 = cast<ReferenceType>(T1); + const ReferenceType *Ref2 = cast<ReferenceType>(T2); + if (Ref1->isSpelledAsLValue() != Ref2->isSpelledAsLValue()) + return false; + if (Ref1->isInnerRef() != Ref2->isInnerRef()) + return false; + if (!IsStructurallyEquivalent(Context, + Ref1->getPointeeTypeAsWritten(), + Ref2->getPointeeTypeAsWritten())) + return false; + break; + } + + case Type::MemberPointer: { + const MemberPointerType *MemPtr1 = cast<MemberPointerType>(T1); + const MemberPointerType *MemPtr2 = cast<MemberPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + MemPtr1->getPointeeType(), + MemPtr2->getPointeeType())) + return false; + if (!IsStructurallyEquivalent(Context, + QualType(MemPtr1->getClass(), 0), + QualType(MemPtr2->getClass(), 0))) + return false; + break; + } + + case Type::ConstantArray: { + const ConstantArrayType *Array1 = cast<ConstantArrayType>(T1); + const ConstantArrayType *Array2 = cast<ConstantArrayType>(T2); + if (!IsSameValue(Array1->getSize(), Array2->getSize())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + break; + } + + case Type::IncompleteArray: + if (!IsArrayStructurallyEquivalent(Context, + cast<ArrayType>(T1), + cast<ArrayType>(T2))) + return false; + break; + + case Type::VariableArray: { + const VariableArrayType *Array1 = cast<VariableArrayType>(T1); + const VariableArrayType *Array2 = cast<VariableArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedArray: { + const DependentSizedArrayType *Array1 = cast<DependentSizedArrayType>(T1); + const DependentSizedArrayType *Array2 = cast<DependentSizedArrayType>(T2); + if (!IsStructurallyEquivalent(Context, + Array1->getSizeExpr(), Array2->getSizeExpr())) + return false; + + if (!IsArrayStructurallyEquivalent(Context, Array1, Array2)) + return false; + + break; + } + + case Type::DependentSizedExtVector: { + const DependentSizedExtVectorType *Vec1 + = cast<DependentSizedExtVectorType>(T1); + const DependentSizedExtVectorType *Vec2 + = cast<DependentSizedExtVectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getSizeExpr(), Vec2->getSizeExpr())) + return false; + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + break; + } + + case Type::Vector: + case Type::ExtVector: { + const VectorType *Vec1 = cast<VectorType>(T1); + const VectorType *Vec2 = cast<VectorType>(T2); + if (!IsStructurallyEquivalent(Context, + Vec1->getElementType(), + Vec2->getElementType())) + return false; + if (Vec1->getNumElements() != Vec2->getNumElements()) + return false; + if (Vec1->getVectorKind() != Vec2->getVectorKind()) + return false; + break; + } + + case Type::FunctionProto: { + const FunctionProtoType *Proto1 = cast<FunctionProtoType>(T1); + const FunctionProtoType *Proto2 = cast<FunctionProtoType>(T2); + if (Proto1->getNumArgs() != Proto2->getNumArgs()) + return false; + for (unsigned I = 0, N = Proto1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getArgType(I), + Proto2->getArgType(I))) + return false; + } + if (Proto1->isVariadic() != Proto2->isVariadic()) + return false; + if (Proto1->getExceptionSpecType() != Proto2->getExceptionSpecType()) + return false; + if (Proto1->getExceptionSpecType() == EST_Dynamic) { + if (Proto1->getNumExceptions() != Proto2->getNumExceptions()) + return false; + for (unsigned I = 0, N = Proto1->getNumExceptions(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Proto1->getExceptionType(I), + Proto2->getExceptionType(I))) + return false; + } + } else if (Proto1->getExceptionSpecType() == EST_ComputedNoexcept) { + if (!IsStructurallyEquivalent(Context, + Proto1->getNoexceptExpr(), + Proto2->getNoexceptExpr())) + return false; + } + if (Proto1->getTypeQuals() != Proto2->getTypeQuals()) + return false; + + // Fall through to check the bits common with FunctionNoProtoType. + } + + case Type::FunctionNoProto: { + const FunctionType *Function1 = cast<FunctionType>(T1); + const FunctionType *Function2 = cast<FunctionType>(T2); + if (!IsStructurallyEquivalent(Context, + Function1->getResultType(), + Function2->getResultType())) + return false; + if (Function1->getExtInfo() != Function2->getExtInfo()) + return false; + break; + } + + case Type::UnresolvedUsing: + if (!IsStructurallyEquivalent(Context, + cast<UnresolvedUsingType>(T1)->getDecl(), + cast<UnresolvedUsingType>(T2)->getDecl())) + return false; + + break; + + case Type::Attributed: + if (!IsStructurallyEquivalent(Context, + cast<AttributedType>(T1)->getModifiedType(), + cast<AttributedType>(T2)->getModifiedType())) + return false; + if (!IsStructurallyEquivalent(Context, + cast<AttributedType>(T1)->getEquivalentType(), + cast<AttributedType>(T2)->getEquivalentType())) + return false; + break; + + case Type::Paren: + if (!IsStructurallyEquivalent(Context, + cast<ParenType>(T1)->getInnerType(), + cast<ParenType>(T2)->getInnerType())) + return false; + break; + + case Type::Typedef: + if (!IsStructurallyEquivalent(Context, + cast<TypedefType>(T1)->getDecl(), + cast<TypedefType>(T2)->getDecl())) + return false; + break; + + case Type::TypeOfExpr: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfExprType>(T1)->getUnderlyingExpr(), + cast<TypeOfExprType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::TypeOf: + if (!IsStructurallyEquivalent(Context, + cast<TypeOfType>(T1)->getUnderlyingType(), + cast<TypeOfType>(T2)->getUnderlyingType())) + return false; + break; + + case Type::UnaryTransform: + if (!IsStructurallyEquivalent(Context, + cast<UnaryTransformType>(T1)->getUnderlyingType(), + cast<UnaryTransformType>(T1)->getUnderlyingType())) + return false; + break; + + case Type::Decltype: + if (!IsStructurallyEquivalent(Context, + cast<DecltypeType>(T1)->getUnderlyingExpr(), + cast<DecltypeType>(T2)->getUnderlyingExpr())) + return false; + break; + + case Type::Auto: + if (!IsStructurallyEquivalent(Context, + cast<AutoType>(T1)->getDeducedType(), + cast<AutoType>(T2)->getDeducedType())) + return false; + break; + + case Type::Record: + case Type::Enum: + if (!IsStructurallyEquivalent(Context, + cast<TagType>(T1)->getDecl(), + cast<TagType>(T2)->getDecl())) + return false; + break; + + case Type::TemplateTypeParm: { + const TemplateTypeParmType *Parm1 = cast<TemplateTypeParmType>(T1); + const TemplateTypeParmType *Parm2 = cast<TemplateTypeParmType>(T2); + if (Parm1->getDepth() != Parm2->getDepth()) + return false; + if (Parm1->getIndex() != Parm2->getIndex()) + return false; + if (Parm1->isParameterPack() != Parm2->isParameterPack()) + return false; + + // Names of template type parameters are never significant. + break; + } + + case Type::SubstTemplateTypeParm: { + const SubstTemplateTypeParmType *Subst1 + = cast<SubstTemplateTypeParmType>(T1); + const SubstTemplateTypeParmType *Subst2 + = cast<SubstTemplateTypeParmType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, + Subst1->getReplacementType(), + Subst2->getReplacementType())) + return false; + break; + } + + case Type::SubstTemplateTypeParmPack: { + const SubstTemplateTypeParmPackType *Subst1 + = cast<SubstTemplateTypeParmPackType>(T1); + const SubstTemplateTypeParmPackType *Subst2 + = cast<SubstTemplateTypeParmPackType>(T2); + if (!IsStructurallyEquivalent(Context, + QualType(Subst1->getReplacedParameter(), 0), + QualType(Subst2->getReplacedParameter(), 0))) + return false; + if (!IsStructurallyEquivalent(Context, + Subst1->getArgumentPack(), + Subst2->getArgumentPack())) + return false; + break; + } + case Type::TemplateSpecialization: { + const TemplateSpecializationType *Spec1 + = cast<TemplateSpecializationType>(T1); + const TemplateSpecializationType *Spec2 + = cast<TemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateName(), + Spec2->getTemplateName())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Spec1->getArg(I), Spec2->getArg(I))) + return false; + } + break; + } + + case Type::Elaborated: { + const ElaboratedType *Elab1 = cast<ElaboratedType>(T1); + const ElaboratedType *Elab2 = cast<ElaboratedType>(T2); + // CHECKME: what if a keyword is ETK_None or ETK_typename ? + if (Elab1->getKeyword() != Elab2->getKeyword()) + return false; + if (!IsStructurallyEquivalent(Context, + Elab1->getQualifier(), + Elab2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Context, + Elab1->getNamedType(), + Elab2->getNamedType())) + return false; + break; + } + + case Type::InjectedClassName: { + const InjectedClassNameType *Inj1 = cast<InjectedClassNameType>(T1); + const InjectedClassNameType *Inj2 = cast<InjectedClassNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Inj1->getInjectedSpecializationType(), + Inj2->getInjectedSpecializationType())) + return false; + break; + } + + case Type::DependentName: { + const DependentNameType *Typename1 = cast<DependentNameType>(T1); + const DependentNameType *Typename2 = cast<DependentNameType>(T2); + if (!IsStructurallyEquivalent(Context, + Typename1->getQualifier(), + Typename2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Typename1->getIdentifier(), + Typename2->getIdentifier())) + return false; + + break; + } + + case Type::DependentTemplateSpecialization: { + const DependentTemplateSpecializationType *Spec1 = + cast<DependentTemplateSpecializationType>(T1); + const DependentTemplateSpecializationType *Spec2 = + cast<DependentTemplateSpecializationType>(T2); + if (!IsStructurallyEquivalent(Context, + Spec1->getQualifier(), + Spec2->getQualifier())) + return false; + if (!IsStructurallyEquivalent(Spec1->getIdentifier(), + Spec2->getIdentifier())) + return false; + if (Spec1->getNumArgs() != Spec2->getNumArgs()) + return false; + for (unsigned I = 0, N = Spec1->getNumArgs(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Spec1->getArg(I), Spec2->getArg(I))) + return false; + } + break; + } + + case Type::PackExpansion: + if (!IsStructurallyEquivalent(Context, + cast<PackExpansionType>(T1)->getPattern(), + cast<PackExpansionType>(T2)->getPattern())) + return false; + break; + + case Type::ObjCInterface: { + const ObjCInterfaceType *Iface1 = cast<ObjCInterfaceType>(T1); + const ObjCInterfaceType *Iface2 = cast<ObjCInterfaceType>(T2); + if (!IsStructurallyEquivalent(Context, + Iface1->getDecl(), Iface2->getDecl())) + return false; + break; + } + + case Type::ObjCObject: { + const ObjCObjectType *Obj1 = cast<ObjCObjectType>(T1); + const ObjCObjectType *Obj2 = cast<ObjCObjectType>(T2); + if (!IsStructurallyEquivalent(Context, + Obj1->getBaseType(), + Obj2->getBaseType())) + return false; + if (Obj1->getNumProtocols() != Obj2->getNumProtocols()) + return false; + for (unsigned I = 0, N = Obj1->getNumProtocols(); I != N; ++I) { + if (!IsStructurallyEquivalent(Context, + Obj1->getProtocol(I), + Obj2->getProtocol(I))) + return false; + } + break; + } + + case Type::ObjCObjectPointer: { + const ObjCObjectPointerType *Ptr1 = cast<ObjCObjectPointerType>(T1); + const ObjCObjectPointerType *Ptr2 = cast<ObjCObjectPointerType>(T2); + if (!IsStructurallyEquivalent(Context, + Ptr1->getPointeeType(), + Ptr2->getPointeeType())) + return false; + break; + } + + } // end switch + + return true; +} + +/// \brief Determine structural equivalence of two records. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + RecordDecl *D1, RecordDecl *D2) { + if (D1->isUnion() != D2->isUnion()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + return false; + } + + // If both declarations are class template specializations, we know + // the ODR applies, so check the template and template arguments. + ClassTemplateSpecializationDecl *Spec1 + = dyn_cast<ClassTemplateSpecializationDecl>(D1); + ClassTemplateSpecializationDecl *Spec2 + = dyn_cast<ClassTemplateSpecializationDecl>(D2); + if (Spec1 && Spec2) { + // Check that the specialized templates are the same. + if (!IsStructurallyEquivalent(Context, Spec1->getSpecializedTemplate(), + Spec2->getSpecializedTemplate())) + return false; + + // Check that the template arguments are the same. + if (Spec1->getTemplateArgs().size() != Spec2->getTemplateArgs().size()) + return false; + + for (unsigned I = 0, N = Spec1->getTemplateArgs().size(); I != N; ++I) + if (!IsStructurallyEquivalent(Context, + Spec1->getTemplateArgs().get(I), + Spec2->getTemplateArgs().get(I))) + return false; + } + // If one is a class template specialization and the other is not, these + // structures are different. + else if (Spec1 || Spec2) + return false; + + // Compare the definitions of these two records. If either or both are + // incomplete, we assume that they are equivalent. + D1 = D1->getDefinition(); + D2 = D2->getDefinition(); + if (!D1 || !D2) + return true; + + if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { + if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { + if (D1CXX->getNumBases() != D2CXX->getNumBases()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + return false; + } + + // Check the base classes. + for (CXXRecordDecl::base_class_iterator Base1 = D1CXX->bases_begin(), + BaseEnd1 = D1CXX->bases_end(), + Base2 = D2CXX->bases_begin(); + Base1 != BaseEnd1; + ++Base1, ++Base2) { + if (!IsStructurallyEquivalent(Context, + Base1->getType(), Base2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), diag::note_odr_base) + << Base2->getType() + << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + return false; + } + + // Check virtual vs. non-virtual inheritance mismatch. + if (Base1->isVirtual() != Base2->isVirtual()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getSourceRange().getBegin(), + diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->isVirtual() + << Base1->getSourceRange(); + return false; + } + } + } else if (D1CXX->getNumBases() > 0) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getSourceRange().getBegin(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + return false; + } + } + + // Check the fields for consistency. + CXXRecordDecl::field_iterator Field2 = D2->field_begin(), + Field2End = D2->field_end(); + for (CXXRecordDecl::field_iterator Field1 = D1->field_begin(), + Field1End = D1->field_end(); + Field1 != Field1End; + ++Field1, ++Field2) { + if (Field2 == Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + return false; + } + + if (!IsStructurallyEquivalent(Context, + Field1->getType(), Field2->getType())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + return false; + } + + if (Field1->isBitField() != Field2->isBitField()) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + if (Field1->isBitField()) { + llvm::APSInt Bits; + Field1->getBitWidth()->isIntegerConstantExpr(Bits, Context.C1); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits.toString(10, false); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + llvm::APSInt Bits; + Field2->getBitWidth()->isIntegerConstantExpr(Bits, Context.C2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits.toString(10, false); + Context.Diag1(Field1->getLocation(), + diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } + return false; + } + + if (Field1->isBitField()) { + // Make sure that the bit-fields are the same length. + llvm::APSInt Bits1, Bits2; + if (!Field1->getBitWidth()->isIntegerConstantExpr(Bits1, Context.C1)) + return false; + if (!Field2->getBitWidth()->isIntegerConstantExpr(Bits2, Context.C2)) + return false; + + if (!IsSameValue(Bits1, Bits2)) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Bits2.toString(10, false); + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Bits1.toString(10, false); + return false; + } + } + } + + if (Field2 != Field2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + return false; + } + + return true; +} + +/// \brief Determine structural equivalence of two enums. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumDecl *D1, EnumDecl *D2) { + EnumDecl::enumerator_iterator EC2 = D2->enumerator_begin(), + EC2End = D2->enumerator_end(); + for (EnumDecl::enumerator_iterator EC1 = D1->enumerator_begin(), + EC1End = D1->enumerator_end(); + EC1 != EC1End; ++EC1, ++EC2) { + if (EC2 == EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + llvm::APSInt Val1 = EC1->getInitVal(); + llvm::APSInt Val2 = EC2->getInitVal(); + if (!IsSameValue(Val1, Val2) || + !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + return false; + } + } + + if (EC2 != EC2End) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateParameterList *Params1, + TemplateParameterList *Params2) { + if (Params1->size() != Params2->size()) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + return false; + } + + for (unsigned I = 0, N = Params1->size(); I != N; ++I) { + if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + return false; + } + + if (!Context.IsStructurallyEquivalent(Params1->getParam(I), + Params2->getParam(I))) { + + return false; + } + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTypeParmDecl *D1, + TemplateTypeParmDecl *D2) { + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + NonTypeTemplateParmDecl *D1, + NonTypeTemplateParmDecl *D2) { + // FIXME: Enable once we have variadic templates. +#if 0 + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } +#endif + + // Check types. + if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + return false; + } + + return true; +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + TemplateTemplateParmDecl *D1, + TemplateTemplateParmDecl *D2) { + // FIXME: Enable once we have variadic templates. +#if 0 + if (D1->isParameterPack() != D2->isParameterPack()) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + return false; + } +#endif + + // Check template parameter lists. + return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + D2->getTemplateParameters()); +} + +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + ClassTemplateDecl *D1, + ClassTemplateDecl *D2) { + // Check template parameters. + if (!IsStructurallyEquivalent(Context, + D1->getTemplateParameters(), + D2->getTemplateParameters())) + return false; + + // Check the templated declaration. + return Context.IsStructurallyEquivalent(D1->getTemplatedDecl(), + D2->getTemplatedDecl()); +} + +/// \brief Determine structural equivalence of two declarations. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + Decl *D1, Decl *D2) { + // FIXME: Check for known structural equivalences via a callback of some sort. + + // Check whether we already know that these two declarations are not + // structurally equivalent. + if (Context.NonEquivalentDecls.count(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl()))) + return false; + + // Determine whether we've already produced a tentative equivalence for D1. + Decl *&EquivToD1 = Context.TentativeEquivalences[D1->getCanonicalDecl()]; + if (EquivToD1) + return EquivToD1 == D2->getCanonicalDecl(); + + // Produce a tentative equivalence D1 <-> D2, which will be checked later. + EquivToD1 = D2->getCanonicalDecl(); + Context.DeclsToCheck.push_back(D1->getCanonicalDecl()); + return true; +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(Decl *D1, + Decl *D2) { + if (!::IsStructurallyEquivalent(*this, D1, D2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::IsStructurallyEquivalent(QualType T1, + QualType T2) { + if (!::IsStructurallyEquivalent(*this, T1, T2)) + return false; + + return !Finish(); +} + +bool StructuralEquivalenceContext::Finish() { + while (!DeclsToCheck.empty()) { + // Check the next declaration. + Decl *D1 = DeclsToCheck.front(); + DeclsToCheck.pop_front(); + + Decl *D2 = TentativeEquivalences[D1]; + assert(D2 && "Unrecorded tentative equivalence?"); + + bool Equivalent = true; + + // FIXME: Switch on all declaration kinds. For now, we're just going to + // check the obvious ones. + if (RecordDecl *Record1 = dyn_cast<RecordDecl>(D1)) { + if (RecordDecl *Record2 = dyn_cast<RecordDecl>(D2)) { + // Check for equivalent structure names. + IdentifierInfo *Name1 = Record1->getIdentifier(); + if (!Name1 && Record1->getTypedefNameForAnonDecl()) + Name1 = Record1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Record2->getIdentifier(); + if (!Name2 && Record2->getTypedefNameForAnonDecl()) + Name2 = Record2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Record1, Record2)) + Equivalent = false; + } else { + // Record/non-record mismatch. + Equivalent = false; + } + } else if (EnumDecl *Enum1 = dyn_cast<EnumDecl>(D1)) { + if (EnumDecl *Enum2 = dyn_cast<EnumDecl>(D2)) { + // Check for equivalent enum names. + IdentifierInfo *Name1 = Enum1->getIdentifier(); + if (!Name1 && Enum1->getTypedefNameForAnonDecl()) + Name1 = Enum1->getTypedefNameForAnonDecl()->getIdentifier(); + IdentifierInfo *Name2 = Enum2->getIdentifier(); + if (!Name2 && Enum2->getTypedefNameForAnonDecl()) + Name2 = Enum2->getTypedefNameForAnonDecl()->getIdentifier(); + if (!::IsStructurallyEquivalent(Name1, Name2) || + !::IsStructurallyEquivalent(*this, Enum1, Enum2)) + Equivalent = false; + } else { + // Enum/non-enum mismatch + Equivalent = false; + } + } else if (TypedefNameDecl *Typedef1 = dyn_cast<TypedefNameDecl>(D1)) { + if (TypedefNameDecl *Typedef2 = dyn_cast<TypedefNameDecl>(D2)) { + if (!::IsStructurallyEquivalent(Typedef1->getIdentifier(), + Typedef2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, + Typedef1->getUnderlyingType(), + Typedef2->getUnderlyingType())) + Equivalent = false; + } else { + // Typedef/non-typedef mismatch. + Equivalent = false; + } + } else if (ClassTemplateDecl *ClassTemplate1 + = dyn_cast<ClassTemplateDecl>(D1)) { + if (ClassTemplateDecl *ClassTemplate2 = dyn_cast<ClassTemplateDecl>(D2)) { + if (!::IsStructurallyEquivalent(ClassTemplate1->getIdentifier(), + ClassTemplate2->getIdentifier()) || + !::IsStructurallyEquivalent(*this, ClassTemplate1, ClassTemplate2)) + Equivalent = false; + } else { + // Class template/non-class-template mismatch. + Equivalent = false; + } + } else if (TemplateTypeParmDecl *TTP1= dyn_cast<TemplateTypeParmDecl>(D1)) { + if (TemplateTypeParmDecl *TTP2 = dyn_cast<TemplateTypeParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (NonTypeTemplateParmDecl *NTTP1 + = dyn_cast<NonTypeTemplateParmDecl>(D1)) { + if (NonTypeTemplateParmDecl *NTTP2 + = dyn_cast<NonTypeTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, NTTP1, NTTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } else if (TemplateTemplateParmDecl *TTP1 + = dyn_cast<TemplateTemplateParmDecl>(D1)) { + if (TemplateTemplateParmDecl *TTP2 + = dyn_cast<TemplateTemplateParmDecl>(D2)) { + if (!::IsStructurallyEquivalent(*this, TTP1, TTP2)) + Equivalent = false; + } else { + // Kind mismatch. + Equivalent = false; + } + } + + if (!Equivalent) { + // Note that these two declarations are not equivalent (and we already + // know about it). + NonEquivalentDecls.insert(std::make_pair(D1->getCanonicalDecl(), + D2->getCanonicalDecl())); + return true; + } + // FIXME: Check other declaration kinds! + } + + return false; +} + +//---------------------------------------------------------------------------- +// Import Types +//---------------------------------------------------------------------------- + +QualType ASTNodeImporter::VisitType(const Type *T) { + Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) + << T->getTypeClassName(); + return QualType(); +} + +QualType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { + switch (T->getKind()) { + case BuiltinType::Void: return Importer.getToContext().VoidTy; + case BuiltinType::Bool: return Importer.getToContext().BoolTy; + + case BuiltinType::Char_U: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().UnsignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::UChar: return Importer.getToContext().UnsignedCharTy; + + case BuiltinType::Char16: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char16Ty; + + case BuiltinType::Char32: + // FIXME: Make sure that the "to" context supports C++! + return Importer.getToContext().Char32Ty; + + case BuiltinType::UShort: return Importer.getToContext().UnsignedShortTy; + case BuiltinType::UInt: return Importer.getToContext().UnsignedIntTy; + case BuiltinType::ULong: return Importer.getToContext().UnsignedLongTy; + case BuiltinType::ULongLong: + return Importer.getToContext().UnsignedLongLongTy; + case BuiltinType::UInt128: return Importer.getToContext().UnsignedInt128Ty; + + case BuiltinType::Char_S: + // The context we're importing from has an unsigned 'char'. If we're + // importing into a context with a signed 'char', translate to + // 'unsigned char' instead. + if (!Importer.getToContext().getLangOptions().CharIsSigned) + return Importer.getToContext().SignedCharTy; + + return Importer.getToContext().CharTy; + + case BuiltinType::SChar: return Importer.getToContext().SignedCharTy; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + // FIXME: If not in C++, shall we translate to the C equivalent of + // wchar_t? + return Importer.getToContext().WCharTy; + + case BuiltinType::Short : return Importer.getToContext().ShortTy; + case BuiltinType::Int : return Importer.getToContext().IntTy; + case BuiltinType::Long : return Importer.getToContext().LongTy; + case BuiltinType::LongLong : return Importer.getToContext().LongLongTy; + case BuiltinType::Int128 : return Importer.getToContext().Int128Ty; + case BuiltinType::Float: return Importer.getToContext().FloatTy; + case BuiltinType::Double: return Importer.getToContext().DoubleTy; + case BuiltinType::LongDouble: return Importer.getToContext().LongDoubleTy; + + case BuiltinType::NullPtr: + // FIXME: Make sure that the "to" context supports C++0x! + return Importer.getToContext().NullPtrTy; + + case BuiltinType::Overload: return Importer.getToContext().OverloadTy; + case BuiltinType::Dependent: return Importer.getToContext().DependentTy; + case BuiltinType::UnknownAny: return Importer.getToContext().UnknownAnyTy; + case BuiltinType::BoundMember: return Importer.getToContext().BoundMemberTy; + + case BuiltinType::ObjCId: + // FIXME: Make sure that the "to" context supports Objective-C! + return Importer.getToContext().ObjCBuiltinIdTy; + + case BuiltinType::ObjCClass: + return Importer.getToContext().ObjCBuiltinClassTy; + + case BuiltinType::ObjCSel: + return Importer.getToContext().ObjCBuiltinSelTy; + } + + return QualType(); +} + +QualType ASTNodeImporter::VisitComplexType(const ComplexType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getComplexType(ToElementType); +} + +QualType ASTNodeImporter::VisitPointerType(const PointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getPointerType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { + // FIXME: Check for blocks support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getBlockPointerType(ToPointeeType); +} + +QualType +ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getLValueReferenceType(ToPointeeType); +} + +QualType +ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { + // FIXME: Check for C++0x support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeTypeAsWritten()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getRValueReferenceType(ToPointeeType); +} + +QualType ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { + // FIXME: Check for C++ support in "to" context. + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + QualType ClassType = Importer.Import(QualType(T->getClass(), 0)); + return Importer.getToContext().getMemberPointerType(ToPointeeType, + ClassType.getTypePtr()); +} + +QualType ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getConstantArrayType(ToElementType, + T->getSize(), + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType +ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getIncompleteArrayType(ToElementType, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers()); +} + +QualType ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + Expr *Size = Importer.Import(T->getSizeExpr()); + if (!Size) + return QualType(); + + SourceRange Brackets = Importer.Import(T->getBracketsRange()); + return Importer.getToContext().getVariableArrayType(ToElementType, Size, + T->getSizeModifier(), + T->getIndexTypeCVRQualifiers(), + Brackets); +} + +QualType ASTNodeImporter::VisitVectorType(const VectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getVectorType(ToElementType, + T->getNumElements(), + T->getVectorKind()); +} + +QualType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) { + QualType ToElementType = Importer.Import(T->getElementType()); + if (ToElementType.isNull()) + return QualType(); + + return Importer.getToContext().getExtVectorType(ToElementType, + T->getNumElements()); +} + +QualType +ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { + // FIXME: What happens if we're importing a function without a prototype + // into C++? Should we make it variadic? + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + return Importer.getToContext().getFunctionNoProtoType(ToResultType, + T->getExtInfo()); +} + +QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { + QualType ToResultType = Importer.Import(T->getResultType()); + if (ToResultType.isNull()) + return QualType(); + + // Import argument types + llvm::SmallVector<QualType, 4> ArgTypes; + for (FunctionProtoType::arg_type_iterator A = T->arg_type_begin(), + AEnd = T->arg_type_end(); + A != AEnd; ++A) { + QualType ArgType = Importer.Import(*A); + if (ArgType.isNull()) + return QualType(); + ArgTypes.push_back(ArgType); + } + + // Import exception types + llvm::SmallVector<QualType, 4> ExceptionTypes; + for (FunctionProtoType::exception_iterator E = T->exception_begin(), + EEnd = T->exception_end(); + E != EEnd; ++E) { + QualType ExceptionType = Importer.Import(*E); + if (ExceptionType.isNull()) + return QualType(); + ExceptionTypes.push_back(ExceptionType); + } + + FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); + EPI.Exceptions = ExceptionTypes.data(); + + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), + ArgTypes.size(), EPI); +} + +QualType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { + TypedefNameDecl *ToDecl + = dyn_cast_or_null<TypedefNameDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTypeDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getTypeOfExprType(ToExpr); +} + +QualType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getTypeOfType(ToUnderlyingType); +} + +QualType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { + // FIXME: Make sure that the "to" context supports C++0x! + Expr *ToExpr = Importer.Import(T->getUnderlyingExpr()); + if (!ToExpr) + return QualType(); + + return Importer.getToContext().getDecltypeType(ToExpr); +} + +QualType ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { + QualType ToBaseType = Importer.Import(T->getBaseType()); + QualType ToUnderlyingType = Importer.Import(T->getUnderlyingType()); + if (ToBaseType.isNull() || ToUnderlyingType.isNull()) + return QualType(); + + return Importer.getToContext().getUnaryTransformType(ToBaseType, + ToUnderlyingType, + T->getUTTKind()); +} + +QualType ASTNodeImporter::VisitAutoType(const AutoType *T) { + // FIXME: Make sure that the "to" context supports C++0x! + QualType FromDeduced = T->getDeducedType(); + QualType ToDeduced; + if (!FromDeduced.isNull()) { + ToDeduced = Importer.Import(FromDeduced); + if (ToDeduced.isNull()) + return QualType(); + } + + return Importer.getToContext().getAutoType(ToDeduced); +} + +QualType ASTNodeImporter::VisitRecordType(const RecordType *T) { + RecordDecl *ToDecl + = dyn_cast_or_null<RecordDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitEnumType(const EnumType *T) { + EnumDecl *ToDecl + = dyn_cast_or_null<EnumDecl>(Importer.Import(T->getDecl())); + if (!ToDecl) + return QualType(); + + return Importer.getToContext().getTagDeclType(ToDecl); +} + +QualType ASTNodeImporter::VisitTemplateSpecializationType( + const TemplateSpecializationType *T) { + TemplateName ToTemplate = Importer.Import(T->getTemplateName()); + if (ToTemplate.isNull()) + return QualType(); + + llvm::SmallVector<TemplateArgument, 2> ToTemplateArgs; + if (ImportTemplateArguments(T->getArgs(), T->getNumArgs(), ToTemplateArgs)) + return QualType(); + + QualType ToCanonType; + if (!QualType(T, 0).isCanonical()) { + QualType FromCanonType + = Importer.getFromContext().getCanonicalType(QualType(T, 0)); + ToCanonType =Importer.Import(FromCanonType); + if (ToCanonType.isNull()) + return QualType(); + } + return Importer.getToContext().getTemplateSpecializationType(ToTemplate, + ToTemplateArgs.data(), + ToTemplateArgs.size(), + ToCanonType); +} + +QualType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { + NestedNameSpecifier *ToQualifier = 0; + // Note: the qualifier in an ElaboratedType is optional. + if (T->getQualifier()) { + ToQualifier = Importer.Import(T->getQualifier()); + if (!ToQualifier) + return QualType(); + } + + QualType ToNamedType = Importer.Import(T->getNamedType()); + if (ToNamedType.isNull()) + return QualType(); + + return Importer.getToContext().getElaboratedType(T->getKeyword(), + ToQualifier, ToNamedType); +} + +QualType ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { + ObjCInterfaceDecl *Class + = dyn_cast_or_null<ObjCInterfaceDecl>(Importer.Import(T->getDecl())); + if (!Class) + return QualType(); + + return Importer.getToContext().getObjCInterfaceType(Class); +} + +QualType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { + QualType ToBaseType = Importer.Import(T->getBaseType()); + if (ToBaseType.isNull()) + return QualType(); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + for (ObjCObjectType::qual_iterator P = T->qual_begin(), + PEnd = T->qual_end(); + P != PEnd; ++P) { + ObjCProtocolDecl *Protocol + = dyn_cast_or_null<ObjCProtocolDecl>(Importer.Import(*P)); + if (!Protocol) + return QualType(); + Protocols.push_back(Protocol); + } + + return Importer.getToContext().getObjCObjectType(ToBaseType, + Protocols.data(), + Protocols.size()); +} + +QualType +ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + QualType ToPointeeType = Importer.Import(T->getPointeeType()); + if (ToPointeeType.isNull()) + return QualType(); + + return Importer.getToContext().getObjCObjectPointerType(ToPointeeType); +} + +//---------------------------------------------------------------------------- +// Import Declarations +//---------------------------------------------------------------------------- +bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, + DeclContext *&LexicalDC, + DeclarationName &Name, + SourceLocation &Loc) { + // Import the context of this declaration. + DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return true; + + LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return true; + } + + // Import the name of this declaration. + Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return true; + + // Import the location of this declaration. + Loc = Importer.Import(D->getLocation()); + return false; +} + +void +ASTNodeImporter::ImportDeclarationNameLoc(const DeclarationNameInfo &From, + DeclarationNameInfo& To) { + // NOTE: To.Name and To.Loc are already imported. + // We only have to import To.LocInfo. + switch (To.getName().getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + return; + + case DeclarationName::CXXOperatorName: { + SourceRange Range = From.getCXXOperatorNameRange(); + To.setCXXOperatorNameRange(Importer.Import(Range)); + return; + } + case DeclarationName::CXXLiteralOperatorName: { + SourceLocation Loc = From.getCXXLiteralOperatorNameLoc(); + To.setCXXLiteralOperatorNameLoc(Importer.Import(Loc)); + return; + } + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: { + TypeSourceInfo *FromTInfo = From.getNamedTypeInfo(); + To.setNamedTypeInfo(Importer.Import(FromTInfo)); + return; + } + assert(0 && "Unknown name kind."); + } +} + +void ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { + if (Importer.isMinimalImport() && !ForceImport) { + if (DeclContext *ToDC = Importer.ImportContext(FromDC)) { + ToDC->setHasExternalLexicalStorage(); + ToDC->setHasExternalVisibleStorage(); + } + return; + } + + for (DeclContext::decl_iterator From = FromDC->decls_begin(), + FromEnd = FromDC->decls_end(); + From != FromEnd; + ++From) + Importer.Import(*From); +} + +bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { + if (To->getDefinition()) + return false; + + To->startDefinition(); + + // Add base classes. + if (CXXRecordDecl *ToCXX = dyn_cast<CXXRecordDecl>(To)) { + CXXRecordDecl *FromCXX = cast<CXXRecordDecl>(From); + + llvm::SmallVector<CXXBaseSpecifier *, 4> Bases; + for (CXXRecordDecl::base_class_iterator + Base1 = FromCXX->bases_begin(), + FromBaseEnd = FromCXX->bases_end(); + Base1 != FromBaseEnd; + ++Base1) { + QualType T = Importer.Import(Base1->getType()); + if (T.isNull()) + return true; + + SourceLocation EllipsisLoc; + if (Base1->isPackExpansion()) + EllipsisLoc = Importer.Import(Base1->getEllipsisLoc()); + + Bases.push_back( + new (Importer.getToContext()) + CXXBaseSpecifier(Importer.Import(Base1->getSourceRange()), + Base1->isVirtual(), + Base1->isBaseOfClass(), + Base1->getAccessSpecifierAsWritten(), + Importer.Import(Base1->getTypeSourceInfo()), + EllipsisLoc)); + } + if (!Bases.empty()) + ToCXX->setBases(Bases.data(), Bases.size()); + } + + ImportDeclContext(From); + To->completeDefinition(); + return false; +} + +TemplateParameterList *ASTNodeImporter::ImportTemplateParameterList( + TemplateParameterList *Params) { + llvm::SmallVector<NamedDecl *, 4> ToParams; + ToParams.reserve(Params->size()); + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Decl *To = Importer.Import(*P); + if (!To) + return 0; + + ToParams.push_back(cast<NamedDecl>(To)); + } + + return TemplateParameterList::Create(Importer.getToContext(), + Importer.Import(Params->getTemplateLoc()), + Importer.Import(Params->getLAngleLoc()), + ToParams.data(), ToParams.size(), + Importer.Import(Params->getRAngleLoc())); +} + +TemplateArgument +ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { + switch (From.getKind()) { + case TemplateArgument::Null: + return TemplateArgument(); + + case TemplateArgument::Type: { + QualType ToType = Importer.Import(From.getAsType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(ToType); + } + + case TemplateArgument::Integral: { + QualType ToType = Importer.Import(From.getIntegralType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(*From.getAsIntegral(), ToType); + } + + case TemplateArgument::Declaration: + if (Decl *To = Importer.Import(From.getAsDecl())) + return TemplateArgument(To); + return TemplateArgument(); + + case TemplateArgument::Template: { + TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); + if (ToTemplate.isNull()) + return TemplateArgument(); + + return TemplateArgument(ToTemplate); + } + + case TemplateArgument::TemplateExpansion: { + TemplateName ToTemplate + = Importer.Import(From.getAsTemplateOrTemplatePattern()); + if (ToTemplate.isNull()) + return TemplateArgument(); + + return TemplateArgument(ToTemplate, From.getNumTemplateExpansions()); + } + + case TemplateArgument::Expression: + if (Expr *ToExpr = Importer.Import(From.getAsExpr())) + return TemplateArgument(ToExpr); + return TemplateArgument(); + + case TemplateArgument::Pack: { + llvm::SmallVector<TemplateArgument, 2> ToPack; + ToPack.reserve(From.pack_size()); + if (ImportTemplateArguments(From.pack_begin(), From.pack_size(), ToPack)) + return TemplateArgument(); + + TemplateArgument *ToArgs + = new (Importer.getToContext()) TemplateArgument[ToPack.size()]; + std::copy(ToPack.begin(), ToPack.end(), ToArgs); + return TemplateArgument(ToArgs, ToPack.size()); + } + } + + llvm_unreachable("Invalid template argument kind"); + return TemplateArgument(); +} + +bool ASTNodeImporter::ImportTemplateArguments(const TemplateArgument *FromArgs, + unsigned NumFromArgs, + llvm::SmallVectorImpl<TemplateArgument> &ToArgs) { + for (unsigned I = 0; I != NumFromArgs; ++I) { + TemplateArgument To = ImportTemplateArgument(FromArgs[I]); + if (To.isNull() && !FromArgs[I].isNull()) + return true; + + ToArgs.push_back(To); + } + + return false; +} + +bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, + RecordDecl *ToRecord) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(FromRecord, ToRecord); +} + +bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(FromEnum, ToEnum); +} + +bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, + ClassTemplateDecl *To) { + StructuralEquivalenceContext Ctx(Importer.getFromContext(), + Importer.getToContext(), + Importer.getNonEquivalentDecls()); + return Ctx.IsStructurallyEquivalent(From, To); +} + +Decl *ASTNodeImporter::VisitDecl(Decl *D) { + Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) + << D->getDeclKindName(); + return 0; +} + +Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { + // Import the major distinguishing characteristics of this namespace. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + NamespaceDecl *MergeWithNamespace = 0; + if (!Name) { + // This is an anonymous namespace. Adopt an existing anonymous + // namespace if we can. + // FIXME: Not testable. + if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(DC)) + MergeWithNamespace = TU->getAnonymousNamespace(); + else + MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace(); + } else { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Namespace)) + continue; + + if (NamespaceDecl *FoundNS = dyn_cast<NamespaceDecl>(*Lookup.first)) { + MergeWithNamespace = FoundNS; + ConflictingDecls.clear(); + break; + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Namespace, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the "to" namespace, if needed. + NamespaceDecl *ToNamespace = MergeWithNamespace; + if (!ToNamespace) { + ToNamespace = NamespaceDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Loc, Name.getAsIdentifierInfo()); + ToNamespace->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToNamespace); + + // If this is an anonymous namespace, register it as the anonymous + // namespace within its context. + if (!Name) { + if (TranslationUnitDecl *TU = dyn_cast<TranslationUnitDecl>(DC)) + TU->setAnonymousNamespace(ToNamespace); + else + cast<NamespaceDecl>(DC)->setAnonymousNamespace(ToNamespace); + } + } + Importer.Imported(D, ToNamespace); + + ImportDeclContext(D); + + return ToNamespace; +} + +Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { + // Import the major distinguishing characteristics of this typedef. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // If this typedef is not in block scope, determine whether we've + // seen a typedef with the same name (that we can merge with) or any + // other entity by that name (which name lookup could conflict with). + if (!DC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + if (TypedefNameDecl *FoundTypedef = + dyn_cast<TypedefNameDecl>(*Lookup.first)) { + if (Importer.IsStructurallyEquivalent(D->getUnderlyingType(), + FoundTypedef->getUnderlyingType())) + return Importer.Imported(D, FoundTypedef); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the underlying type of this typedef; + QualType T = Importer.Import(D->getUnderlyingType()); + if (T.isNull()) + return 0; + + // Create the new typedef node. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + SourceLocation StartL = Importer.Import(D->getLocStart()); + TypedefNameDecl *ToTypedef; + if (IsAlias) + ToTypedef = TypedefDecl::Create(Importer.getToContext(), DC, + StartL, Loc, + Name.getAsIdentifierInfo(), + TInfo); + else + ToTypedef = TypeAliasDecl::Create(Importer.getToContext(), DC, + StartL, Loc, + Name.getAsIdentifierInfo(), + TInfo); + ToTypedef->setAccess(D->getAccess()); + ToTypedef->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToTypedef); + LexicalDC->addDecl(ToTypedef); + + return ToTypedef; +} + +Decl *ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { + return VisitTypedefNameDecl(D, /*IsAlias=*/false); +} + +Decl *ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) { + return VisitTypedefNameDecl(D, /*IsAlias=*/true); +} + +Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { + // Import the major distinguishing characteristics of this enum. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what enum name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefNameForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have an enum of the same name; try to find and match it. + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (EnumDecl *FoundEnum = dyn_cast<EnumDecl>(Found)) { + if (IsStructuralMatch(D, FoundEnum)) + return Importer.Imported(D, FoundEnum); + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the enum declaration. + EnumDecl *D2 = EnumDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Loc, Name.getAsIdentifierInfo(), 0, + D->isScoped(), D->isScopedUsingClassTag(), + D->isFixed()); + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, D2); + LexicalDC->addDecl(D2); + + // Import the integer type. + QualType ToIntegerType = Importer.Import(D->getIntegerType()); + if (ToIntegerType.isNull()) + return 0; + D2->setIntegerType(ToIntegerType); + + // Import the definition + if (D->isDefinition()) { + QualType T = Importer.Import(Importer.getFromContext().getTypeDeclType(D)); + if (T.isNull()) + return 0; + + QualType ToPromotionType = Importer.Import(D->getPromotionType()); + if (ToPromotionType.isNull()) + return 0; + + D2->startDefinition(); + ImportDeclContext(D); + + // FIXME: we might need to merge the number of positive or negative bits + // if the enumerator lists don't match. + D2->completeDefinition(T, ToPromotionType, + D->getNumPositiveBits(), + D->getNumNegativeBits()); + } + + return D2; +} + +Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + TagDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this record. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Figure out what structure name we're looking for. + unsigned IDNS = Decl::IDNS_Tag; + DeclarationName SearchName = Name; + if (!SearchName && D->getTypedefNameForAnonDecl()) { + SearchName = Importer.Import(D->getTypedefNameForAnonDecl()->getDeclName()); + IDNS = Decl::IDNS_Ordinary; + } else if (Importer.getToContext().getLangOptions().CPlusPlus) + IDNS |= Decl::IDNS_Ordinary; + + // We may already have a record of the same name; try to find and match it. + RecordDecl *AdoptDecl = 0; + if (!DC->isFunctionOrMethod() && SearchName) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + Decl *Found = *Lookup.first; + if (TypedefNameDecl *Typedef = dyn_cast<TypedefNameDecl>(Found)) { + if (const TagType *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) + Found = Tag->getDecl(); + } + + if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + // FIXME: For C++, we should also merge methods here. + return Importer.Imported(D, FoundDef); + } + } else { + // We have a forward declaration of this type, so adopt that forward + // declaration rather than building a new one. + AdoptDecl = FoundRecord; + continue; + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + } + + // Create the record declaration. + RecordDecl *D2 = AdoptDecl; + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + if (!D2) { + if (isa<CXXRecordDecl>(D)) { + CXXRecordDecl *D2CXX = CXXRecordDecl::Create(Importer.getToContext(), + D->getTagKind(), + DC, StartLoc, Loc, + Name.getAsIdentifierInfo()); + D2 = D2CXX; + D2->setAccess(D->getAccess()); + } else { + D2 = RecordDecl::Create(Importer.getToContext(), D->getTagKind(), + DC, StartLoc, Loc, Name.getAsIdentifierInfo()); + } + + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + + Importer.Imported(D, D2); + + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + +Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { + // Import the major distinguishing characteristics of this enumerator. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Determine whether there are any other declarations with the same name and + // in the same context. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + Expr *Init = Importer.Import(D->getInitExpr()); + if (D->getInitExpr() && !Init) + return 0; + + EnumConstantDecl *ToEnumerator + = EnumConstantDecl::Create(Importer.getToContext(), cast<EnumDecl>(DC), Loc, + Name.getAsIdentifierInfo(), T, + Init, D->getInitVal()); + ToEnumerator->setAccess(D->getAccess()); + ToEnumerator->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToEnumerator); + LexicalDC->addDecl(ToEnumerator); + return ToEnumerator; +} + +Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { + // Import the major distinguishing characteristics of this function. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a function in our own ("to") context with the same name, same + // type, and in the same context as the function we're importing. + if (!LexicalDC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (FunctionDecl *FoundFunction = dyn_cast<FunctionDecl>(*Lookup.first)) { + if (isExternalLinkage(FoundFunction->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundFunction->getType())) { + // FIXME: Actually try to merge the body and other attributes. + return Importer.Imported(D, FoundFunction); + } + + // FIXME: Check for overloading more carefully, e.g., by boosting + // Sema::IsOverload out to the AST library. + + // Function overloading is okay in C++. + if (Importer.getToContext().getLangOptions().CPlusPlus) + continue; + + // Complain about inconsistent function types. + Importer.ToDiag(Loc, diag::err_odr_function_type_inconsistent) + << Name << D->getType() << FoundFunction->getType(); + Importer.ToDiag(FoundFunction->getLocation(), + diag::note_odr_value_here) + << FoundFunction->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + DeclarationNameInfo NameInfo(Name, Loc); + // Import additional name location/type info. + ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Import the function parameters. + llvm::SmallVector<ParmVarDecl *, 8> Parameters; + for (FunctionDecl::param_iterator P = D->param_begin(), PEnd = D->param_end(); + P != PEnd; ++P) { + ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*P)); + if (!ToP) + return 0; + + Parameters.push_back(ToP); + } + + // Create the imported function. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + FunctionDecl *ToFunction = 0; + if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { + ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), + cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), + NameInfo, T, TInfo, + FromConstructor->isExplicit(), + D->isInlineSpecified(), + D->isImplicit()); + } else if (isa<CXXDestructorDecl>(D)) { + ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), + cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), + NameInfo, T, TInfo, + D->isInlineSpecified(), + D->isImplicit()); + } else if (CXXConversionDecl *FromConversion + = dyn_cast<CXXConversionDecl>(D)) { + ToFunction = CXXConversionDecl::Create(Importer.getToContext(), + cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), + NameInfo, T, TInfo, + D->isInlineSpecified(), + FromConversion->isExplicit(), + Importer.Import(D->getLocEnd())); + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + ToFunction = CXXMethodDecl::Create(Importer.getToContext(), + cast<CXXRecordDecl>(DC), + D->getInnerLocStart(), + NameInfo, T, TInfo, + Method->isStatic(), + Method->getStorageClassAsWritten(), + Method->isInlineSpecified(), + Importer.Import(D->getLocEnd())); + } else { + ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, + D->getInnerLocStart(), + NameInfo, T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), + D->isInlineSpecified(), + D->hasWrittenPrototype()); + } + + // Import the qualifier, if any. + ToFunction->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + ToFunction->setAccess(D->getAccess()); + ToFunction->setLexicalDeclContext(LexicalDC); + ToFunction->setVirtualAsWritten(D->isVirtualAsWritten()); + ToFunction->setTrivial(D->isTrivial()); + ToFunction->setPure(D->isPure()); + Importer.Imported(D, ToFunction); + + // Set the parameters. + for (unsigned I = 0, N = Parameters.size(); I != N; ++I) { + Parameters[I]->setOwningFunction(ToFunction); + ToFunction->addDecl(Parameters[I]); + } + ToFunction->setParams(Parameters.data(), Parameters.size()); + + // FIXME: Other bits to merge? + + // Add this function to the lexical context. + LexicalDC->addDecl(ToFunction); + + return ToFunction; +} + +Decl *ASTNodeImporter::VisitCXXMethodDecl(CXXMethodDecl *D) { + return VisitFunctionDecl(D); +} + +Decl *ASTNodeImporter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { + return VisitCXXMethodDecl(D); +} + +Decl *ASTNodeImporter::VisitCXXDestructorDecl(CXXDestructorDecl *D) { + return VisitCXXMethodDecl(D); +} + +Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { + return VisitCXXMethodDecl(D); +} + +Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + Expr *BitWidth = Importer.Import(D->getBitWidth()); + if (!BitWidth && D->getBitWidth()) + return 0; + + FieldDecl *ToField = FieldDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), + Loc, Name.getAsIdentifierInfo(), + T, TInfo, BitWidth, D->isMutable(), + D->hasInClassInitializer()); + ToField->setAccess(D->getAccess()); + ToField->setLexicalDeclContext(LexicalDC); + if (ToField->hasInClassInitializer()) + ToField->setInClassInitializer(D->getInClassInitializer()); + Importer.Imported(D, ToField); + LexicalDC->addDecl(ToField); + return ToField; +} + +Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + NamedDecl **NamedChain = + new (Importer.getToContext())NamedDecl*[D->getChainingSize()]; + + unsigned i = 0; + for (IndirectFieldDecl::chain_iterator PI = D->chain_begin(), + PE = D->chain_end(); PI != PE; ++PI) { + Decl* D = Importer.Import(*PI); + if (!D) + return 0; + NamedChain[i++] = cast<NamedDecl>(D); + } + + IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create( + Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), T, + NamedChain, D->getChainingSize()); + ToIndirectField->setAccess(D->getAccess()); + ToIndirectField->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToIndirectField); + LexicalDC->addDecl(ToIndirectField); + return ToIndirectField; +} + +Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { + // Import the major distinguishing characteristics of an ivar. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Determine whether we've already imported this ivar + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(*Lookup.first)) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundIvar->getType())) { + Importer.Imported(D, FoundIvar); + return FoundIvar; + } + + Importer.ToDiag(Loc, diag::err_odr_ivar_type_inconsistent) + << Name << D->getType() << FoundIvar->getType(); + Importer.ToDiag(FoundIvar->getLocation(), diag::note_odr_value_here) + << FoundIvar->getType(); + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + Expr *BitWidth = Importer.Import(D->getBitWidth()); + if (!BitWidth && D->getBitWidth()) + return 0; + + ObjCIvarDecl *ToIvar = ObjCIvarDecl::Create(Importer.getToContext(), + cast<ObjCContainerDecl>(DC), + Importer.Import(D->getInnerLocStart()), + Loc, Name.getAsIdentifierInfo(), + T, TInfo, D->getAccessControl(), + BitWidth, D->getSynthesize()); + ToIvar->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToIvar); + LexicalDC->addDecl(ToIvar); + return ToIvar; + +} + +Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { + // Import the major distinguishing characteristics of a variable. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Try to find a variable in our own ("to") context with the same name and + // in the same context as the variable we're importing. + if (D->isFileVarDecl()) { + VarDecl *MergeWithVar = 0; + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + unsigned IDNS = Decl::IDNS_Ordinary; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(IDNS)) + continue; + + if (VarDecl *FoundVar = dyn_cast<VarDecl>(*Lookup.first)) { + // We have found a variable that we may need to merge with. Check it. + if (isExternalLinkage(FoundVar->getLinkage()) && + isExternalLinkage(D->getLinkage())) { + if (Importer.IsStructurallyEquivalent(D->getType(), + FoundVar->getType())) { + MergeWithVar = FoundVar; + break; + } + + const ArrayType *FoundArray + = Importer.getToContext().getAsArrayType(FoundVar->getType()); + const ArrayType *TArray + = Importer.getToContext().getAsArrayType(D->getType()); + if (FoundArray && TArray) { + if (isa<IncompleteArrayType>(FoundArray) && + isa<ConstantArrayType>(TArray)) { + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + FoundVar->setType(T); + MergeWithVar = FoundVar; + break; + } else if (isa<IncompleteArrayType>(TArray) && + isa<ConstantArrayType>(FoundArray)) { + MergeWithVar = FoundVar; + break; + } + } + + Importer.ToDiag(Loc, diag::err_odr_variable_type_inconsistent) + << Name << D->getType() << FoundVar->getType(); + Importer.ToDiag(FoundVar->getLocation(), diag::note_odr_value_here) + << FoundVar->getType(); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (MergeWithVar) { + // An equivalent variable with external linkage has been found. Link + // the two declarations, then merge them. + Importer.Imported(D, MergeWithVar); + + if (VarDecl *DDef = D->getDefinition()) { + if (VarDecl *ExistingDef = MergeWithVar->getDefinition()) { + Importer.ToDiag(ExistingDef->getLocation(), + diag::err_odr_variable_multiple_def) + << Name; + Importer.FromDiag(DDef->getLocation(), diag::note_odr_defined_here); + } else { + Expr *Init = Importer.Import(DDef->getInit()); + MergeWithVar->setInit(Init); + } + } + + return MergeWithVar; + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, IDNS, + ConflictingDecls.data(), + ConflictingDecls.size()); + if (!Name) + return 0; + } + } + + // Import the type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported variable. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + VarDecl *ToVar = VarDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), + Loc, Name.getAsIdentifierInfo(), + T, TInfo, + D->getStorageClass(), + D->getStorageClassAsWritten()); + ToVar->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + ToVar->setAccess(D->getAccess()); + ToVar->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToVar); + LexicalDC->addDecl(ToVar); + + // Merge the initializer. + // FIXME: Can we really import any initializer? Alternatively, we could force + // ourselves to import every declaration of a variable and then only use + // getInit() here. + ToVar->setInit(Importer.Import(const_cast<Expr *>(D->getAnyInitializer()))); + + // FIXME: Other bits to merge? + + return ToVar; +} + +Decl *ASTNodeImporter::VisitImplicitParamDecl(ImplicitParamDecl *D) { + // Parameters are created in the translation unit's context, then moved + // into the function declaration's context afterward. + DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); + + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import the parameter's type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported parameter. + ImplicitParamDecl *ToParm + = ImplicitParamDecl::Create(Importer.getToContext(), DC, + Loc, Name.getAsIdentifierInfo(), + T); + return Importer.Imported(D, ToParm); +} + +Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { + // Parameters are created in the translation unit's context, then moved + // into the function declaration's context afterward. + DeclContext *DC = Importer.getToContext().getTranslationUnitDecl(); + + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import the parameter's type. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Create the imported parameter. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + ParmVarDecl *ToParm = ParmVarDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getInnerLocStart()), + Loc, Name.getAsIdentifierInfo(), + T, TInfo, D->getStorageClass(), + D->getStorageClassAsWritten(), + /*FIXME: Default argument*/ 0); + ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); + return Importer.Imported(D, ToParm); +} + +Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { + // Import the major distinguishing characteristics of a method. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(*Lookup.first)) { + if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) + continue; + + // Check return types. + if (!Importer.IsStructurallyEquivalent(D->getResultType(), + FoundMethod->getResultType())) { + Importer.ToDiag(Loc, diag::err_odr_objc_method_result_type_inconsistent) + << D->isInstanceMethod() << Name + << D->getResultType() << FoundMethod->getResultType(); + Importer.ToDiag(FoundMethod->getLocation(), + diag::note_odr_objc_method_here) + << D->isInstanceMethod() << Name; + return 0; + } + + // Check the number of parameters. + if (D->param_size() != FoundMethod->param_size()) { + Importer.ToDiag(Loc, diag::err_odr_objc_method_num_params_inconsistent) + << D->isInstanceMethod() << Name + << D->param_size() << FoundMethod->param_size(); + Importer.ToDiag(FoundMethod->getLocation(), + diag::note_odr_objc_method_here) + << D->isInstanceMethod() << Name; + return 0; + } + + // Check parameter types. + for (ObjCMethodDecl::param_iterator P = D->param_begin(), + PEnd = D->param_end(), FoundP = FoundMethod->param_begin(); + P != PEnd; ++P, ++FoundP) { + if (!Importer.IsStructurallyEquivalent((*P)->getType(), + (*FoundP)->getType())) { + Importer.FromDiag((*P)->getLocation(), + diag::err_odr_objc_method_param_type_inconsistent) + << D->isInstanceMethod() << Name + << (*P)->getType() << (*FoundP)->getType(); + Importer.ToDiag((*FoundP)->getLocation(), diag::note_odr_value_here) + << (*FoundP)->getType(); + return 0; + } + } + + // Check variadic/non-variadic. + // Check the number of parameters. + if (D->isVariadic() != FoundMethod->isVariadic()) { + Importer.ToDiag(Loc, diag::err_odr_objc_method_variadic_inconsistent) + << D->isInstanceMethod() << Name; + Importer.ToDiag(FoundMethod->getLocation(), + diag::note_odr_objc_method_here) + << D->isInstanceMethod() << Name; + return 0; + } + + // FIXME: Any other bits we need to merge? + return Importer.Imported(D, FoundMethod); + } + } + + // Import the result type. + QualType ResultTy = Importer.Import(D->getResultType()); + if (ResultTy.isNull()) + return 0; + + TypeSourceInfo *ResultTInfo = Importer.Import(D->getResultTypeSourceInfo()); + + ObjCMethodDecl *ToMethod + = ObjCMethodDecl::Create(Importer.getToContext(), + Loc, + Importer.Import(D->getLocEnd()), + Name.getObjCSelector(), + ResultTy, ResultTInfo, DC, + D->isInstanceMethod(), + D->isVariadic(), + D->isSynthesized(), + D->isDefined(), + D->getImplementationControl(), + D->hasRelatedResultType()); + + // FIXME: When we decide to merge method definitions, we'll need to + // deal with implicit parameters. + + // Import the parameters + llvm::SmallVector<ParmVarDecl *, 5> ToParams; + for (ObjCMethodDecl::param_iterator FromP = D->param_begin(), + FromPEnd = D->param_end(); + FromP != FromPEnd; + ++FromP) { + ParmVarDecl *ToP = cast_or_null<ParmVarDecl>(Importer.Import(*FromP)); + if (!ToP) + return 0; + + ToParams.push_back(ToP); + } + + // Set the parameters. + for (unsigned I = 0, N = ToParams.size(); I != N; ++I) { + ToParams[I]->setOwningFunction(ToMethod); + ToMethod->addDecl(ToParams[I]); + } + ToMethod->setMethodParams(Importer.getToContext(), + ToParams.data(), ToParams.size(), + ToParams.size()); + + ToMethod->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToMethod); + LexicalDC->addDecl(ToMethod); + return ToMethod; +} + +Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { + // Import the major distinguishing characteristics of a category. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCInterfaceDecl *ToInterface + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getClassInterface())); + if (!ToInterface) + return 0; + + // Determine if we've already encountered this category. + ObjCCategoryDecl *MergeWithCategory + = ToInterface->FindCategoryDeclaration(Name.getAsIdentifierInfo()); + ObjCCategoryDecl *ToCategory = MergeWithCategory; + if (!ToCategory) { + ToCategory = ObjCCategoryDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getAtLoc()), + Loc, + Importer.Import(D->getCategoryNameLoc()), + Name.getAsIdentifierInfo()); + ToCategory->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToCategory); + Importer.Imported(D, ToCategory); + + // Link this category into its class's category list. + ToCategory->setClassInterface(ToInterface); + ToCategory->insertNextClassCategory(); + + // Import protocols + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + ObjCCategoryDecl::protocol_loc_iterator FromProtoLoc + = D->protocol_loc_begin(); + for (ObjCCategoryDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToCategory->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + + } else { + Importer.Imported(D, ToCategory); + } + + // Import all of the members of this category. + ImportDeclContext(D); + + // If we have an implementation, import it as well. + if (D->getImplementation()) { + ObjCCategoryImplDecl *Impl + = cast_or_null<ObjCCategoryImplDecl>( + Importer.Import(D->getImplementation())); + if (!Impl) + return 0; + + ToCategory->setImplementation(Impl); + } + + return ToCategory; +} + +Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { + // Import the major distinguishing characteristics of a protocol. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCProtocolDecl *MergeWithProtocol = 0; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) + continue; + + if ((MergeWithProtocol = dyn_cast<ObjCProtocolDecl>(*Lookup.first))) + break; + } + + ObjCProtocolDecl *ToProto = MergeWithProtocol; + if (!ToProto || ToProto->isForwardDecl()) { + if (!ToProto) { + ToProto = ObjCProtocolDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo()); + ToProto->setForwardDecl(D->isForwardDecl()); + ToProto->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToProto); + } + Importer.Imported(D, ToProto); + + // Import protocols + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + ObjCProtocolDecl::protocol_loc_iterator + FromProtoLoc = D->protocol_loc_begin(); + for (ObjCProtocolDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToProto->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + } else { + Importer.Imported(D, ToProto); + } + + // Import all of the members of this protocol. + ImportDeclContext(D); + + return ToProto; +} + +Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { + // Import the major distinguishing characteristics of an @interface. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + ObjCInterfaceDecl *MergeWithIface = 0; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + if ((MergeWithIface = dyn_cast<ObjCInterfaceDecl>(*Lookup.first))) + break; + } + + ObjCInterfaceDecl *ToIface = MergeWithIface; + if (!ToIface || ToIface->isForwardDecl()) { + if (!ToIface) { + ToIface = ObjCInterfaceDecl::Create(Importer.getToContext(), + DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getClassLoc()), + D->isForwardDecl(), + D->isImplicitInterfaceDecl()); + ToIface->setForwardDecl(D->isForwardDecl()); + ToIface->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToIface); + } + Importer.Imported(D, ToIface); + + if (D->getSuperClass()) { + ObjCInterfaceDecl *Super + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getSuperClass())); + if (!Super) + return 0; + + ToIface->setSuperClass(Super); + ToIface->setSuperClassLoc(Importer.Import(D->getSuperClassLoc())); + } + + // Import protocols + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> ProtocolLocs; + ObjCInterfaceDecl::protocol_loc_iterator + FromProtoLoc = D->protocol_loc_begin(); + + // FIXME: Should we be usng all_referenced_protocol_begin() here? + for (ObjCInterfaceDecl::protocol_iterator FromProto = D->protocol_begin(), + FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + return 0; + Protocols.push_back(ToProto); + ProtocolLocs.push_back(Importer.Import(*FromProtoLoc)); + } + + // FIXME: If we're merging, make sure that the protocol list is the same. + ToIface->setProtocolList(Protocols.data(), Protocols.size(), + ProtocolLocs.data(), Importer.getToContext()); + + // Import @end range + ToIface->setAtEndRange(Importer.Import(D->getAtEndRange())); + } else { + Importer.Imported(D, ToIface); + + // Check for consistency of superclasses. + DeclarationName FromSuperName, ToSuperName; + if (D->getSuperClass()) + FromSuperName = Importer.Import(D->getSuperClass()->getDeclName()); + if (ToIface->getSuperClass()) + ToSuperName = ToIface->getSuperClass()->getDeclName(); + if (FromSuperName != ToSuperName) { + Importer.ToDiag(ToIface->getLocation(), + diag::err_odr_objc_superclass_inconsistent) + << ToIface->getDeclName(); + if (ToIface->getSuperClass()) + Importer.ToDiag(ToIface->getSuperClassLoc(), + diag::note_odr_objc_superclass) + << ToIface->getSuperClass()->getDeclName(); + else + Importer.ToDiag(ToIface->getLocation(), + diag::note_odr_objc_missing_superclass); + if (D->getSuperClass()) + Importer.FromDiag(D->getSuperClassLoc(), + diag::note_odr_objc_superclass) + << D->getSuperClass()->getDeclName(); + else + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_missing_superclass); + return 0; + } + } + + // Import categories. When the categories themselves are imported, they'll + // hook themselves into this interface. + for (ObjCCategoryDecl *FromCat = D->getCategoryList(); FromCat; + FromCat = FromCat->getNextClassCategory()) + Importer.Import(FromCat); + + // Import all of the members of this class. + ImportDeclContext(D); + + // If we have an @implementation, import it as well. + if (D->getImplementation()) { + ObjCImplementationDecl *Impl = cast_or_null<ObjCImplementationDecl>( + Importer.Import(D->getImplementation())); + if (!Impl) + return 0; + + ToIface->setImplementation(Impl); + } + + return ToIface; +} + +Decl *ASTNodeImporter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { + ObjCCategoryDecl *Category = cast_or_null<ObjCCategoryDecl>( + Importer.Import(D->getCategoryDecl())); + if (!Category) + return 0; + + ObjCCategoryImplDecl *ToImpl = Category->getImplementation(); + if (!ToImpl) { + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + ToImpl = ObjCCategoryImplDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocation()), + Importer.Import(D->getIdentifier()), + Category->getClassInterface()); + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + + ToImpl->setLexicalDeclContext(LexicalDC); + } + + LexicalDC->addDecl(ToImpl); + Category->setImplementation(ToImpl); + } + + Importer.Imported(D, ToImpl); + ImportDeclContext(D); + return ToImpl; +} + +Decl *ASTNodeImporter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { + // Find the corresponding interface. + ObjCInterfaceDecl *Iface = cast_or_null<ObjCInterfaceDecl>( + Importer.Import(D->getClassInterface())); + if (!Iface) + return 0; + + // Import the superclass, if any. + ObjCInterfaceDecl *Super = 0; + if (D->getSuperClass()) { + Super = cast_or_null<ObjCInterfaceDecl>( + Importer.Import(D->getSuperClass())); + if (!Super) + return 0; + } + + ObjCImplementationDecl *Impl = Iface->getImplementation(); + if (!Impl) { + // We haven't imported an implementation yet. Create a new @implementation + // now. + Impl = ObjCImplementationDecl::Create(Importer.getToContext(), + Importer.ImportContext(D->getDeclContext()), + Importer.Import(D->getLocation()), + Iface, Super); + + if (D->getDeclContext() != D->getLexicalDeclContext()) { + DeclContext *LexicalDC + = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + Impl->setLexicalDeclContext(LexicalDC); + } + + // Associate the implementation with the class it implements. + Iface->setImplementation(Impl); + Importer.Imported(D, Iface->getImplementation()); + } else { + Importer.Imported(D, Iface->getImplementation()); + + // Verify that the existing @implementation has the same superclass. + if ((Super && !Impl->getSuperClass()) || + (!Super && Impl->getSuperClass()) || + (Super && Impl->getSuperClass() && + Super->getCanonicalDecl() != Impl->getSuperClass())) { + Importer.ToDiag(Impl->getLocation(), + diag::err_odr_objc_superclass_inconsistent) + << Iface->getDeclName(); + // FIXME: It would be nice to have the location of the superclass + // below. + if (Impl->getSuperClass()) + Importer.ToDiag(Impl->getLocation(), + diag::note_odr_objc_superclass) + << Impl->getSuperClass()->getDeclName(); + else + Importer.ToDiag(Impl->getLocation(), + diag::note_odr_objc_missing_superclass); + if (D->getSuperClass()) + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_superclass) + << D->getSuperClass()->getDeclName(); + else + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_missing_superclass); + return 0; + } + } + + // Import all of the members of this @implementation. + ImportDeclContext(D); + + return Impl; +} + +Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { + // Import the major distinguishing characteristics of an @property. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // Check whether we have already imported this property. + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (ObjCPropertyDecl *FoundProp + = dyn_cast<ObjCPropertyDecl>(*Lookup.first)) { + // Check property types. + if (!Importer.IsStructurallyEquivalent(D->getType(), + FoundProp->getType())) { + Importer.ToDiag(Loc, diag::err_odr_objc_property_type_inconsistent) + << Name << D->getType() << FoundProp->getType(); + Importer.ToDiag(FoundProp->getLocation(), diag::note_odr_value_here) + << FoundProp->getType(); + return 0; + } + + // FIXME: Check property attributes, getters, setters, etc.? + + // Consider these properties to be equivalent. + Importer.Imported(D, FoundProp); + return FoundProp; + } + } + + // Import the type. + TypeSourceInfo *T = Importer.Import(D->getTypeSourceInfo()); + if (!T) + return 0; + + // Create the new property. + ObjCPropertyDecl *ToProperty + = ObjCPropertyDecl::Create(Importer.getToContext(), DC, Loc, + Name.getAsIdentifierInfo(), + Importer.Import(D->getAtLoc()), + T, + D->getPropertyImplementation()); + Importer.Imported(D, ToProperty); + ToProperty->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToProperty); + + ToProperty->setPropertyAttributes(D->getPropertyAttributes()); + ToProperty->setPropertyAttributesAsWritten( + D->getPropertyAttributesAsWritten()); + ToProperty->setGetterName(Importer.Import(D->getGetterName())); + ToProperty->setSetterName(Importer.Import(D->getSetterName())); + ToProperty->setGetterMethodDecl( + cast_or_null<ObjCMethodDecl>(Importer.Import(D->getGetterMethodDecl()))); + ToProperty->setSetterMethodDecl( + cast_or_null<ObjCMethodDecl>(Importer.Import(D->getSetterMethodDecl()))); + ToProperty->setPropertyIvarDecl( + cast_or_null<ObjCIvarDecl>(Importer.Import(D->getPropertyIvarDecl()))); + return ToProperty; +} + +Decl *ASTNodeImporter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { + ObjCPropertyDecl *Property = cast_or_null<ObjCPropertyDecl>( + Importer.Import(D->getPropertyDecl())); + if (!Property) + return 0; + + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + // Import the lexical declaration context. + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + ObjCImplDecl *InImpl = dyn_cast<ObjCImplDecl>(LexicalDC); + if (!InImpl) + return 0; + + // Import the ivar (for an @synthesize). + ObjCIvarDecl *Ivar = 0; + if (D->getPropertyIvarDecl()) { + Ivar = cast_or_null<ObjCIvarDecl>( + Importer.Import(D->getPropertyIvarDecl())); + if (!Ivar) + return 0; + } + + ObjCPropertyImplDecl *ToImpl + = InImpl->FindPropertyImplDecl(Property->getIdentifier()); + if (!ToImpl) { + ToImpl = ObjCPropertyImplDecl::Create(Importer.getToContext(), DC, + Importer.Import(D->getLocStart()), + Importer.Import(D->getLocation()), + Property, + D->getPropertyImplementation(), + Ivar, + Importer.Import(D->getPropertyIvarDeclLoc())); + ToImpl->setLexicalDeclContext(LexicalDC); + Importer.Imported(D, ToImpl); + LexicalDC->addDecl(ToImpl); + } else { + // Check that we have the same kind of property implementation (@synthesize + // vs. @dynamic). + if (D->getPropertyImplementation() != ToImpl->getPropertyImplementation()) { + Importer.ToDiag(ToImpl->getLocation(), + diag::err_odr_objc_property_impl_kind_inconsistent) + << Property->getDeclName() + << (ToImpl->getPropertyImplementation() + == ObjCPropertyImplDecl::Dynamic); + Importer.FromDiag(D->getLocation(), + diag::note_odr_objc_property_impl_kind) + << D->getPropertyDecl()->getDeclName() + << (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic); + return 0; + } + + // For @synthesize, check that we have the same + if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize && + Ivar != ToImpl->getPropertyIvarDecl()) { + Importer.ToDiag(ToImpl->getPropertyIvarDeclLoc(), + diag::err_odr_objc_synthesize_ivar_inconsistent) + << Property->getDeclName() + << ToImpl->getPropertyIvarDecl()->getDeclName() + << Ivar->getDeclName(); + Importer.FromDiag(D->getPropertyIvarDeclLoc(), + diag::note_odr_objc_synthesize_ivar_here) + << D->getPropertyIvarDecl()->getDeclName(); + return 0; + } + + // Merge the existing implementation with the new implementation. + Importer.Imported(D, ToImpl); + } + + return ToImpl; +} + +Decl * +ASTNodeImporter::VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *D) { + // Import the context of this declaration. + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + llvm::SmallVector<ObjCProtocolDecl *, 4> Protocols; + llvm::SmallVector<SourceLocation, 4> Locations; + ObjCForwardProtocolDecl::protocol_loc_iterator FromProtoLoc + = D->protocol_loc_begin(); + for (ObjCForwardProtocolDecl::protocol_iterator FromProto + = D->protocol_begin(), FromProtoEnd = D->protocol_end(); + FromProto != FromProtoEnd; + ++FromProto, ++FromProtoLoc) { + ObjCProtocolDecl *ToProto + = cast_or_null<ObjCProtocolDecl>(Importer.Import(*FromProto)); + if (!ToProto) + continue; + + Protocols.push_back(ToProto); + Locations.push_back(Importer.Import(*FromProtoLoc)); + } + + ObjCForwardProtocolDecl *ToForward + = ObjCForwardProtocolDecl::Create(Importer.getToContext(), DC, Loc, + Protocols.data(), Protocols.size(), + Locations.data()); + ToForward->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToForward); + Importer.Imported(D, ToForward); + return ToForward; +} + +Decl *ASTNodeImporter::VisitObjCClassDecl(ObjCClassDecl *D) { + // Import the context of this declaration. + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + llvm::SmallVector<ObjCInterfaceDecl *, 4> Interfaces; + llvm::SmallVector<SourceLocation, 4> Locations; + for (ObjCClassDecl::iterator From = D->begin(), FromEnd = D->end(); + From != FromEnd; ++From) { + ObjCInterfaceDecl *ToIface + = cast_or_null<ObjCInterfaceDecl>(Importer.Import(From->getInterface())); + if (!ToIface) + continue; + + Interfaces.push_back(ToIface); + Locations.push_back(Importer.Import(From->getLocation())); + } + + ObjCClassDecl *ToClass = ObjCClassDecl::Create(Importer.getToContext(), DC, + Loc, + Interfaces.data(), + Locations.data(), + Interfaces.size()); + ToClass->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(ToClass); + Importer.Imported(D, ToClass); + return ToClass; +} + +Decl *ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // For template arguments, we adopt the translation unit as our declaration + // context. This context will be fixed when the actual template declaration + // is created. + + // FIXME: Import default argument. + return TemplateTypeParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getLocStart()), + Importer.Import(D->getLocation()), + D->getDepth(), + D->getIndex(), + Importer.Import(D->getIdentifier()), + D->wasDeclaredWithTypename(), + D->isParameterPack()); +} + +Decl * +ASTNodeImporter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import the type of this declaration. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + + // Import type-source information. + TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); + if (D->getTypeSourceInfo() && !TInfo) + return 0; + + // FIXME: Import default argument. + + return NonTypeTemplateParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Importer.Import(D->getInnerLocStart()), + Loc, D->getDepth(), D->getPosition(), + Name.getAsIdentifierInfo(), + T, D->isParameterPack(), TInfo); +} + +Decl * +ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + // Import the name of this declaration. + DeclarationName Name = Importer.Import(D->getDeclName()); + if (D->getDeclName() && !Name) + return 0; + + // Import the location of this declaration. + SourceLocation Loc = Importer.Import(D->getLocation()); + + // Import template parameters. + TemplateParameterList *TemplateParams + = ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + // FIXME: Import default argument. + + return TemplateTemplateParmDecl::Create(Importer.getToContext(), + Importer.getToContext().getTranslationUnitDecl(), + Loc, D->getDepth(), D->getPosition(), + D->isParameterPack(), + Name.getAsIdentifierInfo(), + TemplateParams); +} + +Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + CXXRecordDecl *Definition + = cast_or_null<CXXRecordDecl>(D->getTemplatedDecl()->getDefinition()); + if (Definition && Definition != D->getTemplatedDecl()) { + Decl *ImportedDef + = Importer.Import(Definition->getDescribedClassTemplate()); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + // Import the major distinguishing characteristics of this class template. + DeclContext *DC, *LexicalDC; + DeclarationName Name; + SourceLocation Loc; + if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + return 0; + + // We may already have a template of the same name; try to find and match it. + if (!DC->isFunctionOrMethod()) { + llvm::SmallVector<NamedDecl *, 4> ConflictingDecls; + for (DeclContext::lookup_result Lookup = DC->lookup(Name); + Lookup.first != Lookup.second; + ++Lookup.first) { + if (!(*Lookup.first)->isInIdentifierNamespace(Decl::IDNS_Ordinary)) + continue; + + Decl *Found = *Lookup.first; + if (ClassTemplateDecl *FoundTemplate + = dyn_cast<ClassTemplateDecl>(Found)) { + if (IsStructuralMatch(D, FoundTemplate)) { + // The class templates structurally match; call it the same template. + // FIXME: We may be filling in a forward declaration here. Handle + // this case! + Importer.Imported(D->getTemplatedDecl(), + FoundTemplate->getTemplatedDecl()); + return Importer.Imported(D, FoundTemplate); + } + } + + ConflictingDecls.push_back(*Lookup.first); + } + + if (!ConflictingDecls.empty()) { + Name = Importer.HandleNameConflict(Name, DC, Decl::IDNS_Ordinary, + ConflictingDecls.data(), + ConflictingDecls.size()); + } + + if (!Name) + return 0; + } + + CXXRecordDecl *DTemplated = D->getTemplatedDecl(); + + // Create the declaration that is being templated. + SourceLocation StartLoc = Importer.Import(DTemplated->getLocStart()); + SourceLocation IdLoc = Importer.Import(DTemplated->getLocation()); + CXXRecordDecl *D2Templated = CXXRecordDecl::Create(Importer.getToContext(), + DTemplated->getTagKind(), + DC, StartLoc, IdLoc, + Name.getAsIdentifierInfo()); + D2Templated->setAccess(DTemplated->getAccess()); + D2Templated->setQualifierInfo(Importer.Import(DTemplated->getQualifierLoc())); + D2Templated->setLexicalDeclContext(LexicalDC); + + // Create the class template declaration itself. + TemplateParameterList *TemplateParams + = ImportTemplateParameterList(D->getTemplateParameters()); + if (!TemplateParams) + return 0; + + ClassTemplateDecl *D2 = ClassTemplateDecl::Create(Importer.getToContext(), DC, + Loc, Name, TemplateParams, + D2Templated, + /*PrevDecl=*/0); + D2Templated->setDescribedClassTemplate(D2); + + D2->setAccess(D->getAccess()); + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + + // Note the relationship between the class templates. + Importer.Imported(D, D2); + Importer.Imported(DTemplated, D2Templated); + + if (DTemplated->isDefinition() && !D2Templated->isDefinition()) { + // FIXME: Import definition! + } + + return D2; +} + +Decl *ASTNodeImporter::VisitClassTemplateSpecializationDecl( + ClassTemplateSpecializationDecl *D) { + // If this record has a definition in the translation unit we're coming from, + // but this particular declaration is not that definition, import the + // definition and map to that. + TagDecl *Definition = D->getDefinition(); + if (Definition && Definition != D) { + Decl *ImportedDef = Importer.Import(Definition); + if (!ImportedDef) + return 0; + + return Importer.Imported(D, ImportedDef); + } + + ClassTemplateDecl *ClassTemplate + = cast_or_null<ClassTemplateDecl>(Importer.Import( + D->getSpecializedTemplate())); + if (!ClassTemplate) + return 0; + + // Import the context of this declaration. + DeclContext *DC = ClassTemplate->getDeclContext(); + if (!DC) + return 0; + + DeclContext *LexicalDC = DC; + if (D->getDeclContext() != D->getLexicalDeclContext()) { + LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + if (!LexicalDC) + return 0; + } + + // Import the location of this declaration. + SourceLocation StartLoc = Importer.Import(D->getLocStart()); + SourceLocation IdLoc = Importer.Import(D->getLocation()); + + // Import template arguments. + llvm::SmallVector<TemplateArgument, 2> TemplateArgs; + if (ImportTemplateArguments(D->getTemplateArgs().data(), + D->getTemplateArgs().size(), + TemplateArgs)) + return 0; + + // Try to find an existing specialization with these template arguments. + void *InsertPos = 0; + ClassTemplateSpecializationDecl *D2 + = ClassTemplate->findSpecialization(TemplateArgs.data(), + TemplateArgs.size(), InsertPos); + if (D2) { + // We already have a class template specialization with these template + // arguments. + + // FIXME: Check for specialization vs. instantiation errors. + + if (RecordDecl *FoundDef = D2->getDefinition()) { + if (!D->isDefinition() || IsStructuralMatch(D, FoundDef)) { + // The record types structurally match, or the "from" translation + // unit only had a forward declaration anyway; call it the same + // function. + return Importer.Imported(D, FoundDef); + } + } + } else { + // Create a new specialization. + D2 = ClassTemplateSpecializationDecl::Create(Importer.getToContext(), + D->getTagKind(), DC, + StartLoc, IdLoc, + ClassTemplate, + TemplateArgs.data(), + TemplateArgs.size(), + /*PrevDecl=*/0); + D2->setSpecializationKind(D->getSpecializationKind()); + + // Add this specialization to the class template. + ClassTemplate->AddSpecialization(D2, InsertPos); + + // Import the qualifier, if any. + D2->setQualifierInfo(Importer.Import(D->getQualifierLoc())); + + // Add the specialization to this context. + D2->setLexicalDeclContext(LexicalDC); + LexicalDC->addDecl(D2); + } + Importer.Imported(D, D2); + + if (D->isDefinition() && ImportDefinition(D, D2)) + return 0; + + return D2; +} + +//---------------------------------------------------------------------------- +// Import Statements +//---------------------------------------------------------------------------- + +Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { + Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) + << S->getStmtClassName(); + return 0; +} + +//---------------------------------------------------------------------------- +// Import Expressions +//---------------------------------------------------------------------------- +Expr *ASTNodeImporter::VisitExpr(Expr *E) { + Importer.FromDiag(E->getLocStart(), diag::err_unsupported_ast_node) + << E->getStmtClassName(); + return 0; +} + +Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { + ValueDecl *ToD = cast_or_null<ValueDecl>(Importer.Import(E->getDecl())); + if (!ToD) + return 0; + + NamedDecl *FoundD = 0; + if (E->getDecl() != E->getFoundDecl()) { + FoundD = cast_or_null<NamedDecl>(Importer.Import(E->getFoundDecl())); + if (!FoundD) + return 0; + } + + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + return DeclRefExpr::Create(Importer.getToContext(), + Importer.Import(E->getQualifierLoc()), + ToD, + Importer.Import(E->getLocation()), + T, E->getValueKind(), + FoundD, + /*FIXME:TemplateArgs=*/0); +} + +Expr *ASTNodeImporter::VisitIntegerLiteral(IntegerLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + return IntegerLiteral::Create(Importer.getToContext(), + E->getValue(), T, + Importer.Import(E->getLocation())); +} + +Expr *ASTNodeImporter::VisitCharacterLiteral(CharacterLiteral *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + return new (Importer.getToContext()) CharacterLiteral(E->getValue(), + E->isWide(), T, + Importer.Import(E->getLocation())); +} + +Expr *ASTNodeImporter::VisitParenExpr(ParenExpr *E) { + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + return new (Importer.getToContext()) + ParenExpr(Importer.Import(E->getLParen()), + Importer.Import(E->getRParen()), + SubExpr); +} + +Expr *ASTNodeImporter::VisitUnaryOperator(UnaryOperator *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + return new (Importer.getToContext()) UnaryOperator(SubExpr, E->getOpcode(), + T, E->getValueKind(), + E->getObjectKind(), + Importer.Import(E->getOperatorLoc())); +} + +Expr *ASTNodeImporter::VisitUnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTraitExpr *E) { + QualType ResultType = Importer.Import(E->getType()); + + if (E->isArgumentType()) { + TypeSourceInfo *TInfo = Importer.Import(E->getArgumentTypeInfo()); + if (!TInfo) + return 0; + + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + TInfo, ResultType, + Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getRParenLoc())); + } + + Expr *SubExpr = Importer.Import(E->getArgumentExpr()); + if (!SubExpr) + return 0; + + return new (Importer.getToContext()) UnaryExprOrTypeTraitExpr(E->getKind(), + SubExpr, ResultType, + Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getRParenLoc())); +} + +Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *LHS = Importer.Import(E->getLHS()); + if (!LHS) + return 0; + + Expr *RHS = Importer.Import(E->getRHS()); + if (!RHS) + return 0; + + return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(), + T, E->getValueKind(), + E->getObjectKind(), + Importer.Import(E->getOperatorLoc())); +} + +Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + QualType CompLHSType = Importer.Import(E->getComputationLHSType()); + if (CompLHSType.isNull()) + return 0; + + QualType CompResultType = Importer.Import(E->getComputationResultType()); + if (CompResultType.isNull()) + return 0; + + Expr *LHS = Importer.Import(E->getLHS()); + if (!LHS) + return 0; + + Expr *RHS = Importer.Import(E->getRHS()); + if (!RHS) + return 0; + + return new (Importer.getToContext()) + CompoundAssignOperator(LHS, RHS, E->getOpcode(), + T, E->getValueKind(), + E->getObjectKind(), + CompLHSType, CompResultType, + Importer.Import(E->getOperatorLoc())); +} + +static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { + if (E->path_empty()) return false; + + // TODO: import cast paths + return true; +} + +Expr *ASTNodeImporter::VisitImplicitCastExpr(ImplicitCastExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + CXXCastPath BasePath; + if (ImportCastPath(E, BasePath)) + return 0; + + return ImplicitCastExpr::Create(Importer.getToContext(), T, E->getCastKind(), + SubExpr, &BasePath, E->getValueKind()); +} + +Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return 0; + + Expr *SubExpr = Importer.Import(E->getSubExpr()); + if (!SubExpr) + return 0; + + TypeSourceInfo *TInfo = Importer.Import(E->getTypeInfoAsWritten()); + if (!TInfo && E->getTypeInfoAsWritten()) + return 0; + + CXXCastPath BasePath; + if (ImportCastPath(E, BasePath)) + return 0; + + return CStyleCastExpr::Create(Importer.getToContext(), T, + E->getValueKind(), E->getCastKind(), + SubExpr, &BasePath, TInfo, + Importer.Import(E->getLParenLoc()), + Importer.Import(E->getRParenLoc())); +} + +ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, + ASTContext &FromContext, FileManager &FromFileManager, + bool MinimalImport) + : ToContext(ToContext), FromContext(FromContext), + ToFileManager(ToFileManager), FromFileManager(FromFileManager), + Minimal(MinimalImport) +{ + ImportedDecls[FromContext.getTranslationUnitDecl()] + = ToContext.getTranslationUnitDecl(); +} + +ASTImporter::~ASTImporter() { } + +QualType ASTImporter::Import(QualType FromT) { + if (FromT.isNull()) + return QualType(); + + const Type *fromTy = FromT.getTypePtr(); + + // Check whether we've already imported this type. + llvm::DenseMap<const Type *, const Type *>::iterator Pos + = ImportedTypes.find(fromTy); + if (Pos != ImportedTypes.end()) + return ToContext.getQualifiedType(Pos->second, FromT.getLocalQualifiers()); + + // Import the type + ASTNodeImporter Importer(*this); + QualType ToT = Importer.Visit(fromTy); + if (ToT.isNull()) + return ToT; + + // Record the imported type. + ImportedTypes[fromTy] = ToT.getTypePtr(); + + return ToContext.getQualifiedType(ToT, FromT.getLocalQualifiers()); +} + +TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { + if (!FromTSI) + return FromTSI; + + // FIXME: For now we just create a "trivial" type source info based + // on the type and a single location. Implement a real version of this. + QualType T = Import(FromTSI->getType()); + if (T.isNull()) + return 0; + + return ToContext.getTrivialTypeSourceInfo(T, + FromTSI->getTypeLoc().getSourceRange().getBegin()); +} + +Decl *ASTImporter::Import(Decl *FromD) { + if (!FromD) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Decl *ToD = Importer.Visit(FromD); + if (!ToD) + return 0; + + // Record the imported declaration. + ImportedDecls[FromD] = ToD; + + if (TagDecl *FromTag = dyn_cast<TagDecl>(FromD)) { + // Keep track of anonymous tags that have an associated typedef. + if (FromTag->getTypedefNameForAnonDecl()) + AnonTagsWithPendingTypedefs.push_back(FromTag); + } else if (TypedefNameDecl *FromTypedef = dyn_cast<TypedefNameDecl>(FromD)) { + // When we've finished transforming a typedef, see whether it was the + // typedef for an anonymous tag. + for (llvm::SmallVector<TagDecl *, 4>::iterator + FromTag = AnonTagsWithPendingTypedefs.begin(), + FromTagEnd = AnonTagsWithPendingTypedefs.end(); + FromTag != FromTagEnd; ++FromTag) { + if ((*FromTag)->getTypedefNameForAnonDecl() == FromTypedef) { + if (TagDecl *ToTag = cast_or_null<TagDecl>(Import(*FromTag))) { + // We found the typedef for an anonymous tag; link them. + ToTag->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(ToD)); + AnonTagsWithPendingTypedefs.erase(FromTag); + break; + } + } + } + } + + return ToD; +} + +DeclContext *ASTImporter::ImportContext(DeclContext *FromDC) { + if (!FromDC) + return FromDC; + + return cast_or_null<DeclContext>(Import(cast<Decl>(FromDC))); +} + +Expr *ASTImporter::Import(Expr *FromE) { + if (!FromE) + return 0; + + return cast_or_null<Expr>(Import(cast<Stmt>(FromE))); +} + +Stmt *ASTImporter::Import(Stmt *FromS) { + if (!FromS) + return 0; + + // Check whether we've already imported this declaration. + llvm::DenseMap<Stmt *, Stmt *>::iterator Pos = ImportedStmts.find(FromS); + if (Pos != ImportedStmts.end()) + return Pos->second; + + // Import the type + ASTNodeImporter Importer(*this); + Stmt *ToS = Importer.Visit(FromS); + if (!ToS) + return 0; + + // Record the imported declaration. + ImportedStmts[FromS] = ToS; + return ToS; +} + +NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { + if (!FromNNS) + return 0; + + NestedNameSpecifier *prefix = Import(FromNNS->getPrefix()); + + switch (FromNNS->getKind()) { + case NestedNameSpecifier::Identifier: + if (IdentifierInfo *II = Import(FromNNS->getAsIdentifier())) { + return NestedNameSpecifier::Create(ToContext, prefix, II); + } + return 0; + + case NestedNameSpecifier::Namespace: + if (NamespaceDecl *NS = + cast<NamespaceDecl>(Import(FromNNS->getAsNamespace()))) { + return NestedNameSpecifier::Create(ToContext, prefix, NS); + } + return 0; + + case NestedNameSpecifier::NamespaceAlias: + if (NamespaceAliasDecl *NSAD = + cast<NamespaceAliasDecl>(Import(FromNNS->getAsNamespaceAlias()))) { + return NestedNameSpecifier::Create(ToContext, prefix, NSAD); + } + return 0; + + case NestedNameSpecifier::Global: + return NestedNameSpecifier::GlobalSpecifier(ToContext); + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + QualType T = Import(QualType(FromNNS->getAsType(), 0u)); + if (!T.isNull()) { + bool bTemplate = FromNNS->getKind() == + NestedNameSpecifier::TypeSpecWithTemplate; + return NestedNameSpecifier::Create(ToContext, prefix, + bTemplate, T.getTypePtr()); + } + } + return 0; + } + + llvm_unreachable("Invalid nested name specifier kind"); + return 0; +} + +NestedNameSpecifierLoc ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { + // FIXME: Implement! + return NestedNameSpecifierLoc(); +} + +TemplateName ASTImporter::Import(TemplateName From) { + switch (From.getKind()) { + case TemplateName::Template: + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return TemplateName(ToTemplate); + + return TemplateName(); + + case TemplateName::OverloadedTemplate: { + OverloadedTemplateStorage *FromStorage = From.getAsOverloadedTemplate(); + UnresolvedSet<2> ToTemplates; + for (OverloadedTemplateStorage::iterator I = FromStorage->begin(), + E = FromStorage->end(); + I != E; ++I) { + if (NamedDecl *To = cast_or_null<NamedDecl>(Import(*I))) + ToTemplates.addDecl(To); + else + return TemplateName(); + } + return ToContext.getOverloadedTemplateName(ToTemplates.begin(), + ToTemplates.end()); + } + + case TemplateName::QualifiedTemplate: { + QualifiedTemplateName *QTN = From.getAsQualifiedTemplateName(); + NestedNameSpecifier *Qualifier = Import(QTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (TemplateDecl *ToTemplate + = cast_or_null<TemplateDecl>(Import(From.getAsTemplateDecl()))) + return ToContext.getQualifiedTemplateName(Qualifier, + QTN->hasTemplateKeyword(), + ToTemplate); + + return TemplateName(); + } + + case TemplateName::DependentTemplate: { + DependentTemplateName *DTN = From.getAsDependentTemplateName(); + NestedNameSpecifier *Qualifier = Import(DTN->getQualifier()); + if (!Qualifier) + return TemplateName(); + + if (DTN->isIdentifier()) { + return ToContext.getDependentTemplateName(Qualifier, + Import(DTN->getIdentifier())); + } + + return ToContext.getDependentTemplateName(Qualifier, DTN->getOperator()); + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = From.getAsSubstTemplateTemplateParmPack(); + TemplateTemplateParmDecl *Param + = cast_or_null<TemplateTemplateParmDecl>( + Import(SubstPack->getParameterPack())); + if (!Param) + return TemplateName(); + + ASTNodeImporter Importer(*this); + TemplateArgument ArgPack + = Importer.ImportTemplateArgument(SubstPack->getArgumentPack()); + if (ArgPack.isNull()) + return TemplateName(); + + return ToContext.getSubstTemplateTemplateParmPack(Param, ArgPack); + } + } + + llvm_unreachable("Invalid template name kind"); + return TemplateName(); +} + +SourceLocation ASTImporter::Import(SourceLocation FromLoc) { + if (FromLoc.isInvalid()) + return SourceLocation(); + + SourceManager &FromSM = FromContext.getSourceManager(); + + // For now, map everything down to its spelling location, so that we + // don't have to import macro instantiations. + // FIXME: Import macro instantiations! + FromLoc = FromSM.getSpellingLoc(FromLoc); + std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); + SourceManager &ToSM = ToContext.getSourceManager(); + return ToSM.getLocForStartOfFile(Import(Decomposed.first)) + .getFileLocWithOffset(Decomposed.second); +} + +SourceRange ASTImporter::Import(SourceRange FromRange) { + return SourceRange(Import(FromRange.getBegin()), Import(FromRange.getEnd())); +} + +FileID ASTImporter::Import(FileID FromID) { + llvm::DenseMap<FileID, FileID>::iterator Pos + = ImportedFileIDs.find(FromID); + if (Pos != ImportedFileIDs.end()) + return Pos->second; + + SourceManager &FromSM = FromContext.getSourceManager(); + SourceManager &ToSM = ToContext.getSourceManager(); + const SrcMgr::SLocEntry &FromSLoc = FromSM.getSLocEntry(FromID); + assert(FromSLoc.isFile() && "Cannot handle macro instantiations yet"); + + // Include location of this file. + SourceLocation ToIncludeLoc = Import(FromSLoc.getFile().getIncludeLoc()); + + // Map the FileID for to the "to" source manager. + FileID ToID; + const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); + if (Cache->OrigEntry) { + // FIXME: We probably want to use getVirtualFile(), so we don't hit the + // disk again + // FIXME: We definitely want to re-use the existing MemoryBuffer, rather + // than mmap the files several times. + const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); + ToID = ToSM.createFileID(Entry, ToIncludeLoc, + FromSLoc.getFile().getFileCharacteristic()); + } else { + // FIXME: We want to re-use the existing MemoryBuffer! + const llvm::MemoryBuffer * + FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM); + llvm::MemoryBuffer *ToBuf + = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), + FromBuf->getBufferIdentifier()); + ToID = ToSM.createFileIDForMemBuffer(ToBuf); + } + + + ImportedFileIDs[FromID] = ToID; + return ToID; +} + +void ASTImporter::ImportDefinition(Decl *From) { + Decl *To = Import(From); + if (!To) + return; + + if (DeclContext *FromDC = cast<DeclContext>(From)) { + ASTNodeImporter Importer(*this); + Importer.ImportDeclContext(FromDC, true); + } +} + +DeclarationName ASTImporter::Import(DeclarationName FromName) { + if (!FromName) + return DeclarationName(); + + switch (FromName.getNameKind()) { + case DeclarationName::Identifier: + return Import(FromName.getAsIdentifierInfo()); + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + return Import(FromName.getObjCSelector()); + + case DeclarationName::CXXConstructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConstructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXDestructorName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXDestructorName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXConversionFunctionName: { + QualType T = Import(FromName.getCXXNameType()); + if (T.isNull()) + return DeclarationName(); + + return ToContext.DeclarationNames.getCXXConversionFunctionName( + ToContext.getCanonicalType(T)); + } + + case DeclarationName::CXXOperatorName: + return ToContext.DeclarationNames.getCXXOperatorName( + FromName.getCXXOverloadedOperator()); + + case DeclarationName::CXXLiteralOperatorName: + return ToContext.DeclarationNames.getCXXLiteralOperatorName( + Import(FromName.getCXXLiteralIdentifier())); + + case DeclarationName::CXXUsingDirective: + // FIXME: STATICS! + return DeclarationName::getUsingDirectiveName(); + } + + // Silence bogus GCC warning + return DeclarationName(); +} + +IdentifierInfo *ASTImporter::Import(const IdentifierInfo *FromId) { + if (!FromId) + return 0; + + return &ToContext.Idents.get(FromId->getName()); +} + +Selector ASTImporter::Import(Selector FromSel) { + if (FromSel.isNull()) + return Selector(); + + llvm::SmallVector<IdentifierInfo *, 4> Idents; + Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); + for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I) + Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I))); + return ToContext.Selectors.getSelector(FromSel.getNumArgs(), Idents.data()); +} + +DeclarationName ASTImporter::HandleNameConflict(DeclarationName Name, + DeclContext *DC, + unsigned IDNS, + NamedDecl **Decls, + unsigned NumDecls) { + return Name; +} + +DiagnosticBuilder ASTImporter::ToDiag(SourceLocation Loc, unsigned DiagID) { + return ToContext.getDiagnostics().Report(Loc, DiagID); +} + +DiagnosticBuilder ASTImporter::FromDiag(SourceLocation Loc, unsigned DiagID) { + return FromContext.getDiagnostics().Report(Loc, DiagID); +} + +Decl *ASTImporter::Imported(Decl *From, Decl *To) { + ImportedDecls[From] = To; + return To; +} + +bool ASTImporter::IsStructurallyEquivalent(QualType From, QualType To) { + llvm::DenseMap<const Type *, const Type *>::iterator Pos + = ImportedTypes.find(From.getTypePtr()); + if (Pos != ImportedTypes.end() && ToContext.hasSameType(Import(From), To)) + return true; + + StructuralEquivalenceContext Ctx(FromContext, ToContext, NonEquivalentDecls); + return Ctx.IsStructurallyEquivalent(From, To); +} diff --git a/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp b/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp new file mode 100644 index 000000000000..3ca7d4d01d1c --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/AttrImpl.cpp @@ -0,0 +1,22 @@ +//===--- AttrImpl.cpp - Classes for representing attributes -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains out-of-line virtual methods for Attr classes. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Type.h" +#include "clang/AST/Expr.h" +using namespace clang; + +Attr::~Attr() { } + +#include "clang/AST/AttrImpl.inc" diff --git a/contrib/llvm/tools/clang/lib/AST/CXXABI.h b/contrib/llvm/tools/clang/lib/AST/CXXABI.h new file mode 100644 index 000000000000..943c43e79198 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/CXXABI.h @@ -0,0 +1,48 @@ +//===----- CXXABI.h - Interface to C++ ABIs ---------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides an abstract class for C++ AST support. Concrete +// subclasses of this implement AST support for specific C++ ABIs. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_CXXABI_H +#define LLVM_CLANG_AST_CXXABI_H + +#include "clang/AST/Type.h" + +namespace clang { + +class ASTContext; +class MemberPointerType; + +/// Implements C++ ABI-specific semantic analysis functions. +class CXXABI { +public: + virtual ~CXXABI(); + + /// Returns the size of a member pointer in multiples of the target + /// pointer size. + virtual unsigned getMemberPointerSize(const MemberPointerType *MPT) const = 0; + + /// Returns the default calling convention for C++ methods. + virtual CallingConv getDefaultMethodCallConv() const = 0; + + // Returns whether the given class is nearly empty, with just virtual pointers + // and no data except possibly virtual bases. + virtual bool isNearlyEmpty(const CXXRecordDecl *RD) const = 0; +}; + +/// Creates an instance of a C++ ABI class. +CXXABI *CreateARMCXXABI(ASTContext &Ctx); +CXXABI *CreateItaniumCXXABI(ASTContext &Ctx); +CXXABI *CreateMicrosoftCXXABI(ASTContext &Ctx); +} + +#endif diff --git a/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp new file mode 100644 index 000000000000..9ffe1f865689 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/CXXInheritance.cpp @@ -0,0 +1,715 @@ +//===------ CXXInheritance.cpp - C++ 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 provides routines that help analyzing C++ inheritance hierarchies. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/DeclCXX.h" +#include <algorithm> +#include <set> + +using namespace clang; + +/// \brief Computes the set of declarations referenced by these base +/// paths. +void CXXBasePaths::ComputeDeclsFound() { + assert(NumDeclsFound == 0 && !DeclsFound && + "Already computed the set of declarations"); + + std::set<NamedDecl *> Decls; + for (CXXBasePaths::paths_iterator Path = begin(), PathEnd = end(); + Path != PathEnd; ++Path) + Decls.insert(*Path->Decls.first); + + NumDeclsFound = Decls.size(); + DeclsFound = new NamedDecl * [NumDeclsFound]; + std::copy(Decls.begin(), Decls.end(), DeclsFound); +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_begin() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound; +} + +CXXBasePaths::decl_iterator CXXBasePaths::found_decls_end() { + if (NumDeclsFound == 0) + ComputeDeclsFound(); + return DeclsFound + NumDeclsFound; +} + +/// isAmbiguous - Determines whether the set of paths provided is +/// ambiguous, i.e., there are two or more paths that refer to +/// different base class subobjects of the same type. BaseType must be +/// an unqualified, canonical class type. +bool CXXBasePaths::isAmbiguous(CanQualType BaseType) { + BaseType = BaseType.getUnqualifiedType(); + std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; + return Subobjects.second + (Subobjects.first? 1 : 0) > 1; +} + +/// clear - Clear out all prior path information. +void CXXBasePaths::clear() { + Paths.clear(); + ClassSubobjects.clear(); + ScratchPath.clear(); + DetectedVirtual = 0; +} + +/// @brief Swaps the contents of this CXXBasePaths structure with the +/// contents of Other. +void CXXBasePaths::swap(CXXBasePaths &Other) { + std::swap(Origin, Other.Origin); + Paths.swap(Other.Paths); + ClassSubobjects.swap(Other.ClassSubobjects); + std::swap(FindAmbiguities, Other.FindAmbiguities); + std::swap(RecordPaths, Other.RecordPaths); + std::swap(DetectVirtual, Other.DetectVirtual); + std::swap(DetectedVirtual, Other.DetectedVirtual); +} + +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base) const { + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + return isDerivedFrom(Base, Paths); +} + +bool CXXRecordDecl::isDerivedFrom(const CXXRecordDecl *Base, + CXXBasePaths &Paths) const { + if (getCanonicalDecl() == Base->getCanonicalDecl()) + return false; + + Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); + return lookupInBases(&FindBaseClass, + const_cast<CXXRecordDecl*>(Base->getCanonicalDecl()), + Paths); +} + +bool CXXRecordDecl::isVirtuallyDerivedFrom(CXXRecordDecl *Base) const { + if (!getNumVBases()) + return false; + + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/false, + /*DetectVirtual=*/false); + + if (getCanonicalDecl() == Base->getCanonicalDecl()) + return false; + + Paths.setOrigin(const_cast<CXXRecordDecl*>(this)); + return lookupInBases(&FindVirtualBaseClass, Base->getCanonicalDecl(), Paths); +} + +static bool BaseIsNot(const CXXRecordDecl *Base, void *OpaqueTarget) { + // OpaqueTarget is a CXXRecordDecl*. + return Base->getCanonicalDecl() != (const CXXRecordDecl*) OpaqueTarget; +} + +bool CXXRecordDecl::isProvablyNotDerivedFrom(const CXXRecordDecl *Base) const { + return forallBases(BaseIsNot, (void*) Base->getCanonicalDecl()); +} + +bool CXXRecordDecl::forallBases(ForallBasesCallback *BaseMatches, + void *OpaqueData, + bool AllowShortCircuit) const { + llvm::SmallVector<const CXXRecordDecl*, 8> Queue; + + const CXXRecordDecl *Record = this; + bool AllMatches = true; + while (true) { + for (CXXRecordDecl::base_class_const_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *Ty = I->getType()->getAs<RecordType>(); + if (!Ty) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + CXXRecordDecl *Base = + cast_or_null<CXXRecordDecl>(Ty->getDecl()->getDefinition()); + if (!Base) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + + Queue.push_back(Base); + if (!BaseMatches(Base, OpaqueData)) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; + } + } + + if (Queue.empty()) break; + Record = Queue.back(); // not actually a queue. + Queue.pop_back(); + } + + return AllMatches; +} + +bool CXXBasePaths::lookupInBases(ASTContext &Context, + const CXXRecordDecl *Record, + CXXRecordDecl::BaseMatchesCallback *BaseMatches, + void *UserData) { + bool FoundPath = false; + + // The access of the path down to this record. + AccessSpecifier AccessToHere = ScratchPath.Access; + bool IsFirstStep = ScratchPath.empty(); + + for (CXXRecordDecl::base_class_const_iterator BaseSpec = Record->bases_begin(), + BaseSpecEnd = Record->bases_end(); + BaseSpec != BaseSpecEnd; + ++BaseSpec) { + // Find the record of the base class subobjects for this type. + QualType BaseType = Context.getCanonicalType(BaseSpec->getType()) + .getUnqualifiedType(); + + // C++ [temp.dep]p3: + // In the definition of a class template or a member of a class template, + // if a base class of the class template depends on a template-parameter, + // the base class scope is not examined during unqualified name lookup + // either at the point of definition of the class template or member or + // during an instantiation of the class tem- plate or member. + if (BaseType->isDependentType()) + continue; + + // Determine whether we need to visit this base class at all, + // updating the count of subobjects appropriately. + std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; + bool VisitBase = true; + bool SetVirtual = false; + if (BaseSpec->isVirtual()) { + VisitBase = !Subobjects.first; + Subobjects.first = true; + if (isDetectingVirtual() && DetectedVirtual == 0) { + // If this is the first virtual we find, remember it. If it turns out + // there is no base path here, we'll reset it later. + DetectedVirtual = BaseType->getAs<RecordType>(); + SetVirtual = true; + } + } else + ++Subobjects.second; + + if (isRecordingPaths()) { + // Add this base specifier to the current path. + CXXBasePathElement Element; + Element.Base = &*BaseSpec; + Element.Class = Record; + if (BaseSpec->isVirtual()) + Element.SubobjectNumber = 0; + else + Element.SubobjectNumber = Subobjects.second; + ScratchPath.push_back(Element); + + // Calculate the "top-down" access to this base class. + // The spec actually describes this bottom-up, but top-down is + // equivalent because the definition works out as follows: + // 1. Write down the access along each step in the inheritance + // chain, followed by the access of the decl itself. + // For example, in + // class A { public: int foo; }; + // class B : protected A {}; + // class C : public B {}; + // class D : private C {}; + // we would write: + // private public protected public + // 2. If 'private' appears anywhere except far-left, access is denied. + // 3. Otherwise, overall access is determined by the most restrictive + // access in the sequence. + if (IsFirstStep) + ScratchPath.Access = BaseSpec->getAccessSpecifier(); + else + ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere, + BaseSpec->getAccessSpecifier()); + } + + // Track whether there's a path involving this specific base. + bool FoundPathThroughBase = false; + + if (BaseMatches(BaseSpec, ScratchPath, UserData)) { + // We've found a path that terminates at this base. + FoundPath = FoundPathThroughBase = true; + if (isRecordingPaths()) { + // We have a path. Make a copy of it before moving on. + Paths.push_back(ScratchPath); + } else if (!isFindingAmbiguities()) { + // We found a path and we don't care about ambiguities; + // return immediately. + return FoundPath; + } + } else if (VisitBase) { + CXXRecordDecl *BaseRecord + = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>() + ->getDecl()); + if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) { + // C++ [class.member.lookup]p2: + // A member name f in one sub-object B hides a member name f in + // a sub-object A if A is a base class sub-object of B. Any + // declarations that are so hidden are eliminated from + // consideration. + + // There is a path to a base class that meets the criteria. If we're + // not collecting paths or finding ambiguities, we're done. + FoundPath = FoundPathThroughBase = true; + if (!isFindingAmbiguities()) + return FoundPath; + } + } + + // Pop this base specifier off the current path (if we're + // collecting paths). + if (isRecordingPaths()) { + ScratchPath.pop_back(); + } + + // If we set a virtual earlier, and this isn't a path, forget it again. + if (SetVirtual && !FoundPathThroughBase) { + DetectedVirtual = 0; + } + } + + // Reset the scratch path access. + ScratchPath.Access = AccessToHere; + + return FoundPath; +} + +bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, + void *UserData, + CXXBasePaths &Paths) const { + // If we didn't find anything, report that. + if (!Paths.lookupInBases(getASTContext(), this, BaseMatches, UserData)) + return false; + + // If we're not recording paths or we won't ever find ambiguities, + // we're done. + if (!Paths.isRecordingPaths() || !Paths.isFindingAmbiguities()) + return true; + + // C++ [class.member.lookup]p6: + // When virtual base classes are used, a hidden declaration can be + // reached along a path through the sub-object lattice that does + // not pass through the hiding declaration. This is not an + // ambiguity. The identical use with nonvirtual base classes is an + // ambiguity; in that case there is no unique instance of the name + // that hides all the others. + // + // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy + // way to make it any faster. + for (CXXBasePaths::paths_iterator P = Paths.begin(), PEnd = Paths.end(); + P != PEnd; /* increment in loop */) { + bool Hidden = false; + + for (CXXBasePath::iterator PE = P->begin(), PEEnd = P->end(); + PE != PEEnd && !Hidden; ++PE) { + if (PE->Base->isVirtual()) { + CXXRecordDecl *VBase = 0; + if (const RecordType *Record = PE->Base->getType()->getAs<RecordType>()) + VBase = cast<CXXRecordDecl>(Record->getDecl()); + if (!VBase) + break; + + // The declaration(s) we found along this path were found in a + // subobject of a virtual base. Check whether this virtual + // base is a subobject of any other path; if so, then the + // declaration in this path are hidden by that patch. + for (CXXBasePaths::paths_iterator HidingP = Paths.begin(), + HidingPEnd = Paths.end(); + HidingP != HidingPEnd; + ++HidingP) { + CXXRecordDecl *HidingClass = 0; + if (const RecordType *Record + = HidingP->back().Base->getType()->getAs<RecordType>()) + HidingClass = cast<CXXRecordDecl>(Record->getDecl()); + if (!HidingClass) + break; + + if (HidingClass->isVirtuallyDerivedFrom(VBase)) { + Hidden = true; + break; + } + } + } + } + + if (Hidden) + P = Paths.Paths.erase(P); + else + ++P; + } + + return true; +} + +bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *BaseRecord) { + assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && + "User data for FindBaseClass is not canonical!"); + return Specifier->getType()->getAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; +} + +bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *BaseRecord) { + assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && + "User data for FindBaseClass is not canonical!"); + return Specifier->isVirtual() && + Specifier->getType()->getAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; +} + +bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} + +bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + if ((*Path.Decls.first)->isInIdentifierNamespace(IDNS)) + return true; + } + + return false; +} + +bool CXXRecordDecl:: +FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + void *Name) { + RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + + DeclarationName N = DeclarationName::getFromOpaquePtr(Name); + for (Path.Decls = BaseRecord->lookup(N); + Path.Decls.first != Path.Decls.second; + ++Path.Decls.first) { + // FIXME: Refactor the "is it a nested-name-specifier?" check + if (isa<TypedefNameDecl>(*Path.Decls.first) || + (*Path.Decls.first)->isInIdentifierNamespace(IDNS_Tag)) + return true; + } + + return false; +} + +void OverridingMethods::add(unsigned OverriddenSubobject, + UniqueVirtualMethod Overriding) { + llvm::SmallVector<UniqueVirtualMethod, 4> &SubobjectOverrides + = Overrides[OverriddenSubobject]; + if (std::find(SubobjectOverrides.begin(), SubobjectOverrides.end(), + Overriding) == SubobjectOverrides.end()) + SubobjectOverrides.push_back(Overriding); +} + +void OverridingMethods::add(const OverridingMethods &Other) { + for (const_iterator I = Other.begin(), IE = Other.end(); I != IE; ++I) { + for (overriding_const_iterator M = I->second.begin(), + MEnd = I->second.end(); + M != MEnd; + ++M) + add(I->first, *M); + } +} + +void OverridingMethods::replaceAll(UniqueVirtualMethod Overriding) { + for (iterator I = begin(), IEnd = end(); I != IEnd; ++I) { + I->second.clear(); + I->second.push_back(Overriding); + } +} + + +namespace { + class FinalOverriderCollector { + /// \brief The number of subobjects of a given class type that + /// occur within the class hierarchy. + llvm::DenseMap<const CXXRecordDecl *, unsigned> SubobjectCount; + + /// \brief Overriders for each virtual base subobject. + llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *> VirtualOverriders; + + CXXFinalOverriderMap FinalOverriders; + + public: + ~FinalOverriderCollector(); + + void Collect(const CXXRecordDecl *RD, bool VirtualBase, + const CXXRecordDecl *InVirtualSubobject, + CXXFinalOverriderMap &Overriders); + }; +} + +void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, + bool VirtualBase, + const CXXRecordDecl *InVirtualSubobject, + CXXFinalOverriderMap &Overriders) { + unsigned SubobjectNumber = 0; + if (!VirtualBase) + SubobjectNumber + = ++SubobjectCount[cast<CXXRecordDecl>(RD->getCanonicalDecl())]; + + for (CXXRecordDecl::base_class_const_iterator Base = RD->bases_begin(), + BaseEnd = RD->bases_end(); Base != BaseEnd; ++Base) { + if (const RecordType *RT = Base->getType()->getAs<RecordType>()) { + const CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(RT->getDecl()); + if (!BaseDecl->isPolymorphic()) + continue; + + if (Overriders.empty() && !Base->isVirtual()) { + // There are no other overriders of virtual member functions, + // so let the base class fill in our overriders for us. + Collect(BaseDecl, false, InVirtualSubobject, Overriders); + continue; + } + + // Collect all of the overridders from the base class subobject + // and merge them into the set of overridders for this class. + // For virtual base classes, populate or use the cached virtual + // overrides so that we do not walk the virtual base class (and + // its base classes) more than once. + CXXFinalOverriderMap ComputedBaseOverriders; + CXXFinalOverriderMap *BaseOverriders = &ComputedBaseOverriders; + if (Base->isVirtual()) { + CXXFinalOverriderMap *&MyVirtualOverriders = VirtualOverriders[BaseDecl]; + if (!MyVirtualOverriders) { + MyVirtualOverriders = new CXXFinalOverriderMap; + Collect(BaseDecl, true, BaseDecl, *MyVirtualOverriders); + } + + BaseOverriders = MyVirtualOverriders; + } else + Collect(BaseDecl, false, InVirtualSubobject, ComputedBaseOverriders); + + // Merge the overriders from this base class into our own set of + // overriders. + for (CXXFinalOverriderMap::iterator OM = BaseOverriders->begin(), + OMEnd = BaseOverriders->end(); + OM != OMEnd; + ++OM) { + const CXXMethodDecl *CanonOM + = cast<CXXMethodDecl>(OM->first->getCanonicalDecl()); + Overriders[CanonOM].add(OM->second); + } + } + } + + for (CXXRecordDecl::method_iterator M = RD->method_begin(), + MEnd = RD->method_end(); + M != MEnd; + ++M) { + // We only care about virtual methods. + if (!M->isVirtual()) + continue; + + CXXMethodDecl *CanonM = cast<CXXMethodDecl>(M->getCanonicalDecl()); + + if (CanonM->begin_overridden_methods() + == CanonM->end_overridden_methods()) { + // This is a new virtual function that does not override any + // other virtual function. Add it to the map of virtual + // functions for which we are tracking overridders. + + // C++ [class.virtual]p2: + // For convenience we say that any virtual function overrides itself. + Overriders[CanonM].add(SubobjectNumber, + UniqueVirtualMethod(CanonM, SubobjectNumber, + InVirtualSubobject)); + continue; + } + + // This virtual method overrides other virtual methods, so it does + // not add any new slots into the set of overriders. Instead, we + // replace entries in the set of overriders with the new + // overrider. To do so, we dig down to the original virtual + // functions using data recursion and update all of the methods it + // overrides. + typedef std::pair<CXXMethodDecl::method_iterator, + CXXMethodDecl::method_iterator> OverriddenMethods; + llvm::SmallVector<OverriddenMethods, 4> Stack; + Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), + CanonM->end_overridden_methods())); + while (!Stack.empty()) { + OverriddenMethods OverMethods = Stack.back(); + Stack.pop_back(); + + for (; OverMethods.first != OverMethods.second; ++OverMethods.first) { + const CXXMethodDecl *CanonOM + = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl()); + + // C++ [class.virtual]p2: + // A virtual member function C::vf of a class object S is + // a final overrider unless the most derived class (1.8) + // of which S is a base class subobject (if any) declares + // or inherits another member function that overrides vf. + // + // Treating this object like the most derived class, we + // replace any overrides from base classes with this + // overriding virtual function. + Overriders[CanonOM].replaceAll( + UniqueVirtualMethod(CanonM, SubobjectNumber, + InVirtualSubobject)); + + if (CanonOM->begin_overridden_methods() + == CanonOM->end_overridden_methods()) + continue; + + // Continue recursion to the methods that this virtual method + // overrides. + Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(), + CanonOM->end_overridden_methods())); + } + } + + // C++ [class.virtual]p2: + // For convenience we say that any virtual function overrides itself. + Overriders[CanonM].add(SubobjectNumber, + UniqueVirtualMethod(CanonM, SubobjectNumber, + InVirtualSubobject)); + } +} + +FinalOverriderCollector::~FinalOverriderCollector() { + for (llvm::DenseMap<const CXXRecordDecl *, CXXFinalOverriderMap *>::iterator + VO = VirtualOverriders.begin(), VOEnd = VirtualOverriders.end(); + VO != VOEnd; + ++VO) + delete VO->second; +} + +void +CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { + FinalOverriderCollector Collector; + Collector.Collect(this, false, 0, FinalOverriders); + + // Weed out any final overriders that come from virtual base class + // subobjects that were hidden by other subobjects along any path. + // This is the final-overrider variant of C++ [class.member.lookup]p10. + for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(), + OMEnd = FinalOverriders.end(); + OM != OMEnd; + ++OM) { + for (OverridingMethods::iterator SO = OM->second.begin(), + SOEnd = OM->second.end(); + SO != SOEnd; + ++SO) { + llvm::SmallVector<UniqueVirtualMethod, 4> &Overriding = SO->second; + if (Overriding.size() < 2) + continue; + + for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + Pos = Overriding.begin(), PosEnd = Overriding.end(); + Pos != PosEnd; + /* increment in loop */) { + if (!Pos->InVirtualSubobject) { + ++Pos; + continue; + } + + // We have an overriding method in a virtual base class + // subobject (or non-virtual base class subobject thereof); + // determine whether there exists an other overriding method + // in a base class subobject that hides the virtual base class + // subobject. + bool Hidden = false; + for (llvm::SmallVector<UniqueVirtualMethod, 4>::iterator + OP = Overriding.begin(), OPEnd = Overriding.end(); + OP != OPEnd && !Hidden; + ++OP) { + if (Pos == OP) + continue; + + if (OP->Method->getParent()->isVirtuallyDerivedFrom( + const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject))) + Hidden = true; + } + + if (Hidden) { + // The current overriding function is hidden by another + // overriding function; remove this one. + Pos = Overriding.erase(Pos); + PosEnd = Overriding.end(); + } else { + ++Pos; + } + } + } + } +} + +static void +AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, + CXXIndirectPrimaryBaseSet& Bases) { + // If the record has a virtual primary base class, add it to our set. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + if (Layout.isPrimaryBaseVirtual()) + Bases.insert(Layout.getPrimaryBase()); + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot get indirect primary bases for class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (BaseDecl->getNumVBases()) + AddIndirectPrimaryBases(BaseDecl, Context, Bases); + } + +} + +void +CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const { + ASTContext &Context = getASTContext(); + + if (!getNumVBases()) + return; + + for (CXXRecordDecl::base_class_const_iterator I = bases_begin(), + E = bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot get indirect primary bases for class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Only bases with virtual bases participate in computing the + // indirect primary virtual base classes. + if (BaseDecl->getNumVBases()) + AddIndirectPrimaryBases(BaseDecl, Context, Bases); + } +} + diff --git a/contrib/llvm/tools/clang/lib/AST/Decl.cpp b/contrib/llvm/tools/clang/lib/AST/Decl.cpp new file mode 100644 index 000000000000..12357c07a794 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Decl.cpp @@ -0,0 +1,2495 @@ +//===--- 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/TypeLoc.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/Specifiers.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// NamedDecl Implementation +//===----------------------------------------------------------------------===// + +static llvm::Optional<Visibility> getVisibilityOf(const Decl *D) { + // If this declaration has an explicit visibility attribute, use it. + if (const VisibilityAttr *A = D->getAttr<VisibilityAttr>()) { + switch (A->getVisibility()) { + case VisibilityAttr::Default: + return DefaultVisibility; + case VisibilityAttr::Hidden: + return HiddenVisibility; + case VisibilityAttr::Protected: + return ProtectedVisibility; + } + + return DefaultVisibility; + } + + // If we're on Mac OS X, an 'availability' for Mac OS X attribute + // implies visibility(default). + if (D->getASTContext().Target.getTriple().isOSDarwin()) { + for (specific_attr_iterator<AvailabilityAttr> + A = D->specific_attr_begin<AvailabilityAttr>(), + AEnd = D->specific_attr_end<AvailabilityAttr>(); + A != AEnd; ++A) + if ((*A)->getPlatform()->getName().equals("macosx")) + return DefaultVisibility; + } + + return llvm::Optional<Visibility>(); +} + +typedef NamedDecl::LinkageInfo LinkageInfo; +typedef std::pair<Linkage,Visibility> LVPair; + +static LVPair merge(LVPair L, LVPair R) { + return LVPair(minLinkage(L.first, R.first), + minVisibility(L.second, R.second)); +} + +static LVPair merge(LVPair L, LinkageInfo R) { + return LVPair(minLinkage(L.first, R.linkage()), + minVisibility(L.second, R.visibility())); +} + +namespace { +/// Flags controlling the computation of linkage and visibility. +struct LVFlags { + bool ConsiderGlobalVisibility; + bool ConsiderVisibilityAttributes; + bool ConsiderTemplateParameterTypes; + + LVFlags() : ConsiderGlobalVisibility(true), + ConsiderVisibilityAttributes(true), + ConsiderTemplateParameterTypes(true) { + } + + /// \brief Returns a set of flags that is only useful for computing the + /// linkage, not the visibility, of a declaration. + static LVFlags CreateOnlyDeclLinkage() { + LVFlags F; + F.ConsiderGlobalVisibility = false; + F.ConsiderVisibilityAttributes = false; + F.ConsiderTemplateParameterTypes = false; + return F; + } + + /// Returns a set of flags, otherwise based on these, which ignores + /// off all sources of visibility except template arguments. + LVFlags onlyTemplateVisibility() const { + LVFlags F = *this; + F.ConsiderGlobalVisibility = false; + F.ConsiderVisibilityAttributes = false; + F.ConsiderTemplateParameterTypes = false; + return F; + } +}; +} // end anonymous namespace + +/// \brief Get the most restrictive linkage for the types in the given +/// template parameter list. +static LVPair +getLVForTemplateParameterList(const TemplateParameterList *Params) { + LVPair LV(ExternalLinkage, DefaultVisibility); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->isExpandedParameterPack()) { + for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { + QualType T = NTTP->getExpansionType(I); + if (!T->isDependentType()) + LV = merge(LV, T->getLinkageAndVisibility()); + } + continue; + } + + if (!NTTP->getType()->isDependentType()) { + LV = merge(LV, NTTP->getType()->getLinkageAndVisibility()); + continue; + } + } + + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(*P)) { + LV = merge(LV, getLVForTemplateParameterList(TTP->getTemplateParameters())); + } + } + + return LV; +} + +/// getLVForDecl - Get the linkage and visibility for the given declaration. +static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags F); + +/// \brief Get the most restrictive linkage for the types and +/// declarations in the given template argument list. +static LVPair getLVForTemplateArgumentList(const TemplateArgument *Args, + unsigned NumArgs, + LVFlags &F) { + LVPair LV(ExternalLinkage, DefaultVisibility); + + for (unsigned I = 0; I != NumArgs; ++I) { + switch (Args[I].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Expression: + break; + + case TemplateArgument::Type: + LV = merge(LV, Args[I].getAsType()->getLinkageAndVisibility()); + break; + + case TemplateArgument::Declaration: + // The decl can validly be null as the representation of nullptr + // arguments, valid only in C++0x. + if (Decl *D = Args[I].getAsDecl()) { + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + LV = merge(LV, getLVForDecl(ND, F)); + } + break; + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + if (TemplateDecl *Template + = Args[I].getAsTemplateOrTemplatePattern().getAsTemplateDecl()) + LV = merge(LV, getLVForDecl(Template, F)); + break; + + case TemplateArgument::Pack: + LV = merge(LV, getLVForTemplateArgumentList(Args[I].pack_begin(), + Args[I].pack_size(), + F)); + break; + } + } + + return LV; +} + +static LVPair +getLVForTemplateArgumentList(const TemplateArgumentList &TArgs, + LVFlags &F) { + return getLVForTemplateArgumentList(TArgs.data(), TArgs.size(), F); +} + +static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVFlags F) { + assert(D->getDeclContext()->getRedeclContext()->isFileContext() && + "Not a name having namespace scope"); + ASTContext &Context = D->getASTContext(); + + // C++ [basic.link]p3: + // A name having namespace scope (3.3.6) has internal linkage if it + // is the name of + // - an object, reference, function or function template that is + // explicitly declared static; or, + // (This bullet corresponds to C99 6.2.2p3.) + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + // Explicitly declared static. + if (Var->getStorageClass() == SC_Static) + return LinkageInfo::internal(); + + // - an object or reference that is explicitly declared const + // and neither explicitly declared extern nor previously + // declared to have external linkage; or + // (there is no equivalent in C99) + if (Context.getLangOptions().CPlusPlus && + Var->getType().isConstant(Context) && + Var->getStorageClass() != SC_Extern && + Var->getStorageClass() != SC_PrivateExtern) { + bool FoundExtern = false; + for (const VarDecl *PrevVar = Var->getPreviousDeclaration(); + PrevVar && !FoundExtern; + PrevVar = PrevVar->getPreviousDeclaration()) + if (isExternalLinkage(PrevVar->getLinkage())) + FoundExtern = true; + + if (!FoundExtern) + return LinkageInfo::internal(); + } + } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { + // C++ [temp]p4: + // A non-member function template can have internal linkage; any + // other template name shall have external linkage. + const FunctionDecl *Function = 0; + if (const FunctionTemplateDecl *FunTmpl + = dyn_cast<FunctionTemplateDecl>(D)) + Function = FunTmpl->getTemplatedDecl(); + else + Function = cast<FunctionDecl>(D); + + // Explicitly declared static. + if (Function->getStorageClass() == SC_Static) + return LinkageInfo(InternalLinkage, DefaultVisibility, false); + } else if (const FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + // - a data member of an anonymous union. + if (cast<RecordDecl>(Field->getDeclContext())->isAnonymousStructOrUnion()) + return LinkageInfo::internal(); + } + + if (D->isInAnonymousNamespace()) { + const VarDecl *Var = dyn_cast<VarDecl>(D); + const FunctionDecl *Func = dyn_cast<FunctionDecl>(D); + if ((!Var || !Var->isExternC()) && (!Func || !Func->isExternC())) + return LinkageInfo::uniqueExternal(); + } + + // Set up the defaults. + + // C99 6.2.2p5: + // If the declaration of an identifier for an object has file + // scope and no storage-class specifier, its linkage is + // external. + LinkageInfo LV; + + if (F.ConsiderVisibilityAttributes) { + if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) { + LV.setVisibility(*Vis, true); + F.ConsiderGlobalVisibility = false; + } else { + // If we're declared in a namespace with a visibility attribute, + // use that namespace's visibility, but don't call it explicit. + for (const DeclContext *DC = D->getDeclContext(); + !isa<TranslationUnitDecl>(DC); + DC = DC->getParent()) { + if (!isa<NamespaceDecl>(DC)) continue; + if (llvm::Optional<Visibility> Vis + = cast<NamespaceDecl>(DC)->getExplicitVisibility()) { + LV.setVisibility(*Vis, false); + F.ConsiderGlobalVisibility = false; + break; + } + } + } + } + + // C++ [basic.link]p4: + + // A name having namespace scope has external linkage if it is the + // name of + // + // - an object or reference, unless it has internal linkage; or + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + // GCC applies the following optimization to variables and static + // data members, but not to functions: + // + // Modify the variable's LV by the LV of its type unless this is + // C or extern "C". This follows from [basic.link]p9: + // A type without linkage shall not be used as the type of a + // variable or function with external linkage unless + // - the entity has C language linkage, or + // - the entity is declared within an unnamed namespace, or + // - the entity is not used or is defined in the same + // translation unit. + // and [basic.link]p10: + // ...the types specified by all declarations referring to a + // given variable or function shall be identical... + // C does not have an equivalent rule. + // + // Ignore this if we've got an explicit attribute; the user + // probably knows what they're doing. + // + // Note that we don't want to make the variable non-external + // because of this, but unique-external linkage suits us. + if (Context.getLangOptions().CPlusPlus && !Var->isExternC()) { + LVPair TypeLV = Var->getType()->getLinkageAndVisibility(); + if (TypeLV.first != ExternalLinkage) + return LinkageInfo::uniqueExternal(); + if (!LV.visibilityExplicit()) + LV.mergeVisibility(TypeLV.second); + } + + if (Var->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility, true); + + if (!Context.getLangOptions().CPlusPlus && + (Var->getStorageClass() == SC_Extern || + Var->getStorageClass() == SC_PrivateExtern)) { + + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const VarDecl *PrevVar = Var->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(PrevVar, F); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } + } + + // - a function, unless it has internal linkage; or + } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + // In theory, we can modify the function's LV by the LV of its + // type unless it has C linkage (see comment above about variables + // for justification). In practice, GCC doesn't do this, so it's + // just too painful to make work. + + if (Function->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility, true); + + // C99 6.2.2p5: + // If the declaration of an identifier for a function has no + // storage-class specifier, its linkage is determined exactly + // as if it were declared with the storage-class specifier + // extern. + if (!Context.getLangOptions().CPlusPlus && + (Function->getStorageClass() == SC_Extern || + Function->getStorageClass() == SC_PrivateExtern || + Function->getStorageClass() == SC_None)) { + // C99 6.2.2p4: + // For an identifier declared with the storage-class specifier + // extern in a scope in which a prior declaration of that + // identifier is visible, if the prior declaration specifies + // internal or external linkage, the linkage of the identifier + // at the later declaration is the same as the linkage + // specified at the prior declaration. If no prior declaration + // is visible, or if the prior declaration specifies no + // linkage, then the identifier has external linkage. + if (const FunctionDecl *PrevFunc = Function->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(PrevFunc, F); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } + } + + // In C++, then if the type of the function uses a type with + // unique-external linkage, it's not legally usable from outside + // this translation unit. However, we should use the C linkage + // rules instead for extern "C" declarations. + if (Context.getLangOptions().CPlusPlus && !Function->isExternC() && + Function->getType()->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + + if (FunctionTemplateSpecializationInfo *SpecInfo + = Function->getTemplateSpecializationInfo()) { + LV.merge(getLVForDecl(SpecInfo->getTemplate(), + F.onlyTemplateVisibility())); + const TemplateArgumentList &TemplateArgs = *SpecInfo->TemplateArguments; + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + } + + // - a named class (Clause 9), or an unnamed class defined in a + // typedef declaration in which the class has the typedef name + // for linkage purposes (7.1.3); or + // - a named enumeration (7.2), or an unnamed enumeration + // defined in a typedef declaration in which the enumeration + // has the typedef name for linkage purposes (7.1.3); or + } else if (const TagDecl *Tag = dyn_cast<TagDecl>(D)) { + // Unnamed tags have no linkage. + if (!Tag->getDeclName() && !Tag->getTypedefNameForAnonDecl()) + return LinkageInfo::none(); + + // If this is a class template specialization, consider the + // linkage of the template and template arguments. + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(Tag)) { + // From the template. + LV.merge(getLVForDecl(Spec->getSpecializedTemplate(), + F.onlyTemplateVisibility())); + + // The arguments at which the template was instantiated. + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + LV.merge(getLVForTemplateArgumentList(TemplateArgs, F)); + } + + // Consider -fvisibility unless the type has C linkage. + if (F.ConsiderGlobalVisibility) + F.ConsiderGlobalVisibility = + (Context.getLangOptions().CPlusPlus && + !Tag->getDeclContext()->isExternCContext()); + + // - an enumerator belonging to an enumeration with external linkage; + } else if (isa<EnumConstantDecl>(D)) { + LinkageInfo EnumLV = getLVForDecl(cast<NamedDecl>(D->getDeclContext()), F); + if (!isExternalLinkage(EnumLV.linkage())) + return LinkageInfo::none(); + LV.merge(EnumLV); + + // - a template, unless it is a function template that has + // internal linkage (Clause 14); + } else if (const TemplateDecl *temp = dyn_cast<TemplateDecl>(D)) { + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList(temp->getTemplateParameters())); + + // - a namespace (7.3), unless it is declared within an unnamed + // namespace. + } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) { + return LV; + + // By extension, we assign external linkage to Objective-C + // interfaces. + } else if (isa<ObjCInterfaceDecl>(D)) { + // fallout + + // Everything not covered here has no linkage. + } else { + return LinkageInfo::none(); + } + + // If we ended up with non-external linkage, visibility should + // always be default. + if (LV.linkage() != ExternalLinkage) + return LinkageInfo(LV.linkage(), DefaultVisibility, false); + + // If we didn't end up with hidden visibility, consider attributes + // and -fvisibility. + if (F.ConsiderGlobalVisibility) + LV.mergeVisibility(Context.getLangOptions().getVisibilityMode()); + + return LV; +} + +static LinkageInfo getLVForClassMember(const NamedDecl *D, LVFlags F) { + // Only certain class members have linkage. Note that fields don't + // really have linkage, but it's convenient to say they do for the + // purposes of calculating linkage of pointer-to-data-member + // template arguments. + if (!(isa<CXXMethodDecl>(D) || + isa<VarDecl>(D) || + isa<FieldDecl>(D) || + (isa<TagDecl>(D) && + (D->getDeclName() || cast<TagDecl>(D)->getTypedefNameForAnonDecl())))) + return LinkageInfo::none(); + + LinkageInfo LV; + + // The flags we're going to use to compute the class's visibility. + LVFlags ClassF = F; + + // If we have an explicit visibility attribute, merge that in. + if (F.ConsiderVisibilityAttributes) { + if (llvm::Optional<Visibility> Vis = D->getExplicitVisibility()) { + LV.mergeVisibility(*Vis, true); + + // Ignore global visibility later, but not this attribute. + F.ConsiderGlobalVisibility = false; + + // Ignore both global visibility and attributes when computing our + // parent's visibility. + ClassF = F.onlyTemplateVisibility(); + } + } + + // Class members only have linkage if their class has external + // linkage. + LV.merge(getLVForDecl(cast<RecordDecl>(D->getDeclContext()), ClassF)); + if (!isExternalLinkage(LV.linkage())) + return LinkageInfo::none(); + + // If the class already has unique-external linkage, we can't improve. + if (LV.linkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { + // If the type of the function uses a type with unique-external + // linkage, it's not legally usable from outside this translation unit. + if (MD->getType()->getLinkage() == UniqueExternalLinkage) + return LinkageInfo::uniqueExternal(); + + TemplateSpecializationKind TSK = TSK_Undeclared; + + // If this is a method template specialization, use the linkage for + // the template parameters and arguments. + if (FunctionTemplateSpecializationInfo *Spec + = MD->getTemplateSpecializationInfo()) { + LV.merge(getLVForTemplateArgumentList(*Spec->TemplateArguments, F)); + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( + Spec->getTemplate()->getTemplateParameters())); + + TSK = Spec->getTemplateSpecializationKind(); + } else if (MemberSpecializationInfo *MSI = + MD->getMemberSpecializationInfo()) { + TSK = MSI->getTemplateSpecializationKind(); + } + + // If we're paying attention to global visibility, apply + // -finline-visibility-hidden if this is an inline method. + // + // Note that ConsiderGlobalVisibility doesn't yet have information + // about whether containing classes have visibility attributes, + // and that's intentional. + if (TSK != TSK_ExplicitInstantiationDeclaration && + F.ConsiderGlobalVisibility && + MD->getASTContext().getLangOptions().InlineVisibilityHidden) { + // InlineVisibilityHidden only applies to definitions, and + // isInlined() only gives meaningful answers on definitions + // anyway. + const FunctionDecl *Def = 0; + if (MD->hasBody(Def) && Def->isInlined()) + LV.setVisibility(HiddenVisibility); + } + + // Note that in contrast to basically every other situation, we + // *do* apply -fvisibility to method declarations. + + } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + // Merge template argument/parameter information for member + // class template specializations. + LV.merge(getLVForTemplateArgumentList(Spec->getTemplateArgs(), F)); + if (F.ConsiderTemplateParameterTypes) + LV.merge(getLVForTemplateParameterList( + Spec->getSpecializedTemplate()->getTemplateParameters())); + } + + // Static data members. + } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Modify the variable's linkage by its type, but ignore the + // type's visibility unless it's a definition. + LVPair TypeLV = VD->getType()->getLinkageAndVisibility(); + if (TypeLV.first != ExternalLinkage) + LV.mergeLinkage(UniqueExternalLinkage); + if (!LV.visibilityExplicit()) + LV.mergeVisibility(TypeLV.second); + } + + F.ConsiderGlobalVisibility &= !LV.visibilityExplicit(); + + // Apply -fvisibility if desired. + if (F.ConsiderGlobalVisibility && LV.visibility() != HiddenVisibility) { + LV.mergeVisibility(D->getASTContext().getLangOptions().getVisibilityMode()); + } + + return LV; +} + +static void clearLinkageForClass(const CXXRecordDecl *record) { + for (CXXRecordDecl::decl_iterator + i = record->decls_begin(), e = record->decls_end(); i != e; ++i) { + Decl *child = *i; + if (isa<NamedDecl>(child)) + cast<NamedDecl>(child)->ClearLinkageCache(); + } +} + +void NamedDecl::ClearLinkageCache() { + // Note that we can't skip clearing the linkage of children just + // because the parent doesn't have cached linkage: we don't cache + // when computing linkage for parent contexts. + + HasCachedLinkage = 0; + + // If we're changing the linkage of a class, we need to reset the + // linkage of child declarations, too. + if (const CXXRecordDecl *record = dyn_cast<CXXRecordDecl>(this)) + clearLinkageForClass(record); + + if (ClassTemplateDecl *temp = + dyn_cast<ClassTemplateDecl>(const_cast<NamedDecl*>(this))) { + // Clear linkage for the template pattern. + CXXRecordDecl *record = temp->getTemplatedDecl(); + record->HasCachedLinkage = 0; + clearLinkageForClass(record); + + // We need to clear linkage for specializations, too. + for (ClassTemplateDecl::spec_iterator + i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) + i->ClearLinkageCache(); + } + + // Clear cached linkage for function template decls, too. + if (FunctionTemplateDecl *temp = + dyn_cast<FunctionTemplateDecl>(const_cast<NamedDecl*>(this))) { + temp->getTemplatedDecl()->ClearLinkageCache(); + for (FunctionTemplateDecl::spec_iterator + i = temp->spec_begin(), e = temp->spec_end(); i != e; ++i) + i->ClearLinkageCache(); + } + +} + +Linkage NamedDecl::getLinkage() const { + if (HasCachedLinkage) { + assert(Linkage(CachedLinkage) == + getLVForDecl(this, LVFlags::CreateOnlyDeclLinkage()).linkage()); + return Linkage(CachedLinkage); + } + + CachedLinkage = getLVForDecl(this, + LVFlags::CreateOnlyDeclLinkage()).linkage(); + HasCachedLinkage = 1; + return Linkage(CachedLinkage); +} + +LinkageInfo NamedDecl::getLinkageAndVisibility() const { + LinkageInfo LI = getLVForDecl(this, LVFlags()); + assert(!HasCachedLinkage || Linkage(CachedLinkage) == LI.linkage()); + HasCachedLinkage = 1; + CachedLinkage = LI.linkage(); + return LI; +} + +llvm::Optional<Visibility> NamedDecl::getExplicitVisibility() const { + // Use the most recent declaration of a variable. + if (const VarDecl *var = dyn_cast<VarDecl>(this)) + return getVisibilityOf(var->getMostRecentDeclaration()); + + // Use the most recent declaration of a function, and also handle + // function template specializations. + if (const FunctionDecl *fn = dyn_cast<FunctionDecl>(this)) { + if (llvm::Optional<Visibility> V + = getVisibilityOf(fn->getMostRecentDeclaration())) + return V; + + // If the function is a specialization of a template with an + // explicit visibility attribute, use that. + if (FunctionTemplateSpecializationInfo *templateInfo + = fn->getTemplateSpecializationInfo()) + return getVisibilityOf(templateInfo->getTemplate()->getTemplatedDecl()); + + return llvm::Optional<Visibility>(); + } + + // Otherwise, just check the declaration itself first. + if (llvm::Optional<Visibility> V = getVisibilityOf(this)) + return V; + + // If there wasn't explicit visibility there, and this is a + // specialization of a class template, check for visibility + // on the pattern. + if (const ClassTemplateSpecializationDecl *spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) + return getVisibilityOf(spec->getSpecializedTemplate()->getTemplatedDecl()); + + return llvm::Optional<Visibility>(); +} + +static LinkageInfo getLVForDecl(const NamedDecl *D, LVFlags Flags) { + // Objective-C: treat all Objective-C declarations as having external + // linkage. + switch (D->getKind()) { + default: + break; + case Decl::TemplateTemplateParm: // count these as external + case Decl::NonTypeTemplateParm: + case Decl::ObjCAtDefsField: + case Decl::ObjCCategory: + case Decl::ObjCCategoryImpl: + case Decl::ObjCCompatibleAlias: + case Decl::ObjCForwardProtocol: + case Decl::ObjCImplementation: + case Decl::ObjCMethod: + case Decl::ObjCProperty: + case Decl::ObjCPropertyImpl: + case Decl::ObjCProtocol: + return LinkageInfo::external(); + } + + // Handle linkage for namespace-scope names. + if (D->getDeclContext()->getRedeclContext()->isFileContext()) + return getLVForNamespaceScopeDecl(D, Flags); + + // C++ [basic.link]p5: + // In addition, a member function, static data member, a named + // class or enumeration of class scope, or an unnamed class or + // enumeration defined in a class-scope typedef declaration such + // that the class or enumeration has the typedef name for linkage + // purposes (7.1.3), has external linkage if the name of the class + // has external linkage. + if (D->getDeclContext()->isRecord()) + return getLVForClassMember(D, Flags); + + // C++ [basic.link]p6: + // The name of a function declared in block scope and the name of + // an object declared by a block scope extern declaration have + // linkage. If there is a visible declaration of an entity with + // linkage having the same name and type, ignoring entities + // declared outside the innermost enclosing namespace scope, the + // block scope declaration declares that same entity and receives + // the linkage of the previous declaration. If there is more than + // one such matching entity, the program is ill-formed. Otherwise, + // if no matching entity is found, the block scope entity receives + // external linkage. + if (D->getLexicalDeclContext()->isFunctionOrMethod()) { + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + if (Function->isInAnonymousNamespace() && !Function->isExternC()) + return LinkageInfo::uniqueExternal(); + + LinkageInfo LV; + if (Flags.ConsiderVisibilityAttributes) { + if (llvm::Optional<Visibility> Vis = Function->getExplicitVisibility()) + LV.setVisibility(*Vis); + } + + if (const FunctionDecl *Prev = Function->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } + + return LV; + } + + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) + if (Var->getStorageClass() == SC_Extern || + Var->getStorageClass() == SC_PrivateExtern) { + if (Var->isInAnonymousNamespace() && !Var->isExternC()) + return LinkageInfo::uniqueExternal(); + + LinkageInfo LV; + if (Var->getStorageClass() == SC_PrivateExtern) + LV.setVisibility(HiddenVisibility); + else if (Flags.ConsiderVisibilityAttributes) { + if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility()) + LV.setVisibility(*Vis); + } + + if (const VarDecl *Prev = Var->getPreviousDeclaration()) { + LinkageInfo PrevLV = getLVForDecl(Prev, Flags); + if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); + LV.mergeVisibility(PrevLV); + } + + return LV; + } + } + + // C++ [basic.link]p6: + // Names not covered by these rules have no linkage. + return LinkageInfo::none(); +} + +std::string NamedDecl::getQualifiedNameAsString() const { + return getQualifiedNameAsString(getASTContext().getLangOptions()); +} + +std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { + const DeclContext *Ctx = getDeclContext(); + + if (Ctx->isFunctionOrMethod()) + return getNameAsString(); + + typedef llvm::SmallVector<const DeclContext *, 8> ContextsTy; + ContextsTy Contexts; + + // Collect contexts. + while (Ctx && isa<NamedDecl>(Ctx)) { + Contexts.push_back(Ctx); + Ctx = Ctx->getParent(); + }; + + std::string QualName; + llvm::raw_string_ostream OS(QualName); + + for (ContextsTy::reverse_iterator I = Contexts.rbegin(), E = Contexts.rend(); + I != E; ++I) { + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(*I)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.data(), + TemplateArgs.size(), + P); + OS << Spec->getName() << TemplateArgsStr; + } else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(*I)) { + if (ND->isAnonymousNamespace()) + OS << "<anonymous namespace>"; + else + OS << ND; + } else if (const RecordDecl *RD = dyn_cast<RecordDecl>(*I)) { + if (!RD->getIdentifier()) + OS << "<anonymous " << RD->getKindName() << '>'; + else + OS << RD; + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); + + OS << FD << '('; + if (FT) { + unsigned NumParams = FD->getNumParams(); + for (unsigned i = 0; i < NumParams; ++i) { + if (i) + OS << ", "; + std::string Param; + FD->getParamDecl(i)->getType().getAsStringInternal(Param, P); + OS << Param; + } + + if (FT->isVariadic()) { + if (NumParams > 0) + OS << ", "; + OS << "..."; + } + } + OS << ')'; + } else { + OS << cast<NamedDecl>(*I); + } + OS << "::"; + } + + if (getDeclName()) + OS << this; + else + OS << "<anonymous>"; + + return OS.str(); +} + +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() + ->getOriginalNamespace() == + cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace() + ->getOriginalNamespace(); + } + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) + // For function declarations, we keep track of redeclarations. + return FD->getPreviousDeclaration() == OldD; + + // For function templates, the underlying function declarations are linked. + if (const FunctionTemplateDecl *FunctionTemplate + = dyn_cast<FunctionTemplateDecl>(this)) + if (const FunctionTemplateDecl *OldFunctionTemplate + = dyn_cast<FunctionTemplateDecl>(OldD)) + return FunctionTemplate->getTemplatedDecl() + ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl()); + + // For method declarations, we keep track of redeclarations. + if (isa<ObjCMethodDecl>(this)) + return false; + + if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD)) + return true; + + if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD)) + return cast<UsingShadowDecl>(this)->getTargetDecl() == + cast<UsingShadowDecl>(OldD)->getTargetDecl(); + + if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD)) { + ASTContext &Context = getASTContext(); + return Context.getCanonicalNestedNameSpecifier( + cast<UsingDecl>(this)->getQualifier()) == + Context.getCanonicalNestedNameSpecifier( + cast<UsingDecl>(OldD)->getQualifier()); + } + + // 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 { + return getLinkage() != NoLinkage; +} + +NamedDecl *NamedDecl::getUnderlyingDecl() { + NamedDecl *ND = this; + while (true) { + if (UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(ND)) + ND = UD->getTargetDecl(); + else if (ObjCCompatibleAliasDecl *AD + = dyn_cast<ObjCCompatibleAliasDecl>(ND)) + return AD->getClassInterface(); + else + return ND; + } +} + +bool NamedDecl::isCXXInstanceMember() const { + assert(isCXXClassMember() && + "checking whether non-member is instance member"); + + const NamedDecl *D = this; + if (isa<UsingShadowDecl>(D)) + D = cast<UsingShadowDecl>(D)->getTargetDecl(); + + if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D)) + return true; + if (isa<CXXMethodDecl>(D)) + return cast<CXXMethodDecl>(D)->isInstance(); + if (isa<FunctionTemplateDecl>(D)) + return cast<CXXMethodDecl>(cast<FunctionTemplateDecl>(D) + ->getTemplatedDecl())->isInstance(); + return false; +} + +//===----------------------------------------------------------------------===// +// DeclaratorDecl Implementation +//===----------------------------------------------------------------------===// + +template <typename DeclT> +static SourceLocation getTemplateOrInnerLocStart(const DeclT *decl) { + if (decl->getNumTemplateParameterLists() > 0) + return decl->getTemplateParameterList(0)->getTemplateLoc(); + else + return decl->getInnerLocStart(); +} + +SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { + TypeSourceInfo *TSI = getTypeSourceInfo(); + if (TSI) return TSI->getTypeLoc().getBeginLoc(); + return SourceLocation(); +} + +void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { + if (QualifierLoc) { + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) { + // Save (non-extended) type source info pointer. + TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>(); + // Allocate external info struct. + DeclInfo = new (getASTContext()) ExtInfo; + // Restore savedTInfo into (extended) decl info. + getExtInfo()->TInfo = savedTInfo; + } + // Set qualifier info. + getExtInfo()->QualifierLoc = QualifierLoc; + } + else { + // Here Qualifier == 0, i.e., we are removing the qualifier (if any). + if (hasExtInfo()) { + if (getExtInfo()->NumTemplParamLists == 0) { + // Save type source info pointer. + TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; + // Deallocate the extended decl info. + getASTContext().Deallocate(getExtInfo()); + // Restore savedTInfo into (non-extended) decl info. + DeclInfo = savedTInfo; + } + else + getExtInfo()->QualifierLoc = QualifierLoc; + } + } +} + +void +DeclaratorDecl::setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert(NumTPLists > 0); + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) { + // Save (non-extended) type source info pointer. + TypeSourceInfo *savedTInfo = DeclInfo.get<TypeSourceInfo*>(); + // Allocate external info struct. + DeclInfo = new (getASTContext()) ExtInfo; + // Restore savedTInfo into (extended) decl info. + getExtInfo()->TInfo = savedTInfo; + } + // Set the template parameter lists info. + getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); +} + +SourceLocation DeclaratorDecl::getOuterLocStart() const { + return getTemplateOrInnerLocStart(this); +} + +namespace { + +// Helper function: returns true if QT is or contains a type +// having a postfix component. +bool typeIsPostfix(clang::QualType QT) { + while (true) { + const Type* T = QT.getTypePtr(); + switch (T->getTypeClass()) { + default: + return false; + case Type::Pointer: + QT = cast<PointerType>(T)->getPointeeType(); + break; + case Type::BlockPointer: + QT = cast<BlockPointerType>(T)->getPointeeType(); + break; + case Type::MemberPointer: + QT = cast<MemberPointerType>(T)->getPointeeType(); + break; + case Type::LValueReference: + case Type::RValueReference: + QT = cast<ReferenceType>(T)->getPointeeType(); + break; + case Type::PackExpansion: + QT = cast<PackExpansionType>(T)->getPattern(); + break; + case Type::Paren: + case Type::ConstantArray: + case Type::DependentSizedArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::FunctionProto: + case Type::FunctionNoProto: + return true; + } + } +} + +} // namespace + +SourceRange DeclaratorDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocation(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { + if (typeIsPostfix(TInfo->getType())) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + } + return SourceRange(getOuterLocStart(), RangeEnd); +} + +void +QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert((NumTPLists == 0 || TPLists != 0) && + "Empty array of template parameters with positive size!"); + + // Free previous template parameters (if any). + if (NumTemplParamLists > 0) { + Context.Deallocate(TemplParamLists); + TemplParamLists = 0; + NumTemplParamLists = 0; + } + // Set info on matched template parameter lists (if any). + if (NumTPLists > 0) { + TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; + NumTemplParamLists = NumTPLists; + for (unsigned i = NumTPLists; i-- > 0; ) + TemplParamLists[i] = TPLists[i]; + } +} + +//===----------------------------------------------------------------------===// +// VarDecl Implementation +//===----------------------------------------------------------------------===// + +const char *VarDecl::getStorageClassSpecifierString(StorageClass SC) { + switch (SC) { + case SC_None: break; + case SC_Auto: return "auto"; break; + case SC_Extern: return "extern"; break; + case SC_PrivateExtern: return "__private_extern__"; break; + case SC_Register: return "register"; break; + case SC_Static: return "static"; break; + } + + assert(0 && "Invalid storage class"); + return 0; +} + +VarDecl *VarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartL, SourceLocation IdL, + IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten) { + return new (C) VarDecl(Var, DC, StartL, IdL, Id, T, TInfo, S, SCAsWritten); +} + +void VarDecl::setStorageClass(StorageClass SC) { + assert(isLegalForVariable(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + VarDeclBits.SClass = SC; +} + +SourceRange VarDecl::getSourceRange() const { + if (getInit()) + return SourceRange(getOuterLocStart(), getInit()->getLocEnd()); + return DeclaratorDecl::getSourceRange(); +} + +bool VarDecl::isExternC() const { + ASTContext &Context = getASTContext(); + if (!Context.getLangOptions().CPlusPlus) + return (getDeclContext()->isTranslationUnit() && + getStorageClass() != SC_Static) || + (getDeclContext()->isFunctionOrMethod() && hasExternalStorage()); + + const DeclContext *DC = getDeclContext(); + if (DC->isFunctionOrMethod()) + return false; + + for (; !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != SC_Static; + + break; + } + + } + + return false; +} + +VarDecl *VarDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + +VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition() const { + // C++ [basic.def]p2: + // A declaration is a definition unless [...] it contains the 'extern' + // specifier or a linkage-specification and neither an initializer [...], + // it declares a static data member in a class declaration [...]. + // C++ [temp.expl.spec]p15: + // An explicit specialization of a static data member of a template is a + // definition if the declaration includes an initializer; otherwise, it is + // a declaration. + if (isStaticDataMember()) { + if (isOutOfLine() && (hasInit() || + getTemplateSpecializationKind() != TSK_ExplicitSpecialization)) + return Definition; + else + return DeclarationOnly; + } + // C99 6.7p5: + // A definition of an identifier is a declaration for that identifier that + // [...] causes storage to be reserved for that object. + // Note: that applies for all non-file-scope objects. + // C99 6.9.2p1: + // If the declaration of an identifier for an object has file scope and an + // initializer, the declaration is an external definition for the identifier + if (hasInit()) + return Definition; + // AST for 'extern "C" int foo;' is annotated with 'extern'. + if (hasExternalStorage()) + return DeclarationOnly; + + if (getStorageClassAsWritten() == SC_Extern || + getStorageClassAsWritten() == SC_PrivateExtern) { + for (const VarDecl *PrevVar = getPreviousDeclaration(); + PrevVar; PrevVar = PrevVar->getPreviousDeclaration()) { + if (PrevVar->getLinkage() == InternalLinkage && PrevVar->hasInit()) + return DeclarationOnly; + } + } + // C99 6.9.2p2: + // A declaration of an object that has file scope without an initializer, + // and without a storage class specifier or the scs 'static', constitutes + // a tentative definition. + // No such thing in C++. + if (!getASTContext().getLangOptions().CPlusPlus && isFileVarDecl()) + return TentativeDefinition; + + // What's left is (in C, block-scope) declarations without initializers or + // external storage. These are definitions. + return Definition; +} + +VarDecl *VarDecl::getActingDefinition() { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return 0; + + VarDecl *LastTentative = 0; + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + Kind = (*I)->isThisDeclarationADefinition(); + if (Kind == Definition) + return 0; + else if (Kind == TentativeDefinition) + LastTentative = *I; + } + return LastTentative; +} + +bool VarDecl::isTentativeDefinitionNow() const { + DefinitionKind Kind = isThisDeclarationADefinition(); + if (Kind != TentativeDefinition) + return false; + + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return false; + } + return true; +} + +VarDecl *VarDecl::getDefinition() { + VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) { + if ((*I)->isThisDeclarationADefinition() == Definition) + return *I; + } + return 0; +} + +VarDecl::DefinitionKind VarDecl::hasDefinition() const { + DefinitionKind Kind = DeclarationOnly; + + const VarDecl *First = getFirstDeclaration(); + for (redecl_iterator I = First->redecls_begin(), E = First->redecls_end(); + I != E; ++I) + Kind = std::max(Kind, (*I)->isThisDeclarationADefinition()); + + return Kind; +} + +const Expr *VarDecl::getAnyInitializer(const VarDecl *&D) const { + redecl_iterator I = redecls_begin(), E = redecls_end(); + while (I != E && !I->getInit()) + ++I; + + if (I != E) { + D = *I; + return I->getInit(); + } + return 0; +} + +bool VarDecl::isOutOfLine() const { + if (Decl::isOutOfLine()) + return true; + + if (!isStaticDataMember()) + return false; + + // If this static data member was instantiated from a static data member of + // a class template, check whether that static data member was defined + // out-of-line. + if (VarDecl *VD = getInstantiatedFromStaticDataMember()) + return VD->isOutOfLine(); + + return false; +} + +VarDecl *VarDecl::getOutOfLineDefinition() { + if (!isStaticDataMember()) + return 0; + + for (VarDecl::redecl_iterator RD = redecls_begin(), RDEnd = redecls_end(); + RD != RDEnd; ++RD) { + if (RD->getLexicalDeclContext()->isFileContext()) + return *RD; + } + + return 0; +} + +void VarDecl::setInit(Expr *I) { + if (EvaluatedStmt *Eval = Init.dyn_cast<EvaluatedStmt *>()) { + Eval->~EvaluatedStmt(); + getASTContext().Deallocate(Eval); + } + + Init = I; +} + +VarDecl *VarDecl::getInstantiatedFromStaticDataMember() const { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return cast<VarDecl>(MSI->getInstantiatedFrom()); + + return 0; +} + +TemplateSpecializationKind VarDecl::getTemplateSpecializationKind() const { + if (MemberSpecializationInfo *MSI = getMemberSpecializationInfo()) + return MSI->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { + return getASTContext().getInstantiatedFromStaticDataMember(this); +} + +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { + MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); + assert(MSI && "Not an instantiated static data member?"); + MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); +} + +//===----------------------------------------------------------------------===// +// ParmVarDecl Implementation +//===----------------------------------------------------------------------===// + +ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + StorageClass S, StorageClass SCAsWritten, + Expr *DefArg) { + return new (C) ParmVarDecl(ParmVar, DC, StartLoc, IdLoc, Id, T, TInfo, + S, SCAsWritten, DefArg); +} + +Expr *ParmVarDecl::getDefaultArg() { + assert(!hasUnparsedDefaultArg() && "Default argument is not yet parsed!"); + assert(!hasUninstantiatedDefaultArg() && + "Default argument is not yet instantiated!"); + + Expr *Arg = getInit(); + if (ExprWithCleanups *E = dyn_cast_or_null<ExprWithCleanups>(Arg)) + return E->getSubExpr(); + + return Arg; +} + +unsigned ParmVarDecl::getNumDefaultArgTemporaries() const { + if (const ExprWithCleanups *E = dyn_cast<ExprWithCleanups>(getInit())) + return E->getNumTemporaries(); + + return 0; +} + +CXXTemporary *ParmVarDecl::getDefaultArgTemporary(unsigned i) { + assert(getNumDefaultArgTemporaries() && + "Default arguments does not have any temporaries!"); + + ExprWithCleanups *E = cast<ExprWithCleanups>(getInit()); + return E->getTemporary(i); +} + +SourceRange ParmVarDecl::getDefaultArgRange() const { + if (const Expr *E = getInit()) + return E->getSourceRange(); + + if (hasUninstantiatedDefaultArg()) + return getUninstantiatedDefaultArg()->getSourceRange(); + + return SourceRange(); +} + +bool ParmVarDecl::isParameterPack() const { + return isa<PackExpansionType>(getType()); +} + +//===----------------------------------------------------------------------===// +// FunctionDecl Implementation +//===----------------------------------------------------------------------===// + +void FunctionDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + const TemplateArgumentList *TemplateArgs = getTemplateSpecializationArgs(); + if (TemplateArgs) + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs->data(), + TemplateArgs->size(), + Policy); + +} + +bool FunctionDecl::isVariadic() const { + if (const FunctionProtoType *FT = getType()->getAs<FunctionProtoType>()) + return FT->isVariadic(); + return false; +} + +bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body || I->IsLateTemplateParsed) { + Definition = *I; + return true; + } + } + + return false; +} + +bool FunctionDecl::hasTrivialBody() const +{ + Stmt *S = getBody(); + if (!S) { + // Since we don't have a body for this function, we don't know if it's + // trivial or not. + return false; + } + + if (isa<CompoundStmt>(S) && cast<CompoundStmt>(S)->body_empty()) + return true; + return false; +} + +bool FunctionDecl::isDefined(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->IsDeleted || I->IsDefaulted || I->Body || I->IsLateTemplateParsed) { + Definition = I->IsDeleted ? I->getCanonicalDecl() : *I; + return true; + } + } + + return false; +} + +Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if (I->Body) { + Definition = *I; + return I->Body.get(getASTContext().getExternalSource()); + } else if (I->IsLateTemplateParsed) { + Definition = *I; + return 0; + } + } + + return 0; +} + +void FunctionDecl::setBody(Stmt *B) { + Body = B; + if (B) + EndRangeLoc = B->getLocEnd(); +} + +void FunctionDecl::setPure(bool P) { + IsPure = P; + if (P) + if (CXXRecordDecl *Parent = dyn_cast<CXXRecordDecl>(getDeclContext())) + Parent->markedVirtualFunctionPure(); +} + +bool FunctionDecl::isMain() const { + const TranslationUnitDecl *tunit = + dyn_cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()); + return tunit && + !tunit->getASTContext().getLangOptions().Freestanding && + getIdentifier() && + getIdentifier()->isStr("main"); +} + +bool FunctionDecl::isReservedGlobalPlacementOperator() const { + assert(getDeclName().getNameKind() == DeclarationName::CXXOperatorName); + assert(getDeclName().getCXXOverloadedOperator() == OO_New || + getDeclName().getCXXOverloadedOperator() == OO_Delete || + getDeclName().getCXXOverloadedOperator() == OO_Array_New || + getDeclName().getCXXOverloadedOperator() == OO_Array_Delete); + + if (isa<CXXRecordDecl>(getDeclContext())) return false; + assert(getDeclContext()->getRedeclContext()->isTranslationUnit()); + + const FunctionProtoType *proto = getType()->castAs<FunctionProtoType>(); + if (proto->getNumArgs() != 2 || proto->isVariadic()) return false; + + ASTContext &Context = + cast<TranslationUnitDecl>(getDeclContext()->getRedeclContext()) + ->getASTContext(); + + // The result type and first argument type are constant across all + // these operators. The second argument must be exactly void*. + return (proto->getArgType(1).getCanonicalType() == Context.VoidPtrTy); +} + +bool FunctionDecl::isExternC() const { + ASTContext &Context = getASTContext(); + // In C, any non-static, non-overloadable function has external + // linkage. + if (!Context.getLangOptions().CPlusPlus) + return getStorageClass() != SC_Static && !getAttr<OverloadableAttr>(); + + const DeclContext *DC = getDeclContext(); + if (DC->isRecord()) + return false; + + for (; !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) { + if (Linkage->getLanguage() == LinkageSpecDecl::lang_c) + return getStorageClass() != SC_Static && + !getAttr<OverloadableAttr>(); + + break; + } + } + + return isMain(); +} + +bool FunctionDecl::isGlobal() const { + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(this)) + return Method->isStatic(); + + if (getStorageClass() == SC_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; +} + +void +FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { + redeclarable_base::setPreviousDeclaration(PrevDecl); + + if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) { + FunctionTemplateDecl *PrevFunTmpl + = PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0; + assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch"); + FunTmpl->setPreviousDeclaration(PrevFunTmpl); + } + + if (PrevDecl->IsInline) + IsInline = true; +} + +const FunctionDecl *FunctionDecl::getCanonicalDecl() const { + return getFirstDeclaration(); +} + +FunctionDecl *FunctionDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + +void FunctionDecl::setStorageClass(StorageClass SC) { + assert(isLegalForFunction(SC)); + if (getStorageClass() != SC) + ClearLinkageCache(); + + SClass = SC; +} + +/// \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() const { + ASTContext &Context = getASTContext(); + 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() == SC_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 ParamInfo array +/// after it has been created. +unsigned FunctionDecl::getNumParams() const { + const FunctionType *FT = getType()->getAs<FunctionType>(); + 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); + + // Update source range. The check below allows us to set EndRangeLoc before + // setting the parameters. + if (EndRangeLoc.isInvalid() || EndRangeLoc == getLocation()) + EndRangeLoc = NewParamInfo[NumParams-1]->getLocEnd(); + } +} + +/// 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++) or the last parameter is a parameter pack. +unsigned FunctionDecl::getMinRequiredArguments() const { + if (!getASTContext().getLangOptions().CPlusPlus) + return getNumParams(); + + unsigned NumRequiredArgs = getNumParams(); + + // If the last parameter is a parameter pack, we don't need an argument for + // it. + if (NumRequiredArgs > 0 && + getParamDecl(NumRequiredArgs - 1)->isParameterPack()) + --NumRequiredArgs; + + // If this parameter has a default argument, we don't need an argument for + // it. + while (NumRequiredArgs > 0 && + getParamDecl(NumRequiredArgs-1)->hasDefaultArg()) + --NumRequiredArgs; + + // We might have parameter packs before the end. These can't be deduced, + // but they can still handle multiple arguments. + unsigned ArgIdx = NumRequiredArgs; + while (ArgIdx > 0) { + if (getParamDecl(ArgIdx - 1)->isParameterPack()) + NumRequiredArgs = ArgIdx; + + --ArgIdx; + } + + return NumRequiredArgs; +} + +bool FunctionDecl::isInlined() const { + if (IsInline) + return true; + + if (isa<CXXMethodDecl>(this)) { + if (!isOutOfLine() || getCanonicalDecl()->isInlineSpecified()) + return true; + } + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + return false; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + // Handle below. + break; + } + + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + bool HasPattern = false; + if (PatternDecl) + HasPattern = PatternDecl->hasBody(PatternDecl); + + if (HasPattern && PatternDecl) + return PatternDecl->isInlined(); + + return false; +} + +/// \brief For an inline function definition in C or C++, determine whether the +/// definition will be externally visible. +/// +/// Inline function definitions are always available for inlining optimizations. +/// However, depending on the language dialect, declaration specifiers, and +/// attributes, the definition of an inline function may or may not be +/// "externally" visible to other translation units in the program. +/// +/// In C99, inline definitions are not externally visible by default. However, +/// if even one of the global-scope declarations is marked "extern inline", the +/// inline definition becomes externally visible (C99 6.7.4p6). +/// +/// In GNU89 mode, or if the gnu_inline attribute is attached to the function +/// definition, we use the GNU semantics for inline, which are nearly the +/// opposite of C99 semantics. In particular, "inline" by itself will create +/// an externally visible symbol, but "extern inline" will not create an +/// externally visible symbol. +bool FunctionDecl::isInlineDefinitionExternallyVisible() const { + assert(doesThisDeclarationHaveABody() && "Must have the function definition"); + assert(isInlined() && "Function must be inline"); + ASTContext &Context = getASTContext(); + + if (Context.getLangOptions().GNUInline || hasAttr<GNUInlineAttr>()) { + // If it's not the case that both 'inline' and 'extern' are + // specified on the definition, then this inline definition is + // externally visible. + if (!(isInlineSpecified() && getStorageClassAsWritten() == SC_Extern)) + return true; + + // If any declaration is 'inline' but not 'extern', then this definition + // is externally visible. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + if (Redecl->isInlineSpecified() && + Redecl->getStorageClassAsWritten() != SC_Extern) + return true; + } + + return false; + } + + // C99 6.7.4p6: + // [...] If all of the file scope declarations for a function in a + // translation unit include the inline function specifier without extern, + // then the definition in that translation unit is an inline definition. + for (redecl_iterator Redecl = redecls_begin(), RedeclEnd = redecls_end(); + Redecl != RedeclEnd; + ++Redecl) { + // Only consider file-scope declarations in this test. + if (!Redecl->getLexicalDeclContext()->isTranslationUnit()) + continue; + + if (!Redecl->isInlineSpecified() || Redecl->getStorageClass() == SC_Extern) + return true; // Not an inline definition + } + + // C99 6.7.4p6: + // An inline definition does not provide an external definition for the + // function, and does not forbid an external definition in another + // translation unit. + 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; +} + +/// getLiteralIdentifier - The literal suffix identifier this function +/// represents, if any. +const IdentifierInfo *FunctionDecl::getLiteralIdentifier() const { + if (getDeclName().getNameKind() == DeclarationName::CXXLiteralOperatorName) + return getDeclName().getCXXLiteralIdentifier(); + else + return 0; +} + +FunctionDecl::TemplatedKind FunctionDecl::getTemplatedKind() const { + if (TemplateOrSpecialization.isNull()) + return TK_NonTemplate; + if (TemplateOrSpecialization.is<FunctionTemplateDecl *>()) + return TK_FunctionTemplate; + if (TemplateOrSpecialization.is<MemberSpecializationInfo *>()) + return TK_MemberSpecialization; + if (TemplateOrSpecialization.is<FunctionTemplateSpecializationInfo *>()) + return TK_FunctionTemplateSpecialization; + if (TemplateOrSpecialization.is + <DependentFunctionTemplateSpecializationInfo*>()) + return TK_DependentFunctionTemplateSpecialization; + + assert(false && "Did we miss a TemplateOrSpecialization type?"); + return TK_NonTemplate; +} + +FunctionDecl *FunctionDecl::getInstantiatedFromMemberFunction() const { + if (MemberSpecializationInfo *Info = getMemberSpecializationInfo()) + return cast<FunctionDecl>(Info->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *FunctionDecl::getMemberSpecializationInfo() const { + return TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); +} + +void +FunctionDecl::setInstantiationOfMemberFunction(ASTContext &C, + FunctionDecl *FD, + TemplateSpecializationKind TSK) { + assert(TemplateOrSpecialization.isNull() && + "Member function is already a specialization"); + MemberSpecializationInfo *Info + = new (C) MemberSpecializationInfo(FD, TSK); + TemplateOrSpecialization = Info; +} + +bool FunctionDecl::isImplicitlyInstantiable() const { + // If the function is invalid, it can't be implicitly instantiated. + if (isInvalidDecl()) + return false; + + switch (getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + case TSK_ExplicitInstantiationDefinition: + return false; + + case TSK_ImplicitInstantiation: + return true; + + case TSK_ExplicitInstantiationDeclaration: + // Handled below. + break; + } + + // Find the actual template from which we will instantiate. + const FunctionDecl *PatternDecl = getTemplateInstantiationPattern(); + bool HasPattern = false; + if (PatternDecl) + HasPattern = PatternDecl->hasBody(PatternDecl); + + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (!HasPattern || !PatternDecl) + return true; + + return PatternDecl->isInlined(); +} + +FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const { + if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) { + while (Primary->getInstantiatedFromMemberTemplate()) { + // If we have hit a point where the user provided a specialization of + // this template, we're done looking. + if (Primary->isMemberSpecialization()) + break; + + Primary = Primary->getInstantiatedFromMemberTemplate(); + } + + return Primary->getTemplatedDecl(); + } + + return getInstantiatedFromMemberFunction(); +} + +FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + return Info->Template.getPointer(); + } + return 0; +} + +const TemplateArgumentList * +FunctionDecl::getTemplateSpecializationArgs() const { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + return Info->TemplateArguments; + } + return 0; +} + +const TemplateArgumentListInfo * +FunctionDecl::getTemplateSpecializationArgsAsWritten() const { + if (FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization + .dyn_cast<FunctionTemplateSpecializationInfo*>()) { + return Info->TemplateArgumentsAsWritten; + } + return 0; +} + +void +FunctionDecl::setFunctionTemplateSpecialization(ASTContext &C, + FunctionTemplateDecl *Template, + const TemplateArgumentList *TemplateArgs, + void *InsertPos, + TemplateSpecializationKind TSK, + const TemplateArgumentListInfo *TemplateArgsAsWritten, + SourceLocation PointOfInstantiation) { + assert(TSK != TSK_Undeclared && + "Must specify the type of function template specialization"); + FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); + if (!Info) + Info = FunctionTemplateSpecializationInfo::Create(C, this, Template, TSK, + TemplateArgs, + TemplateArgsAsWritten, + PointOfInstantiation); + TemplateOrSpecialization = Info; + + // Insert this function template specialization into the set of known + // function template specializations. + if (InsertPos) + Template->addSpecialization(Info, InsertPos); + else { + // Try to insert the new node. If there is an existing node, leave it, the + // set will contain the canonical decls while + // FunctionTemplateDecl::findSpecialization will return + // the most recent redeclarations. + FunctionTemplateSpecializationInfo *Existing + = Template->getSpecializations().GetOrInsertNode(Info); + (void)Existing; + assert((!Existing || Existing->Function->isCanonicalDecl()) && + "Set is supposed to only contain canonical decls"); + } +} + +void +FunctionDecl::setDependentTemplateSpecialization(ASTContext &Context, + const UnresolvedSetImpl &Templates, + const TemplateArgumentListInfo &TemplateArgs) { + assert(TemplateOrSpecialization.isNull()); + size_t Size = sizeof(DependentFunctionTemplateSpecializationInfo); + Size += Templates.size() * sizeof(FunctionTemplateDecl*); + Size += TemplateArgs.size() * sizeof(TemplateArgumentLoc); + void *Buffer = Context.Allocate(Size); + DependentFunctionTemplateSpecializationInfo *Info = + new (Buffer) DependentFunctionTemplateSpecializationInfo(Templates, + TemplateArgs); + TemplateOrSpecialization = Info; +} + +DependentFunctionTemplateSpecializationInfo:: +DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, + const TemplateArgumentListInfo &TArgs) + : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + + d.NumTemplates = Ts.size(); + d.NumArgs = TArgs.size(); + + FunctionTemplateDecl **TsArray = + const_cast<FunctionTemplateDecl**>(getTemplates()); + for (unsigned I = 0, E = Ts.size(); I != E; ++I) + TsArray[I] = cast<FunctionTemplateDecl>(Ts[I]->getUnderlyingDecl()); + + TemplateArgumentLoc *ArgsArray = + const_cast<TemplateArgumentLoc*>(getTemplateArgs()); + for (unsigned I = 0, E = TArgs.size(); I != E; ++I) + new (&ArgsArray[I]) TemplateArgumentLoc(TArgs[I]); +} + +TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { + // For a function template specialization, query the specialization + // information object. + FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); + if (FTSInfo) + return FTSInfo->getTemplateSpecializationKind(); + + MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>(); + if (MSInfo) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) { + FTSInfo->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) { + MSInfo->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else + assert(false && "Function cannot have a template specialization kind"); +} + +SourceLocation FunctionDecl::getPointOfInstantiation() const { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + return FTSInfo->getPointOfInstantiation(); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast<MemberSpecializationInfo*>()) + return MSInfo->getPointOfInstantiation(); + + return SourceLocation(); +} + +bool FunctionDecl::isOutOfLine() const { + if (Decl::isOutOfLine()) + return true; + + // If this function was instantiated from a member function of a + // class template, check whether that member function was defined out-of-line. + if (FunctionDecl *FD = getInstantiatedFromMemberFunction()) { + const FunctionDecl *Definition; + if (FD->hasBody(Definition)) + return Definition->isOutOfLine(); + } + + // If this function was instantiated from a function template, + // check whether that function template was defined out-of-line. + if (FunctionTemplateDecl *FunTmpl = getPrimaryTemplate()) { + const FunctionDecl *Definition; + if (FunTmpl->getTemplatedDecl()->hasBody(Definition)) + return Definition->isOutOfLine(); + } + + return false; +} + +SourceRange FunctionDecl::getSourceRange() const { + return SourceRange(getOuterLocStart(), EndRangeLoc); +} + +//===----------------------------------------------------------------------===// +// FieldDecl Implementation +//===----------------------------------------------------------------------===// + +FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, Expr *BW, bool Mutable, + bool HasInit) { + return new (C) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, + BW, Mutable, HasInit); +} + +bool FieldDecl::isAnonymousStructOrUnion() const { + if (!isImplicit() || getDeclName()) + return false; + + if (const RecordType *Record = getType()->getAs<RecordType>()) + return Record->getDecl()->isAnonymousStructOrUnion(); + + return false; +} + +unsigned FieldDecl::getFieldIndex() const { + if (CachedFieldIndex) return CachedFieldIndex - 1; + + unsigned index = 0; + const RecordDecl *RD = getParent(); + const FieldDecl *LastFD = 0; + bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + + RecordDecl::field_iterator i = RD->field_begin(), e = RD->field_end(); + while (true) { + assert(i != e && "failed to find field in parent!"); + if (*i == this) + break; + + if (IsMsStruct) { + // Zero-length bitfields following non-bitfield members are ignored. + if (getASTContext().ZeroBitfieldFollowsNonBitfield((*i), LastFD)) { + ++i; + continue; + } + LastFD = (*i); + } + ++i; + ++index; + } + + CachedFieldIndex = index + 1; + return index; +} + +SourceRange FieldDecl::getSourceRange() const { + if (isBitField()) + return SourceRange(getInnerLocStart(), getBitWidth()->getLocEnd()); + return DeclaratorDecl::getSourceRange(); +} + +void FieldDecl::setInClassInitializer(Expr *Init) { + assert(!InitializerOrBitWidth.getPointer() && + "bit width or initializer already set"); + InitializerOrBitWidth.setPointer(Init); + InitializerOrBitWidth.setInt(0); +} + +//===----------------------------------------------------------------------===// +// TagDecl Implementation +//===----------------------------------------------------------------------===// + +SourceLocation TagDecl::getOuterLocStart() const { + return getTemplateOrInnerLocStart(this); +} + +SourceRange TagDecl::getSourceRange() const { + SourceLocation E = RBraceLoc.isValid() ? RBraceLoc : getLocation(); + return SourceRange(getOuterLocStart(), E); +} + +TagDecl* TagDecl::getCanonicalDecl() { + return getFirstDeclaration(); +} + +void TagDecl::setTypedefNameForAnonDecl(TypedefNameDecl *TDD) { + TypedefNameDeclOrQualifier = TDD; + if (TypeForDecl) + const_cast<Type*>(TypeForDecl)->ClearLinkageCache(); + ClearLinkageCache(); +} + +void TagDecl::startDefinition() { + IsBeingDefined = true; + + if (isa<CXXRecordDecl>(this)) { + CXXRecordDecl *D = cast<CXXRecordDecl>(this); + struct CXXRecordDecl::DefinitionData *Data = + new (getASTContext()) struct CXXRecordDecl::DefinitionData(D); + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + cast<CXXRecordDecl>(*I)->DefinitionData = Data; + } +} + +void TagDecl::completeDefinition() { + assert((!isa<CXXRecordDecl>(this) || + cast<CXXRecordDecl>(this)->hasDefinition()) && + "definition completed but not started"); + + IsDefinition = true; + IsBeingDefined = false; + + if (ASTMutationListener *L = getASTMutationListener()) + L->CompletedTagDefinition(this); +} + +TagDecl* TagDecl::getDefinition() const { + if (isDefinition()) + return const_cast<TagDecl *>(this); + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this)) + return CXXRD->getDefinition(); + + for (redecl_iterator R = redecls_begin(), REnd = redecls_end(); + R != REnd; ++R) + if (R->isDefinition()) + return *R; + + return 0; +} + +void TagDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { + if (QualifierLoc) { + // Make sure the extended qualifier info is allocated. + if (!hasExtInfo()) + TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + // Set qualifier info. + getExtInfo()->QualifierLoc = QualifierLoc; + } + else { + // Here Qualifier == 0, i.e., we are removing the qualifier (if any). + if (hasExtInfo()) { + if (getExtInfo()->NumTemplParamLists == 0) { + getASTContext().Deallocate(getExtInfo()); + TypedefNameDeclOrQualifier = (TypedefNameDecl*) 0; + } + else + getExtInfo()->QualifierLoc = QualifierLoc; + } + } +} + +void TagDecl::setTemplateParameterListsInfo(ASTContext &Context, + unsigned NumTPLists, + TemplateParameterList **TPLists) { + assert(NumTPLists > 0); + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) + // Allocate external info struct. + TypedefNameDeclOrQualifier = new (getASTContext()) ExtInfo; + // Set the template parameter lists info. + getExtInfo()->setTemplateParameterListsInfo(Context, NumTPLists, TPLists); +} + +//===----------------------------------------------------------------------===// +// EnumDecl Implementation +//===----------------------------------------------------------------------===// + +EnumDecl *EnumDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, + EnumDecl *PrevDecl, bool IsScoped, + bool IsScopedUsingClassTag, bool IsFixed) { + EnumDecl *Enum = new (C) EnumDecl(DC, StartLoc, IdLoc, Id, PrevDecl, + IsScoped, IsScopedUsingClassTag, IsFixed); + C.getTypeDeclType(Enum, PrevDecl); + return Enum; +} + +EnumDecl *EnumDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) EnumDecl(0, SourceLocation(), SourceLocation(), 0, 0, + false, false, false); +} + +void EnumDecl::completeDefinition(QualType NewType, + QualType NewPromotionType, + unsigned NumPositiveBits, + unsigned NumNegativeBits) { + assert(!isDefinition() && "Cannot redefine enums!"); + if (!IntegerType) + IntegerType = NewType.getTypePtr(); + PromotionType = NewPromotionType; + setNumPositiveBits(NumPositiveBits); + setNumNegativeBits(NumNegativeBits); + TagDecl::completeDefinition(); +} + +//===----------------------------------------------------------------------===// +// RecordDecl Implementation +//===----------------------------------------------------------------------===// + +RecordDecl::RecordDecl(Kind DK, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl *PrevDecl) + : TagDecl(DK, TK, DC, IdLoc, Id, PrevDecl, StartLoc) { + HasFlexibleArrayMember = false; + AnonymousStructOrUnion = false; + HasObjectMember = false; + LoadedFieldsFromExternalStorage = false; + assert(classof(static_cast<Decl*>(this)) && "Invalid Kind!"); +} + +RecordDecl *RecordDecl::Create(const ASTContext &C, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, RecordDecl* PrevDecl) { + RecordDecl* R = new (C) RecordDecl(Record, TK, DC, StartLoc, IdLoc, Id, + PrevDecl); + C.getTypeDeclType(R, PrevDecl); + return R; +} + +RecordDecl *RecordDecl::Create(const ASTContext &C, EmptyShell Empty) { + return new (C) RecordDecl(Record, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); +} + +bool RecordDecl::isInjectedClassName() const { + return isImplicit() && getDeclName() && getDeclContext()->isRecord() && + cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); +} + +RecordDecl::field_iterator RecordDecl::field_begin() const { + if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage) + LoadFieldsFromExternalStorage(); + + return field_iterator(decl_iterator(FirstDecl)); +} + +/// completeDefinition - Notes that the definition of this type is now +/// complete. +void RecordDecl::completeDefinition() { + assert(!isDefinition() && "Cannot redefine record!"); + TagDecl::completeDefinition(); +} + +void RecordDecl::LoadFieldsFromExternalStorage() const { + ExternalASTSource *Source = getASTContext().getExternalSource(); + assert(hasExternalLexicalStorage() && Source && "No external storage?"); + + // Notify that we have a RecordDecl doing some initialization. + ExternalASTSource::Deserializing TheFields(Source); + + llvm::SmallVector<Decl*, 64> Decls; + if (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) + return; + +#ifndef NDEBUG + // Check that all decls we got were FieldDecls. + for (unsigned i=0, e=Decls.size(); i != e; ++i) + assert(isa<FieldDecl>(Decls[i])); +#endif + + LoadedFieldsFromExternalStorage = true; + + if (Decls.empty()) + return; + + llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); +} + +//===----------------------------------------------------------------------===// +// BlockDecl Implementation +//===----------------------------------------------------------------------===// + +void BlockDecl::setParams(ParmVarDecl **NewParamInfo, + unsigned NParms) { + assert(ParamInfo == 0 && "Already has param info!"); + + // Zero params -> null pointer. + if (NParms) { + NumParams = NParms; + void *Mem = getASTContext().Allocate(sizeof(ParmVarDecl*)*NumParams); + ParamInfo = new (Mem) ParmVarDecl*[NumParams]; + memcpy(ParamInfo, NewParamInfo, sizeof(ParmVarDecl*)*NumParams); + } +} + +void BlockDecl::setCaptures(ASTContext &Context, + const Capture *begin, + const Capture *end, + bool capturesCXXThis) { + CapturesCXXThis = capturesCXXThis; + + if (begin == end) { + NumCaptures = 0; + Captures = 0; + return; + } + + NumCaptures = end - begin; + + // Avoid new Capture[] because we don't want to provide a default + // constructor. + size_t allocationSize = NumCaptures * sizeof(Capture); + void *buffer = Context.Allocate(allocationSize, /*alignment*/sizeof(void*)); + memcpy(buffer, begin, allocationSize); + Captures = static_cast<Capture*>(buffer); +} + +SourceRange BlockDecl::getSourceRange() const { + return SourceRange(getLocation(), Body? Body->getLocEnd() : getLocation()); +} + +//===----------------------------------------------------------------------===// +// Other Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { + return new (C) TranslationUnitDecl(C); +} + +LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II) { + return new (C) LabelDecl(DC, IdentL, II, 0, IdentL); +} + +LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation IdentL, IdentifierInfo *II, + SourceLocation GnuLabelL) { + assert(GnuLabelL != IdentL && "Use this only for GNU local labels"); + return new (C) LabelDecl(DC, IdentL, II, 0, GnuLabelL); +} + + +NamespaceDecl *NamespaceDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id) { + return new (C) NamespaceDecl(DC, StartLoc, IdLoc, Id); +} + +NamespaceDecl *NamespaceDecl::getNextNamespace() { + return dyn_cast_or_null<NamespaceDecl>( + NextNamespace.get(getASTContext().getExternalSource())); +} + +ImplicitParamDecl *ImplicitParamDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation IdLoc, + IdentifierInfo *Id, + QualType Type) { + return new (C) ImplicitParamDecl(DC, IdLoc, Id, Type); +} + +FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + StorageClass SC, StorageClass SCAsWritten, + bool isInlineSpecified, + bool hasWrittenPrototype) { + FunctionDecl *New = new (C) FunctionDecl(Function, DC, StartLoc, NameInfo, + T, TInfo, SC, SCAsWritten, + isInlineSpecified); + New->HasWrittenPrototype = hasWrittenPrototype; + return New; +} + +BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { + return new (C) BlockDecl(DC, L); +} + +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); +} + +IndirectFieldDecl * +IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + IdentifierInfo *Id, QualType T, NamedDecl **CH, + unsigned CHS) { + return new (C) IndirectFieldDecl(DC, L, Id, T, CH, CHS); +} + +SourceRange EnumConstantDecl::getSourceRange() const { + SourceLocation End = getLocation(); + if (Init) + End = Init->getLocEnd(); + return SourceRange(getLocation(), End); +} + +TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, TypeSourceInfo *TInfo) { + return new (C) TypedefDecl(DC, StartLoc, IdLoc, Id, TInfo); +} + +TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + TypeSourceInfo *TInfo) { + return new (C) TypeAliasDecl(DC, StartLoc, IdLoc, Id, TInfo); +} + +SourceRange TypedefDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocation(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) { + if (typeIsPostfix(TInfo->getType())) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + } + return SourceRange(getLocStart(), RangeEnd); +} + +SourceRange TypeAliasDecl::getSourceRange() const { + SourceLocation RangeEnd = getLocStart(); + if (TypeSourceInfo *TInfo = getTypeSourceInfo()) + RangeEnd = TInfo->getTypeLoc().getSourceRange().getEnd(); + return SourceRange(getLocStart(), RangeEnd); +} + +FileScopeAsmDecl *FileScopeAsmDecl::Create(ASTContext &C, DeclContext *DC, + StringLiteral *Str, + SourceLocation AsmLoc, + SourceLocation RParenLoc) { + return new (C) FileScopeAsmDecl(DC, Str, AsmLoc, RParenLoc); +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp new file mode 100644 index 000000000000..1766d39c1405 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclBase.cpp @@ -0,0 +1,1293 @@ +//===--- 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/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DependentDiagnostic.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 "clang/AST/ASTMutationListener.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstdio> +using namespace clang; + +//===----------------------------------------------------------------------===// +// Statistics +//===----------------------------------------------------------------------===// + +#define DECL(DERIVED, BASE) static int n##DERIVED##s = 0; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + +static bool StatSwitch = false; + +const char *Decl::getDeclKindName() const { + switch (DeclKind) { + default: assert(0 && "Declaration not in DeclNodes.inc!"); +#define DECL(DERIVED, BASE) case DERIVED: return #DERIVED; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } +} + +void Decl::setInvalidDecl(bool Invalid) { + InvalidDecl = Invalid; + if (Invalid) { + // Defensive maneuver for ill-formed code: we're likely not to make it to + // a point where we set the access specifier, so default it to "public" + // to avoid triggering asserts elsewhere in the front end. + setAccess(AS_public); + } +} + +const char *DeclContext::getDeclKindName() const { + switch (DeclKind) { + default: assert(0 && "Declaration context not in DeclNodes.inc!"); +#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } +} + +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; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + 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))); \ + } +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + + fprintf(stderr, "Total bytes = %d\n", totalBytes); +} + +void Decl::add(Kind k) { + switch (k) { + default: assert(0 && "Declaration not in DeclNodes.inc!"); +#define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } +} + +bool Decl::isTemplateParameterPack() const { + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) + return TTP->isParameterPack(); + if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(this)) + return NTTP->isParameterPack(); + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(this)) + return TTP->isParameterPack(); + return false; +} + +bool Decl::isParameterPack() const { + if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(this)) + return Parm->isParameterPack(); + + return isTemplateParameterPack(); +} + +bool Decl::isFunctionOrFunctionTemplate() const { + if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this)) + return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); + + return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); +} + +bool Decl::isDefinedOutsideFunctionOrMethod() const { + for (const DeclContext *DC = getDeclContext(); + DC && !DC->isTranslationUnit(); + DC = DC->getParent()) + if (DC->isFunctionOrMethod()) + return false; + + return true; +} + + +//===----------------------------------------------------------------------===// +// 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 (const 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() { } + +void Decl::setDeclContext(DeclContext *DC) { + DeclCtx = DC; +} + +void Decl::setLexicalDeclContext(DeclContext *DC) { + if (DC == getLexicalDeclContext()) + return; + + if (isInSemaDC()) { + MultipleDC *MDC = new (getASTContext()) MultipleDC(); + MDC->SemanticDC = getDeclContext(); + MDC->LexicalDC = DC; + DeclCtx = MDC; + } else { + getMultipleDC()->LexicalDC = DC; + } +} + +bool Decl::isInAnonymousNamespace() const { + const DeclContext *DC = getDeclContext(); + do { + if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) + if (ND->isAnonymousNamespace()) + return true; + } while ((DC = DC->getParent())); + + return false; +} + +TranslationUnitDecl *Decl::getTranslationUnitDecl() { + if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this)) + return TUD; + + DeclContext *DC = getDeclContext(); + assert(DC && "This decl is not contained in a translation unit!"); + + while (!DC->isTranslationUnit()) { + DC = DC->getParent(); + assert(DC && "This decl is not contained in a translation unit!"); + } + + return cast<TranslationUnitDecl>(DC); +} + +ASTContext &Decl::getASTContext() const { + return getTranslationUnitDecl()->getASTContext(); +} + +ASTMutationListener *Decl::getASTMutationListener() const { + return getASTContext().getASTMutationListener(); +} + +bool Decl::isUsed(bool CheckUsedAttr) const { + if (Used) + return true; + + // Check for used attribute. + if (CheckUsedAttr && hasAttr<UsedAttr>()) + return true; + + // Check redeclarations for used attribute. + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { + if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used) + return true; + } + + return false; +} + +bool Decl::isReferenced() const { + if (Referenced) + return true; + + // Check redeclarations. + for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) + if (I->Referenced) + return true; + + return false; +} + +/// \brief Determine the availability of the given declaration based on +/// the target platform. +/// +/// When it returns an availability result other than \c AR_Available, +/// if the \p Message parameter is non-NULL, it will be set to a +/// string describing why the entity is unavailable. +/// +/// FIXME: Make these strings localizable, since they end up in +/// diagnostics. +static AvailabilityResult CheckAvailability(ASTContext &Context, + const AvailabilityAttr *A, + std::string *Message) { + llvm::StringRef TargetPlatform = Context.Target.getPlatformName(); + llvm::StringRef PrettyPlatformName + = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); + if (PrettyPlatformName.empty()) + PrettyPlatformName = TargetPlatform; + + VersionTuple TargetMinVersion = Context.Target.getPlatformMinVersion(); + if (TargetMinVersion.empty()) + return AR_Available; + + // Match the platform name. + if (A->getPlatform()->getName() != TargetPlatform) + return AR_Available; + + // Make sure that this declaration has not been marked 'unavailable'. + if (A->getUnavailable()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "not available on " << PrettyPlatformName; + } + + return AR_Unavailable; + } + + // Make sure that this declaration has already been introduced. + if (!A->getIntroduced().empty() && + TargetMinVersion < A->getIntroduced()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "introduced in " << PrettyPlatformName << ' ' + << A->getIntroduced(); + } + + return AR_NotYetIntroduced; + } + + // Make sure that this declaration hasn't been obsoleted. + if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "obsoleted in " << PrettyPlatformName << ' ' + << A->getObsoleted(); + } + + return AR_Unavailable; + } + + // Make sure that this declaration hasn't been deprecated. + if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) { + if (Message) { + Message->clear(); + llvm::raw_string_ostream Out(*Message); + Out << "first deprecated in " << PrettyPlatformName << ' ' + << A->getDeprecated(); + } + + return AR_Deprecated; + } + + return AR_Available; +} + +AvailabilityResult Decl::getAvailability(std::string *Message) const { + AvailabilityResult Result = AR_Available; + std::string ResultMessage; + + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) { + if (Result >= AR_Deprecated) + continue; + + if (Message) + ResultMessage = Deprecated->getMessage(); + + Result = AR_Deprecated; + continue; + } + + if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) { + if (Message) + *Message = Unavailable->getMessage(); + return AR_Unavailable; + } + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, + Message); + + if (AR == AR_Unavailable) + return AR_Unavailable; + + if (AR > Result) { + Result = AR; + if (Message) + ResultMessage.swap(*Message); + } + continue; + } + } + + if (Message) + Message->swap(ResultMessage); + return Result; +} + +bool Decl::canBeWeakImported(bool &IsDefinition) const { + IsDefinition = false; + if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { + if (!Var->hasExternalStorage() || Var->getInit()) { + IsDefinition = true; + return false; + } + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + if (FD->hasBody()) { + IsDefinition = true; + return false; + } + } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this)) + return false; + else if (!(getASTContext().getLangOptions().ObjCNonFragileABI && + isa<ObjCInterfaceDecl>(this))) + return false; + + return true; +} + +bool Decl::isWeakImported() const { + bool IsDefinition; + if (!canBeWeakImported(IsDefinition)) + return false; + + for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { + if (isa<WeakImportAttr>(*A)) + return true; + + if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { + if (CheckAvailability(getASTContext(), Availability, 0) + == AR_NotYetIntroduced) + return true; + } + } + + return false; +} + +unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { + switch (DeclKind) { + case Function: + case CXXMethod: + case CXXConstructor: + case CXXDestructor: + case CXXConversion: + case EnumConstant: + case Var: + case ImplicitParam: + case ParmVar: + case NonTypeTemplateParm: + case ObjCMethod: + case ObjCProperty: + return IDNS_Ordinary; + case Label: + return IDNS_Label; + case IndirectField: + return IDNS_Ordinary | IDNS_Member; + + case ObjCCompatibleAlias: + case ObjCInterface: + return IDNS_Ordinary | IDNS_Type; + + case Typedef: + case TypeAlias: + case TypeAliasTemplate: + case UnresolvedUsingTypename: + case TemplateTypeParm: + return IDNS_Ordinary | IDNS_Type; + + case UsingShadow: + return 0; // we'll actually overwrite this later + + case UnresolvedUsingValue: + return IDNS_Ordinary | IDNS_Using; + + case Using: + return IDNS_Using; + + case ObjCProtocol: + return IDNS_ObjCProtocol; + + case Field: + case ObjCAtDefsField: + case ObjCIvar: + return IDNS_Member; + + case Record: + case CXXRecord: + case Enum: + return IDNS_Tag | IDNS_Type; + + case Namespace: + case NamespaceAlias: + return IDNS_Namespace; + + case FunctionTemplate: + return IDNS_Ordinary; + + case ClassTemplate: + case TemplateTemplateParm: + return IDNS_Ordinary | IDNS_Tag | IDNS_Type; + + // Never have names. + case Friend: + case FriendTemplate: + case AccessSpec: + case LinkageSpec: + case FileScopeAsm: + case StaticAssert: + case ObjCClass: + case ObjCPropertyImpl: + case ObjCForwardProtocol: + case Block: + case TranslationUnit: + + case UsingDirective: + case ClassTemplateSpecialization: + case ClassTemplatePartialSpecialization: + case ObjCImplementation: + case ObjCCategory: + case ObjCCategoryImpl: + // Never looked up by name. + return 0; + } + + return 0; +} + +void Decl::setAttrs(const AttrVec &attrs) { + assert(!HasAttrs && "Decl already contains attrs."); + + AttrVec &AttrBlank = getASTContext().getDeclAttrs(this); + assert(AttrBlank.empty() && "HasAttrs was wrong?"); + + AttrBlank = attrs; + HasAttrs = true; +} + +void Decl::dropAttrs() { + if (!HasAttrs) return; + + HasAttrs = false; + getASTContext().eraseDeclAttrs(this); +} + +const AttrVec &Decl::getAttrs() const { + assert(HasAttrs && "No attrs to get!"); + return getASTContext().getDeclAttrs(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); + + ASTContext &Context = getASTContext(); + + // Handle the case when both decls have attrs. + if (HasRHSAttr) { + std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); + return; + } + + // Otherwise, LHS has an attr and RHS doesn't. + Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); + Context.eraseDeclAttrs(this); + this->HasAttrs = false; + RHS->HasAttrs = true; +} + +Decl *Decl::castFromDeclContext (const DeclContext *D) { + Decl::Kind DK = D->getDeclKind(); + switch(DK) { +#define DECL(NAME, BASE) +#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.inc" + default: +#define DECL(NAME, BASE) +#define DECL_CONTEXT_BASE(NAME) \ + if (DK >= first##NAME && DK <= last##NAME) \ + return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); +#include "clang/AST/DeclNodes.inc" + 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(NAME, BASE) +#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.inc" + default: +#define DECL(NAME, BASE) +#define DECL_CONTEXT_BASE(NAME) \ + if (DK >= first##NAME && DK <= last##NAME) \ + return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); +#include "clang/AST/DeclNodes.inc" + assert(false && "a decl that inherits DeclContext isn't handled"); + return 0; + } +} + +SourceLocation Decl::getBodyRBrace() const { + // Special handling of FunctionDecl to avoid de-serializing the body from PCH. + // FunctionDecl stores EndRangeLoc for this purpose. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { + const FunctionDecl *Definition; + if (FD->hasBody(Definition)) + return Definition->getSourceRange().getEnd(); + return SourceLocation(); + } + + if (Stmt *Body = getBody()) + return Body->getSourceRange().getEnd(); + + return SourceLocation(); +} + +void Decl::CheckAccessDeclContext() const { +#ifndef NDEBUG + // Suppress this check if any of the following hold: + // 1. this is the translation unit (and thus has no parent) + // 2. this is a template parameter (and thus doesn't belong to its context) + // 3. this is a non-type template parameter + // 4. the context is not a record + // 5. it's invalid + // 6. it's a C++0x static_assert. + if (isa<TranslationUnitDecl>(this) || + isa<TemplateTypeParmDecl>(this) || + isa<NonTypeTemplateParmDecl>(this) || + !isa<CXXRecordDecl>(getDeclContext()) || + isInvalidDecl() || + isa<StaticAssertDecl>(this) || + // FIXME: a ParmVarDecl can have ClassTemplateSpecialization + // as DeclContext (?). + isa<ParmVarDecl>(this) || + // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have + // AS_none as access specifier. + isa<CXXRecordDecl>(this)) + return; + + assert(Access != AS_none && + "Access specifier is AS_none inside a record decl"); +#endif +} + +DeclContext *Decl::getNonClosureContext() { + DeclContext *DC = getDeclContext(); + + // This is basically "while (DC->isClosure()) DC = DC->getParent();" + // except that it's significantly more efficient to cast to a known + // decl type and call getDeclContext() than to call getParent(). + do { + if (isa<BlockDecl>(DC)) { + DC = cast<BlockDecl>(DC)->getDeclContext(); + continue; + } + } while (false); + + assert(!DC->isClosure()); + return DC; +} + +//===----------------------------------------------------------------------===// +// DeclContext Implementation +//===----------------------------------------------------------------------===// + +bool DeclContext::classof(const Decl *D) { + switch (D->getKind()) { +#define DECL(NAME, BASE) +#define DECL_CONTEXT(NAME) case Decl::NAME: +#define DECL_CONTEXT_BASE(NAME) +#include "clang/AST/DeclNodes.inc" + return true; + default: +#define DECL(NAME, BASE) +#define DECL_CONTEXT_BASE(NAME) \ + if (D->getKind() >= Decl::first##NAME && \ + D->getKind() <= Decl::last##NAME) \ + return true; +#include "clang/AST/DeclNodes.inc" + return false; + } +} + +DeclContext::~DeclContext() { } + +/// \brief Find the parent context of this context that will be +/// used for unqualified name lookup. +/// +/// Generally, the parent lookup context is the semantic context. However, for +/// a friend function the parent lookup context is the lexical context, which +/// is the class in which the friend is declared. +DeclContext *DeclContext::getLookupParent() { + // FIXME: Find a better way to identify friends + if (isa<FunctionDecl>(this)) + if (getParent()->getRedeclContext()->isFileContext() && + getLexicalParent()->getRedeclContext()->isRecord()) + return getLexicalParent(); + + return getParent(); +} + +bool DeclContext::isInlineNamespace() const { + return isNamespace() && + cast<NamespaceDecl>(this)->isInline(); +} + +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; + + // Friend function declarations are dependent if their *lexical* + // context is dependent. + if (cast<Decl>(this)->getFriendObjectKind()) + return getLexicalParent()->isDependentContext(); + } + + return getParent() && getParent()->isDependentContext(); +} + +bool DeclContext::isTransparentContext() const { + if (DeclKind == Decl::Enum) + return !cast<EnumDecl>(this)->isScoped(); + else if (DeclKind == Decl::LinkageSpec) + return true; + + return false; +} + +bool DeclContext::isExternCContext() const { + const DeclContext *DC = this; + while (DC->DeclKind != Decl::TranslationUnit) { + if (DC->DeclKind == Decl::LinkageSpec) + return cast<LinkageSpecDecl>(DC)->getLanguage() + == LinkageSpecDecl::lang_c; + DC = DC->getParent(); + } + return false; +} + +bool DeclContext::Encloses(const DeclContext *DC) const { + if (getPrimaryContext() != this) + return getPrimaryContext()->Encloses(DC); + + for (; DC; DC = DC->getParent()) + if (DC->getPrimaryContext() == this) + return true; + 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::firstTag && DeclKind <= Decl::lastTag) { + // If this is a tag type that has a definition or is currently + // being defined, that definition is our primary context. + TagDecl *Tag = cast<TagDecl>(this); + assert(isa<TagType>(Tag->TypeForDecl) || + isa<InjectedClassNameType>(Tag->TypeForDecl)); + + if (TagDecl *Def = Tag->getDefinition()) + return Def; + + if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) { + const TagType *TagTy = cast<TagType>(Tag->TypeForDecl); + if (TagTy->isBeingDefined()) + // FIXME: is it necessarily being defined in the decl + // that owns the type? + return TagTy->getDecl(); + } + + return Tag; + } + + assert(DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction && + "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; + } +} + +std::pair<Decl *, Decl *> +DeclContext::BuildDeclChain(const llvm::SmallVectorImpl<Decl*> &Decls) { + // Build 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 = Decls[I]; + if (PrevDecl) + PrevDecl->NextDeclInContext = D; + else + FirstNewDecl = D; + + PrevDecl = D; + } + + return std::make_pair(FirstNewDecl, PrevDecl); +} + +/// \brief Load the declarations within this lexical storage from an +/// external source. +void +DeclContext::LoadLexicalDeclsFromExternalStorage() const { + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + assert(hasExternalLexicalStorage() && Source && "No external storage?"); + + // Notify that we have a DeclContext that is initializing. + ExternalASTSource::Deserializing ADeclContext(Source); + + llvm::SmallVector<Decl*, 64> Decls; + if (Source->FindExternalLexicalDecls(this, Decls)) + return; + + // There is no longer any lexical storage in this context + ExternalLexicalStorage = false; + + if (Decls.empty()) + return; + + // We may have already loaded just the fields of this record, in which case + // don't add the decls, just replace the FirstDecl/LastDecl chain. + if (const RecordDecl *RD = dyn_cast<RecordDecl>(this)) + if (RD->LoadedFieldsFromExternalStorage) { + llvm::tie(FirstDecl, LastDecl) = BuildDeclChain(Decls); + return; + } + + // Splice the newly-read declarations into the beginning of the list + // of declarations. + Decl *ExternalFirst, *ExternalLast; + llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls); + ExternalLast->NextDeclInContext = FirstDecl; + FirstDecl = ExternalFirst; + if (!LastDecl) + LastDecl = ExternalLast; +} + +DeclContext::lookup_result +ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name) { + ASTContext &Context = DC->getParentASTContext(); + StoredDeclsMap *Map; + if (!(Map = DC->LookupPtr)) + Map = DC->CreateStoredDeclsMap(Context); + + StoredDeclsList &List = (*Map)[Name]; + assert(List.isNull()); + (void) List; + + return DeclContext::lookup_result(); +} + +DeclContext::lookup_result +ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name, + llvm::SmallVectorImpl<NamedDecl*> &Decls) { + ASTContext &Context = DC->getParentASTContext();; + + StoredDeclsMap *Map; + if (!(Map = DC->LookupPtr)) + Map = DC->CreateStoredDeclsMap(Context); + + StoredDeclsList &List = (*Map)[Name]; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (List.isNull()) + List.setOnlyValue(Decls[I]); + else + List.AddSubsequentDecl(Decls[I]); + } + + return List.getLookupResult(); +} + +void ExternalASTSource::MaterializeVisibleDeclsForName(const DeclContext *DC, + DeclarationName Name, + llvm::SmallVectorImpl<NamedDecl*> &Decls) { + assert(DC->LookupPtr); + StoredDeclsMap &Map = *DC->LookupPtr; + + // If there's an entry in the table the visible decls for this name have + // already been deserialized. + if (Map.find(Name) == Map.end()) { + StoredDeclsList &List = Map[Name]; + for (unsigned I = 0, N = Decls.size(); I != N; ++I) { + if (List.isNull()) + List.setOnlyValue(Decls[I]); + else + List.AddSubsequentDecl(Decls[I]); + } + } +} + +DeclContext::decl_iterator DeclContext::noload_decls_begin() const { + return decl_iterator(FirstDecl); +} + +DeclContext::decl_iterator DeclContext::noload_decls_end() const { + return decl_iterator(); +} + +DeclContext::decl_iterator DeclContext::decls_begin() const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(); + + // FIXME: Check whether we need to load some declarations from + // external storage. + return decl_iterator(FirstDecl); +} + +DeclContext::decl_iterator DeclContext::decls_end() const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(); + + return decl_iterator(); +} + +bool DeclContext::decls_empty() const { + if (hasExternalLexicalStorage()) + LoadLexicalDeclsFromExternalStorage(); + + return !FirstDecl; +} + +void DeclContext::removeDecl(Decl *D) { + assert(D->getLexicalDeclContext() == this && + "decl being removed from non-lexical context"); + assert((D->NextDeclInContext || D == LastDecl) && + "decl is not in decls list"); + + // Remove D from the decl chain. This is O(n) but hopefully rare. + if (D == FirstDecl) { + if (D == LastDecl) + FirstDecl = LastDecl = 0; + else + FirstDecl = D->NextDeclInContext; + } else { + for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) { + assert(I && "decl not found in linked list"); + if (I->NextDeclInContext == D) { + I->NextDeclInContext = D->NextDeclInContext; + if (D == LastDecl) LastDecl = I; + break; + } + } + } + + // Mark that D is no longer in the decl chain. + D->NextDeclInContext = 0; + + // Remove D from the lookup table if necessary. + if (isa<NamedDecl>(D)) { + NamedDecl *ND = cast<NamedDecl>(D); + + StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; + if (!Map) return; + + StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); + assert(Pos != Map->end() && "no lookup entry for decl"); + Pos->second.remove(ND); + } +} + +void DeclContext::addHiddenDecl(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; + } + + // Notify a C++ record declaration that we've added a member, so it can + // update it's class-specific state. + if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) + Record->addedMember(D); +} + +void DeclContext::addDecl(Decl *D) { + addHiddenDecl(D); + + if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) + ND->getDeclContext()->makeDeclVisibleInContext(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(DeclContext *DCtx) { + for (; DCtx; DCtx = DCtx->getNextContext()) { + for (decl_iterator D = DCtx->decls_begin(), + DEnd = DCtx->decls_end(); + D != DEnd; ++D) { + // Insert this declaration into the lookup structure, but only + // if it's semantically in its decl context. During non-lazy + // lookup building, this is implicitly enforced by addDecl. + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) + if (D->getDeclContext() == DCtx) + makeDeclVisibleInContextImpl(ND); + + // Insert any forward-declared Objective-C interfaces into the lookup + // data structure. + if (ObjCClassDecl *Class = dyn_cast<ObjCClassDecl>(*D)) + for (ObjCClassDecl::iterator I = Class->begin(), IEnd = Class->end(); + I != IEnd; ++I) + makeDeclVisibleInContextImpl(I->getInterface()); + + // If this declaration is itself a transparent declaration context or + // inline namespace, add its members (recursively). + if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) + if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) + buildLookup(InnerCtx->getPrimaryContext()); + } + } +} + +DeclContext::lookup_result +DeclContext::lookup(DeclarationName Name) { + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) + return PrimaryContext->lookup(Name); + + if (hasExternalVisibleStorage()) { + // Check to see if we've already cached the lookup results. + if (LookupPtr) { + StoredDeclsMap::iterator I = LookupPtr->find(Name); + if (I != LookupPtr->end()) + return I->second.getLookupResult(); + } + + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + return Source->FindExternalVisibleDeclsByName(this, Name); + } + + /// 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(this); + + if (!LookupPtr) + return lookup_result(lookup_iterator(0), lookup_iterator(0)); + } + + StoredDeclsMap::iterator Pos = LookupPtr->find(Name); + if (Pos == LookupPtr->end()) + return lookup_result(lookup_iterator(0), lookup_iterator(0)); + return Pos->second.getLookupResult(); +} + +DeclContext::lookup_const_result +DeclContext::lookup(DeclarationName Name) const { + return const_cast<DeclContext*>(this)->lookup(Name); +} + +DeclContext *DeclContext::getRedeclContext() { + 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 = Ctx->getParent(); + return Ctx->getPrimaryContext(); +} + +bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { + // For non-file contexts, this is equivalent to Equals. + if (!isFileContext()) + return O->Equals(this); + + do { + if (O->Equals(this)) + return true; + + const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(O); + if (!NS || !NS->isInline()) + break; + O = NS->getParent(); + } while (O); + + return false; +} + +void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) { + // 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) || D->isTemplateParameter()) + return; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isFunctionTemplateSpecialization()) + return; + + DeclContext *PrimaryContext = getPrimaryContext(); + if (PrimaryContext != this) { + PrimaryContext->makeDeclVisibleInContext(D, Recoverable); + return; + } + + // If we already have a lookup data structure, perform the insertion + // into it. If we haven't deserialized externally stored decls, deserialize + // them so we can add the decl. Otherwise, be lazy and don't build that + // structure until someone asks for it. + if (LookupPtr || !Recoverable || hasExternalVisibleStorage()) + makeDeclVisibleInContextImpl(D); + + // If we are a transparent context or inline namespace, insert into our + // parent context, too. This operation is recursive. + if (isTransparentContext() || isInlineNamespace()) + getParent()->makeDeclVisibleInContext(D, Recoverable); + + Decl *DCAsDecl = cast<Decl>(this); + // Notify that a decl was made visible unless it's a Tag being defined. + if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) + if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) + L->AddedVisibleDecl(this, D); +} + +void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { + // Skip unnamed declarations. + if (!D->getDeclName()) + return; + + // Skip entities that can't be found by name lookup into a particular + // context. + if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || + D->isTemplateParameter()) + return; + + ASTContext *C = 0; + if (!LookupPtr) { + C = &getParentASTContext(); + CreateStoredDeclsMap(*C); + } + + // If there is an external AST source, load any declarations it knows about + // with this declaration's name. + // If the lookup table contains an entry about this name it means that we + // have already checked the external source. + if (ExternalASTSource *Source = getParentASTContext().getExternalSource()) + if (hasExternalVisibleStorage() && + LookupPtr->find(D->getDeclName()) == LookupPtr->end()) + Source->FindExternalVisibleDeclsByName(this, D->getDeclName()); + + // Insert this declaration into the map. + StoredDeclsList &DeclNameEntries = (*LookupPtr)[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(D)) + return; + + // Put this declaration into the appropriate slot. + DeclNameEntries.AddSubsequentDecl(D); +} + +void DeclContext::MaterializeVisibleDeclsFromExternalStorage() { + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + assert(hasExternalVisibleStorage() && Source && "No external storage?"); + + if (!LookupPtr) + CreateStoredDeclsMap(getParentASTContext()); + Source->MaterializeVisibleDecls(this); +} + +/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within +/// this context. +DeclContext::udir_iterator_range +DeclContext::getUsingDirectives() const { + lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); + return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), + reinterpret_cast<udir_iterator>(Result.second)); +} + +//===----------------------------------------------------------------------===// +// Creation and Destruction of StoredDeclsMaps. // +//===----------------------------------------------------------------------===// + +StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { + assert(!LookupPtr && "context already has a decls map"); + assert(getPrimaryContext() == this && + "creating decls map on non-primary context"); + + StoredDeclsMap *M; + bool Dependent = isDependentContext(); + if (Dependent) + M = new DependentStoredDeclsMap(); + else + M = new StoredDeclsMap(); + M->Previous = C.LastSDM; + C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent); + LookupPtr = M; + return M; +} + +void ASTContext::ReleaseDeclContextMaps() { + // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap + // pointer because the subclass doesn't add anything that needs to + // be deleted. + StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); +} + +void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { + while (Map) { + // Advance the iteration before we invalidate memory. + llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous; + + if (Dependent) + delete static_cast<DependentStoredDeclsMap*>(Map); + else + delete Map; + + Map = Next.getPointer(); + Dependent = Next.getInt(); + } +} + +DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, + DeclContext *Parent, + const PartialDiagnostic &PDiag) { + assert(Parent->isDependentContext() + && "cannot iterate dependent diagnostics of non-dependent context"); + Parent = Parent->getPrimaryContext(); + if (!Parent->LookupPtr) + Parent->CreateStoredDeclsMap(C); + + DependentStoredDeclsMap *Map + = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr); + + // Allocate the copy of the PartialDiagnostic via the ASTContext's + // BumpPtrAllocator, rather than the ASTContext itself. + PartialDiagnostic::Storage *DiagStorage = 0; + if (PDiag.hasStorage()) + DiagStorage = new (C) PartialDiagnostic::Storage; + + DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); + + // TODO: Maybe we shouldn't reverse the order during insertion. + DD->NextDiagnostic = Map->FirstDiagnostic; + Map->FirstDiagnostic = DD; + + return DD; +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp new file mode 100644 index 000000000000..08ac2a5be4d9 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclCXX.cpp @@ -0,0 +1,1693 @@ +//===--- 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/ASTMutationListener.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Expr.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallPtrSet.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// Decl Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) + : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), + UserDeclaredMoveConstructor(false), UserDeclaredCopyAssignment(false), + UserDeclaredMoveAssignment(false), UserDeclaredDestructor(false), + Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false), + Abstract(false), IsStandardLayout(true), HasNoNonEmptyBases(true), + HasPrivateFields(false), HasProtectedFields(false), HasPublicFields(false), + HasMutableFields(false), HasTrivialDefaultConstructor(true), + HasConstExprNonCopyMoveConstructor(false), HasTrivialCopyConstructor(true), + HasTrivialMoveConstructor(true), HasTrivialCopyAssignment(true), + HasTrivialMoveAssignment(true), HasTrivialDestructor(true), + HasNonLiteralTypeFieldsOrBases(false), ComputedVisibleConversions(false), + UserProvidedDefaultConstructor(false), DeclaredDefaultConstructor(false), + DeclaredCopyConstructor(false), DeclaredMoveConstructor(false), + DeclaredCopyAssignment(false), DeclaredMoveAssignment(false), + DeclaredDestructor(false), NumBases(0), NumVBases(0), Bases(), VBases(), + Definition(D), FirstFriend(0) { +} + +CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, CXXRecordDecl *PrevDecl) + : RecordDecl(K, TK, DC, StartLoc, IdLoc, Id, PrevDecl), + DefinitionData(PrevDecl ? PrevDecl->DefinitionData : 0), + TemplateOrInstantiation() { } + +CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + CXXRecordDecl* PrevDecl, + bool DelayTypeCreation) { + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, StartLoc, IdLoc, + Id, PrevDecl); + + // FIXME: DelayTypeCreation seems like such a hack + if (!DelayTypeCreation) + C.getTypeDeclType(R, PrevDecl); + return R; +} + +CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, EmptyShell Empty) { + return new (C) CXXRecordDecl(CXXRecord, TTK_Struct, 0, SourceLocation(), + SourceLocation(), 0, 0); +} + +void +CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, + unsigned NumBases) { + ASTContext &C = getASTContext(); + + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with [...] + // no base classes [...]. + data().Aggregate = false; + + if (!data().Bases.isOffset() && data().NumBases > 0) + C.Deallocate(data().getBases()); + + // The set of seen virtual base types. + llvm::SmallPtrSet<CanQualType, 8> SeenVBaseTypes; + + // The virtual bases of this class. + llvm::SmallVector<const CXXBaseSpecifier *, 8> VBases; + + data().Bases = new(C) CXXBaseSpecifier [NumBases]; + data().NumBases = NumBases; + for (unsigned i = 0; i < NumBases; ++i) { + data().getBases()[i] = *Bases[i]; + // Keep track of inherited vbases for this base class. + const CXXBaseSpecifier *Base = Bases[i]; + QualType BaseType = Base->getType(); + // Skip dependent types; we can't do any checking on them now. + if (BaseType->isDependentType()) + continue; + CXXRecordDecl *BaseClassDecl + = cast<CXXRecordDecl>(BaseType->getAs<RecordType>()->getDecl()); + + // C++ [dcl.init.aggr]p1: + // An aggregate is [...] a class with [...] no base classes [...]. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class... + data().PlainOldData = false; + + // A class with a non-empty base class is not empty. + // FIXME: Standard ref? + if (!BaseClassDecl->isEmpty()) { + if (!data().Empty) { + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- either has no non-static data members in the most derived + // class and at most one base class with non-static data members, + // or has no base classes with non-static data members, and + // If this is the second non-empty base, then neither of these two + // clauses can be true. + data().IsStandardLayout = false; + } + + data().Empty = false; + data().HasNoNonEmptyBases = false; + } + + // C++ [class.virtual]p1: + // A class that declares or inherits a virtual function is called a + // polymorphic class. + if (BaseClassDecl->isPolymorphic()) + data().Polymorphic = true; + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has no non-standard-layout base classes + if (!BaseClassDecl->isStandardLayout()) + data().IsStandardLayout = false; + + // Record if this base is the first non-literal field or base. + if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType()) + data().HasNonLiteralTypeFieldsOrBases = true; + + // Now go through all virtual bases of this base and add them. + for (CXXRecordDecl::base_class_iterator VBase = + BaseClassDecl->vbases_begin(), + E = BaseClassDecl->vbases_end(); VBase != E; ++VBase) { + // Add this base if it's not already in the list. + if (SeenVBaseTypes.insert(C.getCanonicalType(VBase->getType()))) + VBases.push_back(VBase); + } + + if (Base->isVirtual()) { + // Add this base if it's not already in the list. + if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) + VBases.push_back(Base); + + // C++0x [meta.unary.prop] is_empty: + // T is a class type, but not a union type, with ... no virtual base + // classes + data().Empty = false; + + // C++ [class.ctor]p5: + // A default constructor is trivial [...] if: + // -- its class has [...] no virtual bases + data().HasTrivialDefaultConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is neither + // user-provided nor deleted and if + // -- class X has no virtual functions and no virtual base classes, and + data().HasTrivialCopyConstructor = false; + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted and if + // -- class X has no virtual functions and no virtual base classes, and + data().HasTrivialCopyAssignment = false; + data().HasTrivialMoveAssignment = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has [...] no virtual base classes + data().IsStandardLayout = false; + } else { + // C++ [class.ctor]p5: + // A default constructor is trivial [...] if: + // -- all the direct base classes of its class have trivial default + // constructors. + if (!BaseClassDecl->hasTrivialDefaultConstructor()) + data().HasTrivialDefaultConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // [...] + // -- the constructor selected to copy/move each direct base class + // subobject is trivial, and + // FIXME: C++0x: We need to only consider the selected constructor + // instead of all of them. + if (!BaseClassDecl->hasTrivialCopyConstructor()) + data().HasTrivialCopyConstructor = false; + if (!BaseClassDecl->hasTrivialMoveConstructor()) + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // [...] + // -- the assignment operator selected to copy/move each direct base + // class subobject is trivial, and + // FIXME: C++0x: We need to only consider the selected operator instead + // of all of them. + if (!BaseClassDecl->hasTrivialCopyAssignment()) + data().HasTrivialCopyAssignment = false; + if (!BaseClassDecl->hasTrivialMoveAssignment()) + data().HasTrivialMoveAssignment = false; + } + + // C++ [class.ctor]p3: + // A destructor is trivial if all the direct base classes of its class + // have trivial destructors. + if (!BaseClassDecl->hasTrivialDestructor()) + data().HasTrivialDestructor = false; + + // Keep track of the presence of mutable fields. + if (BaseClassDecl->hasMutableFields()) + data().HasMutableFields = true; + } + + if (VBases.empty()) + return; + + // Create base specifier for any direct or indirect virtual bases. + data().VBases = new (C) CXXBaseSpecifier[VBases.size()]; + data().NumVBases = VBases.size(); + for (int I = 0, E = VBases.size(); I != E; ++I) { + TypeSourceInfo *VBaseTypeInfo = VBases[I]->getTypeSourceInfo(); + + // Skip dependent types; we can't do any checking on them now. + if (VBaseTypeInfo->getType()->isDependentType()) + continue; + + CXXRecordDecl *VBaseClassDecl = cast<CXXRecordDecl>( + VBaseTypeInfo->getType()->getAs<RecordType>()->getDecl()); + + data().getVBases()[I] = + CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, + VBaseClassDecl->getTagKind() == TTK_Class, + VBases[I]->getAccessSpecifier(), VBaseTypeInfo, + SourceLocation()); + } +} + +/// Callback function for CXXRecordDecl::forallBases that acknowledges +/// that it saw a base class. +static bool SawBase(const CXXRecordDecl *, void *) { + return true; +} + +bool CXXRecordDecl::hasAnyDependentBases() const { + if (!isDependentContext()) + return false; + + return !forallBases(SawBase, 0); +} + +bool CXXRecordDecl::hasConstCopyConstructor() const { + return getCopyConstructor(Qualifiers::Const) != 0; +} + +bool CXXRecordDecl::isTriviallyCopyable() const { + // C++0x [class]p5: + // A trivially copyable class is a class that: + // -- has no non-trivial copy constructors, + if (!hasTrivialCopyConstructor()) return false; + // -- has no non-trivial move constructors, + if (!hasTrivialMoveConstructor()) return false; + // -- has no non-trivial copy assignment operators, + if (!hasTrivialCopyAssignment()) return false; + // -- has no non-trivial move assignment operators, and + if (!hasTrivialMoveAssignment()) return false; + // -- has a trivial destructor. + if (!hasTrivialDestructor()) return false; + + return true; +} + +/// \brief Perform a simplistic form of overload resolution that only considers +/// cv-qualifiers on a single parameter, and return the best overload candidate +/// (if there is one). +static CXXMethodDecl * +GetBestOverloadCandidateSimple( + const llvm::SmallVectorImpl<std::pair<CXXMethodDecl *, Qualifiers> > &Cands) { + if (Cands.empty()) + return 0; + if (Cands.size() == 1) + return Cands[0].first; + + unsigned Best = 0, N = Cands.size(); + for (unsigned I = 1; I != N; ++I) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) + Best = I; + + for (unsigned I = 1; I != N; ++I) + if (Cands[Best].second.compatiblyIncludes(Cands[I].second)) + return 0; + + return Cands[Best].first; +} + +CXXConstructorDecl *CXXRecordDecl::getCopyConstructor(unsigned TypeQuals) const{ + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); + DeclarationName ConstructorName + = Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(ClassType)); + unsigned FoundTQs; + llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; + DeclContext::lookup_const_iterator Con, ConEnd; + for (llvm::tie(Con, ConEnd) = this->lookup(ConstructorName); + Con != ConEnd; ++Con) { + // C++ [class.copy]p2: + // A non-template constructor for class X is a copy constructor if [...] + if (isa<FunctionTemplateDecl>(*Con)) + continue; + + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(*Con); + if (Constructor->isCopyConstructor(FoundTQs)) { + if (((TypeQuals & Qualifiers::Const) == (FoundTQs & Qualifiers::Const)) || + (!(TypeQuals & Qualifiers::Const) && (FoundTQs & Qualifiers::Const))) + Found.push_back(std::make_pair( + const_cast<CXXConstructorDecl *>(Constructor), + Qualifiers::fromCVRMask(FoundTQs))); + } + } + + return cast_or_null<CXXConstructorDecl>( + GetBestOverloadCandidateSimple(Found)); +} + +CXXConstructorDecl *CXXRecordDecl::getMoveConstructor() const { + for (ctor_iterator I = ctor_begin(), E = ctor_end(); I != E; ++I) + if (I->isMoveConstructor()) + return *I; + + return 0; +} + +CXXMethodDecl *CXXRecordDecl::getCopyAssignmentOperator(bool ArgIsConst) const { + ASTContext &Context = getASTContext(); + QualType Class = Context.getTypeDeclType(const_cast<CXXRecordDecl *>(this)); + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Equal); + + llvm::SmallVector<std::pair<CXXMethodDecl *, Qualifiers>, 4> Found; + DeclContext::lookup_const_iterator Op, OpEnd; + for (llvm::tie(Op, OpEnd) = this->lookup(Name); 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 = dyn_cast<CXXMethodDecl>(*Op); + if (!Method || Method->isStatic() || Method->getPrimaryTemplate()) + continue; + + const FunctionProtoType *FnType + = Method->getType()->getAs<FunctionProtoType>(); + 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; + + QualType ArgType = FnType->getArgType(0); + Qualifiers Quals; + if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) { + ArgType = Ref->getPointeeType(); + // If we have a const argument and we have a reference to a non-const, + // this function does not match. + if (ArgIsConst && !ArgType.isConstQualified()) + continue; + + Quals = ArgType.getQualifiers(); + } else { + // By-value copy-assignment operators are treated like const X& + // copy-assignment operators. + Quals = Qualifiers::fromCVRMask(Qualifiers::Const); + } + + if (!Context.hasSameUnqualifiedType(ArgType, Class)) + continue; + + // Save this copy-assignment operator. It might be "the one". + Found.push_back(std::make_pair(const_cast<CXXMethodDecl *>(Method), Quals)); + } + + // Use a simplistic form of overload resolution to find the candidate. + return GetBestOverloadCandidateSimple(Found); +} + +CXXMethodDecl *CXXRecordDecl::getMoveAssignmentOperator() const { + for (method_iterator I = method_begin(), E = method_end(); I != E; ++I) + if (I->isMoveAssignmentOperator()) + return *I; + + return 0; +} + +void CXXRecordDecl::markedVirtualFunctionPure() { + // C++ [class.abstract]p2: + // A class is abstract if it has at least one pure virtual function. + data().Abstract = true; +} + +void CXXRecordDecl::addedMember(Decl *D) { + // Ignore friends and invalid declarations. + if (D->getFriendObjectKind() || D->isInvalidDecl()) + return; + + FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D); + if (FunTmpl) + D = FunTmpl->getTemplatedDecl(); + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isVirtual()) { + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class with [...] no virtual functions. + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class... + data().PlainOldData = false; + + // Virtual functions make the class non-empty. + // FIXME: Standard ref? + data().Empty = false; + + // C++ [class.virtual]p1: + // A class that declares or inherits a virtual function is called a + // polymorphic class. + data().Polymorphic = true; + + // C++0x [class.ctor]p5 + // A default constructor is trivial [...] if: + // -- its class has no virtual functions [...] + data().HasTrivialDefaultConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // -- class X has no virtual functions [...] + data().HasTrivialCopyConstructor = false; + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // -- class X has no virtual functions [...] + data().HasTrivialCopyAssignment = false; + data().HasTrivialMoveAssignment = false; + // FIXME: Destructor? + + // C++0x [class]p7: + // A standard-layout class is a class that: [...] + // -- has no virtual functions + data().IsStandardLayout = false; + } + } + + if (D->isImplicit()) { + // Notify that an implicit member was added after the definition + // was completed. + if (!isBeingDefined()) + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXImplicitMember(data().Definition, D); + + // If this is a special member function, note that it was added and then + // return early. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + if (Constructor->isDefaultConstructor()) + data().DeclaredDefaultConstructor = true; + else if (Constructor->isCopyConstructor()) + data().DeclaredCopyConstructor = true; + else if (Constructor->isMoveConstructor()) + data().DeclaredMoveConstructor = true; + else + goto NotASpecialMember; + return; + } else if (isa<CXXDestructorDecl>(D)) { + data().DeclaredDestructor = true; + return; + } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isCopyAssignmentOperator()) + data().DeclaredCopyAssignment = true; + else if (Method->isMoveAssignmentOperator()) + data().DeclaredMoveAssignment = true; + else + goto NotASpecialMember; + return; + } + +NotASpecialMember:; + // Any other implicit declarations are handled like normal declarations. + } + + // Handle (user-declared) constructors. + if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { + // Note that we have a user-declared constructor. + data().UserDeclaredConstructor = true; + + // FIXME: Under C++0x, /only/ special member functions may be user-provided. + // This is probably a defect. + bool UserProvided = false; + + // C++0x [class.ctor]p5: + // A default constructor is trivial if it is not user-provided [...] + if (Constructor->isDefaultConstructor()) { + data().DeclaredDefaultConstructor = true; + if (Constructor->isUserProvided()) { + data().HasTrivialDefaultConstructor = false; + data().UserProvidedDefaultConstructor = true; + UserProvided = true; + } + } + + // Note when we have a user-declared copy or move constructor, which will + // suppress the implicit declaration of those constructors. + if (!FunTmpl) { + if (Constructor->isCopyConstructor()) { + data().UserDeclaredCopyConstructor = true; + data().DeclaredCopyConstructor = true; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is not + // user-provided [...] + if (Constructor->isUserProvided()) { + data().HasTrivialCopyConstructor = false; + UserProvided = true; + } + } else if (Constructor->isMoveConstructor()) { + data().UserDeclaredMoveConstructor = true; + data().DeclaredMoveConstructor = true; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if it is not + // user-provided [...] + if (Constructor->isUserProvided()) { + data().HasTrivialMoveConstructor = false; + UserProvided = true; + } + } + } + if (Constructor->isConstExpr() && + !Constructor->isCopyOrMoveConstructor()) { + // Record if we see any constexpr constructors which are niether copy + // nor move constructors. + data().HasConstExprNonCopyMoveConstructor = true; + } + + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-declared + // constructors [...]. + // C++0x [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-provided + // constructors [...]. + if (!getASTContext().getLangOptions().CPlusPlus0x || UserProvided) + data().Aggregate = false; + + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + // Since the POD bit is meant to be C++03 POD-ness, clear it even if the + // type is technically an aggregate in C++0x since it wouldn't be in 03. + data().PlainOldData = false; + + return; + } + + // Handle (user-declared) destructors. + if (CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(D)) { + data().DeclaredDestructor = true; + data().UserDeclaredDestructor = true; + + // C++ [class]p4: + // A POD-struct is an aggregate class that has [...] no user-defined + // destructor. + // This bit is the C++03 POD bit, not the 0x one. + data().PlainOldData = false; + + // C++0x [class.dtor]p5: + // A destructor is trivial if it is not user-provided and [...] + if (DD->isUserProvided()) + data().HasTrivialDestructor = false; + + return; + } + + // Handle (user-declared) member functions. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { + if (Method->isCopyAssignmentOperator()) { + // C++ [class]p4: + // A POD-struct is an aggregate class that [...] has no user-defined + // copy assignment operator [...]. + // This is the C++03 bit only. + data().PlainOldData = false; + + // This is a copy assignment operator. + + // Suppress the implicit declaration of a copy constructor. + data().UserDeclaredCopyAssignment = true; + data().DeclaredCopyAssignment = true; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + if (Method->isUserProvided()) + data().HasTrivialCopyAssignment = false; + + return; + } + + if (Method->isMoveAssignmentOperator()) { + // This is an extension in C++03 mode, but we'll keep consistency by + // taking a move assignment operator to induce non-POD-ness + data().PlainOldData = false; + + // This is a move assignment operator. + data().UserDeclaredMoveAssignment = true; + data().DeclaredMoveAssignment = true; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if it is + // neither user-provided nor deleted [...] + if (Method->isUserProvided()) + data().HasTrivialMoveAssignment = false; + } + + // Keep the list of conversion functions up-to-date. + if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { + // We don't record specializations. + if (Conversion->getPrimaryTemplate()) + return; + + // FIXME: We intentionally don't use the decl's access here because it + // hasn't been set yet. That's really just a misdesign in Sema. + + if (FunTmpl) { + if (FunTmpl->getPreviousDeclaration()) + data().Conversions.replace(FunTmpl->getPreviousDeclaration(), + FunTmpl); + else + data().Conversions.addDecl(FunTmpl); + } else { + if (Conversion->getPreviousDeclaration()) + data().Conversions.replace(Conversion->getPreviousDeclaration(), + Conversion); + else + data().Conversions.addDecl(Conversion); + } + } + + return; + } + + // Handle non-static data members. + if (FieldDecl *Field = dyn_cast<FieldDecl>(D)) { + // C++ [dcl.init.aggr]p1: + // An aggregate is an array or a class (clause 9) with [...] no + // private or protected non-static data members (clause 11). + // + // A POD must be an aggregate. + if (D->getAccess() == AS_private || D->getAccess() == AS_protected) { + data().Aggregate = false; + data().PlainOldData = false; + } + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has the same access control for all non-static data members, + switch (D->getAccess()) { + case AS_private: data().HasPrivateFields = true; break; + case AS_protected: data().HasProtectedFields = true; break; + case AS_public: data().HasPublicFields = true; break; + case AS_none: assert(0 && "Invalid access specifier"); + }; + if ((data().HasPrivateFields + data().HasProtectedFields + + data().HasPublicFields) > 1) + data().IsStandardLayout = false; + + // Keep track of the presence of mutable fields. + if (Field->isMutable()) + data().HasMutableFields = true; + + // C++0x [class]p9: + // A POD struct is a class that is both a trivial class and a + // standard-layout class, and has no non-static data members of type + // non-POD struct, non-POD union (or array of such types). + ASTContext &Context = getASTContext(); + QualType T = Context.getBaseElementType(Field->getType()); + if (!T->isPODType()) + data().PlainOldData = false; + if (T->isReferenceType()) { + data().HasTrivialDefaultConstructor = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: + // -- has no non-static data members of type [...] reference, + data().IsStandardLayout = false; + } + + // Record if this field is the first non-literal field or base. + if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType()) + data().HasNonLiteralTypeFieldsOrBases = true; + + if (Field->hasInClassInitializer()) { + // C++0x [class]p5: + // A default constructor is trivial if [...] no non-static data member + // of its class has a brace-or-equal-initializer. + data().HasTrivialDefaultConstructor = false; + + // C++0x [dcl.init.aggr]p1: + // An aggregate is a [...] class with [...] no + // brace-or-equal-initializers for non-static data members. + data().Aggregate = false; + + // C++0x [class]p10: + // A POD struct is [...] a trivial class. + data().PlainOldData = false; + } + + if (const RecordType *RecordTy = T->getAs<RecordType>()) { + CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl()); + if (FieldRec->getDefinition()) { + // C++0x [class.ctor]p5: + // A defulat constructor is trivial [...] if: + // -- for all the non-static data members of its class that are of + // class type (or array thereof), each such class has a trivial + // default constructor. + if (!FieldRec->hasTrivialDefaultConstructor()) + data().HasTrivialDefaultConstructor = false; + + // C++0x [class.copy]p13: + // A copy/move constructor for class X is trivial if [...] + // [...] + // -- for each non-static data member of X that is of class type (or + // an array thereof), the constructor selected to copy/move that + // member is trivial; + // FIXME: C++0x: We don't correctly model 'selected' constructors. + if (!FieldRec->hasTrivialCopyConstructor()) + data().HasTrivialCopyConstructor = false; + if (!FieldRec->hasTrivialMoveConstructor()) + data().HasTrivialMoveConstructor = false; + + // C++0x [class.copy]p27: + // A copy/move assignment operator for class X is trivial if [...] + // [...] + // -- for each non-static data member of X that is of class type (or + // an array thereof), the assignment operator selected to + // copy/move that member is trivial; + // FIXME: C++0x: We don't correctly model 'selected' operators. + if (!FieldRec->hasTrivialCopyAssignment()) + data().HasTrivialCopyAssignment = false; + if (!FieldRec->hasTrivialMoveAssignment()) + data().HasTrivialMoveAssignment = false; + + if (!FieldRec->hasTrivialDestructor()) + data().HasTrivialDestructor = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: + // -- has no non-static data members of type non-standard-layout + // class (or array of such types) [...] + if (!FieldRec->isStandardLayout()) + data().IsStandardLayout = false; + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- has no base classes of the same type as the first non-static + // data member. + // We don't want to expend bits in the state of the record decl + // tracking whether this is the first non-static data member so we + // cheat a bit and use some of the existing state: the empty bit. + // Virtual bases and virtual methods make a class non-empty, but they + // also make it non-standard-layout so we needn't check here. + // A non-empty base class may leave the class standard-layout, but not + // if we have arrived here, and have at least on non-static data + // member. If IsStandardLayout remains true, then the first non-static + // data member must come through here with Empty still true, and Empty + // will subsequently be set to false below. + if (data().IsStandardLayout && data().Empty) { + for (CXXRecordDecl::base_class_const_iterator BI = bases_begin(), + BE = bases_end(); + BI != BE; ++BI) { + if (Context.hasSameUnqualifiedType(BI->getType(), T)) { + data().IsStandardLayout = false; + break; + } + } + } + + // Keep track of the presence of mutable fields. + if (FieldRec->hasMutableFields()) + data().HasMutableFields = true; + } + } + + // C++0x [class]p7: + // A standard-layout class is a class that: + // [...] + // -- either has no non-static data members in the most derived + // class and at most one base class with non-static data members, + // or has no base classes with non-static data members, and + // At this point we know that we have a non-static data member, so the last + // clause holds. + if (!data().HasNoNonEmptyBases) + data().IsStandardLayout = false; + + // If this is not a zero-length bit-field, then the class is not empty. + if (data().Empty) { + if (!Field->getBitWidth()) + data().Empty = false; + else if (!Field->getBitWidth()->isTypeDependent() && + !Field->getBitWidth()->isValueDependent()) { + llvm::APSInt Bits; + if (Field->getBitWidth()->isIntegerConstantExpr(Bits, Context)) + if (!!Bits) + data().Empty = false; + } + } + } + + // Handle using declarations of conversion functions. + if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(D)) + if (Shadow->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName) + data().Conversions.addDecl(Shadow, Shadow->getAccess()); +} + +static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { + QualType T; + if (isa<UsingShadowDecl>(Conv)) + Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl(); + if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv)) + T = ConvTemp->getTemplatedDecl()->getResultType(); + else + T = cast<CXXConversionDecl>(Conv)->getConversionType(); + return Context.getCanonicalType(T); +} + +/// Collect the visible conversions of a base class. +/// +/// \param Base a base class of the class we're considering +/// \param InVirtual whether this base class is a virtual base (or a base +/// of a virtual base) +/// \param Access the access along the inheritance path to this base +/// \param ParentHiddenTypes the conversions provided by the inheritors +/// of this base +/// \param Output the set to which to add conversions from non-virtual bases +/// \param VOutput the set to which to add conversions from virtual bases +/// \param HiddenVBaseCs the set of conversions which were hidden in a +/// virtual base along some inheritance path +static void CollectVisibleConversions(ASTContext &Context, + CXXRecordDecl *Record, + bool InVirtual, + AccessSpecifier Access, + const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, + UnresolvedSetImpl &Output, + UnresolvedSetImpl &VOutput, + llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { + // The set of types which have conversions in this class or its + // subclasses. As an optimization, we don't copy the derived set + // unless it might change. + const llvm::SmallPtrSet<CanQualType, 8> *HiddenTypes = &ParentHiddenTypes; + llvm::SmallPtrSet<CanQualType, 8> HiddenTypesBuffer; + + // Collect the direct conversions and figure out which conversions + // will be hidden in the subclasses. + UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); + if (!Cs.empty()) { + HiddenTypesBuffer = ParentHiddenTypes; + HiddenTypes = &HiddenTypesBuffer; + + for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) { + bool Hidden = + !HiddenTypesBuffer.insert(GetConversionType(Context, I.getDecl())); + + // If this conversion is hidden and we're in a virtual base, + // remember that it's hidden along some inheritance path. + if (Hidden && InVirtual) + HiddenVBaseCs.insert(cast<NamedDecl>(I.getDecl()->getCanonicalDecl())); + + // If this conversion isn't hidden, add it to the appropriate output. + else if (!Hidden) { + AccessSpecifier IAccess + = CXXRecordDecl::MergeAccess(Access, I.getAccess()); + + if (InVirtual) + VOutput.addDecl(I.getDecl(), IAccess); + else + Output.addDecl(I.getDecl(), IAccess); + } + } + } + + // Collect information recursively from any base classes. + for (CXXRecordDecl::base_class_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *RT = I->getType()->getAs<RecordType>(); + if (!RT) continue; + + AccessSpecifier BaseAccess + = CXXRecordDecl::MergeAccess(Access, I->getAccessSpecifier()); + bool BaseInVirtual = InVirtual || I->isVirtual(); + + CXXRecordDecl *Base = cast<CXXRecordDecl>(RT->getDecl()); + CollectVisibleConversions(Context, Base, BaseInVirtual, BaseAccess, + *HiddenTypes, Output, VOutput, HiddenVBaseCs); + } +} + +/// Collect the visible conversions of a class. +/// +/// This would be extremely straightforward if it weren't for virtual +/// bases. It might be worth special-casing that, really. +static void CollectVisibleConversions(ASTContext &Context, + CXXRecordDecl *Record, + UnresolvedSetImpl &Output) { + // The collection of all conversions in virtual bases that we've + // found. These will be added to the output as long as they don't + // appear in the hidden-conversions set. + UnresolvedSet<8> VBaseCs; + + // The set of conversions in virtual bases that we've determined to + // be hidden. + llvm::SmallPtrSet<NamedDecl*, 8> HiddenVBaseCs; + + // The set of types hidden by classes derived from this one. + llvm::SmallPtrSet<CanQualType, 8> HiddenTypes; + + // Go ahead and collect the direct conversions and add them to the + // hidden-types set. + UnresolvedSetImpl &Cs = *Record->getConversionFunctions(); + Output.append(Cs.begin(), Cs.end()); + for (UnresolvedSetIterator I = Cs.begin(), E = Cs.end(); I != E; ++I) + HiddenTypes.insert(GetConversionType(Context, I.getDecl())); + + // Recursively collect conversions from base classes. + for (CXXRecordDecl::base_class_iterator + I = Record->bases_begin(), E = Record->bases_end(); I != E; ++I) { + const RecordType *RT = I->getType()->getAs<RecordType>(); + if (!RT) continue; + + CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), + I->isVirtual(), I->getAccessSpecifier(), + HiddenTypes, Output, VBaseCs, HiddenVBaseCs); + } + + // Add any unhidden conversions provided by virtual bases. + for (UnresolvedSetIterator I = VBaseCs.begin(), E = VBaseCs.end(); + I != E; ++I) { + if (!HiddenVBaseCs.count(cast<NamedDecl>(I.getDecl()->getCanonicalDecl()))) + Output.addDecl(I.getDecl(), I.getAccess()); + } +} + +/// getVisibleConversionFunctions - get all conversion functions visible +/// in current class; including conversion function templates. +const UnresolvedSetImpl *CXXRecordDecl::getVisibleConversionFunctions() { + // If root class, all conversions are visible. + if (bases_begin() == bases_end()) + return &data().Conversions; + // If visible conversion list is already evaluated, return it. + if (data().ComputedVisibleConversions) + return &data().VisibleConversions; + CollectVisibleConversions(getASTContext(), this, data().VisibleConversions); + data().ComputedVisibleConversions = true; + return &data().VisibleConversions; +} + +void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { + // This operation is O(N) but extremely rare. Sema only uses it to + // remove UsingShadowDecls in a class that were followed by a direct + // declaration, e.g.: + // class A : B { + // using B::operator int; + // operator int(); + // }; + // This is uncommon by itself and even more uncommon in conjunction + // with sufficiently large numbers of directly-declared conversions + // that asymptotic behavior matters. + + UnresolvedSetImpl &Convs = *getConversionFunctions(); + for (unsigned I = 0, E = Convs.size(); I != E; ++I) { + if (Convs[I].getDecl() == ConvDecl) { + Convs.erase(I); + assert(std::find(Convs.begin(), Convs.end(), ConvDecl) == Convs.end() + && "conversion was found multiple times in unresolved set"); + return; + } + } + + llvm_unreachable("conversion not found in set!"); +} + +CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() const { + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return cast<CXXRecordDecl>(MSInfo->getInstantiatedFrom()); + + return 0; +} + +MemberSpecializationInfo *CXXRecordDecl::getMemberSpecializationInfo() const { + return TemplateOrInstantiation.dyn_cast<MemberSpecializationInfo *>(); +} + +void +CXXRecordDecl::setInstantiationOfMemberClass(CXXRecordDecl *RD, + TemplateSpecializationKind TSK) { + assert(TemplateOrInstantiation.isNull() && + "Previous template or instantiation?"); + assert(!isa<ClassTemplateSpecializationDecl>(this)); + TemplateOrInstantiation + = new (getASTContext()) MemberSpecializationInfo(RD, TSK); +} + +TemplateSpecializationKind CXXRecordDecl::getTemplateSpecializationKind() const{ + if (const ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) + return Spec->getSpecializationKind(); + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) + return MSInfo->getTemplateSpecializationKind(); + + return TSK_Undeclared; +} + +void +CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(this)) { + Spec->setSpecializationKind(TSK); + return; + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + MSInfo->setTemplateSpecializationKind(TSK); + return; + } + + assert(false && "Not a class template or member class specialization"); +} + +CXXDestructorDecl *CXXRecordDecl::getDestructor() const { + ASTContext &Context = getASTContext(); + QualType ClassType = Context.getTypeDeclType(this); + + DeclarationName Name + = Context.DeclarationNames.getCXXDestructorName( + Context.getCanonicalType(ClassType)); + + DeclContext::lookup_const_iterator I, E; + llvm::tie(I, E) = lookup(Name); + if (I == E) + return 0; + + CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I); + return Dtor; +} + +void CXXRecordDecl::completeDefinition() { + completeDefinition(0); +} + +void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { + RecordDecl::completeDefinition(); + + // If the class may be abstract (but hasn't been marked as such), check for + // any pure final overriders. + if (mayBeAbstract()) { + CXXFinalOverriderMap MyFinalOverriders; + if (!FinalOverriders) { + getFinalOverriders(MyFinalOverriders); + FinalOverriders = &MyFinalOverriders; + } + + bool Done = false; + for (CXXFinalOverriderMap::iterator M = FinalOverriders->begin(), + MEnd = FinalOverriders->end(); + M != MEnd && !Done; ++M) { + for (OverridingMethods::iterator SO = M->second.begin(), + SOEnd = M->second.end(); + SO != SOEnd && !Done; ++SO) { + assert(SO->second.size() > 0 && + "All virtual functions have overridding virtual functions"); + + // C++ [class.abstract]p4: + // A class is abstract if it contains or inherits at least one + // pure virtual function for which the final overrider is pure + // virtual. + if (SO->second.front().Method->isPure()) { + data().Abstract = true; + Done = true; + break; + } + } + } + } + + // Set access bits correctly on the directly-declared conversions. + for (UnresolvedSetIterator I = data().Conversions.begin(), + E = data().Conversions.end(); + I != E; ++I) + data().Conversions.setAccess(I, (*I)->getAccess()); +} + +bool CXXRecordDecl::mayBeAbstract() const { + if (data().Abstract || isInvalidDecl() || !data().Polymorphic || + isDependentContext()) + return false; + + for (CXXRecordDecl::base_class_const_iterator B = bases_begin(), + BEnd = bases_end(); + B != BEnd; ++B) { + CXXRecordDecl *BaseDecl + = cast<CXXRecordDecl>(B->getType()->getAs<RecordType>()->getDecl()); + if (BaseDecl->isAbstract()) + return true; + } + + return false; +} + +CXXMethodDecl * +CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isStatic, StorageClass SCAsWritten, bool isInline, + SourceLocation EndLocation) { + return new (C) CXXMethodDecl(CXXMethod, RD, StartLoc, NameInfo, T, TInfo, + isStatic, SCAsWritten, isInline, EndLocation); +} + +bool CXXMethodDecl::isUsualDeallocationFunction() const { + if (getOverloadedOperator() != OO_Delete && + getOverloadedOperator() != OO_Array_Delete) + return false; + + // C++ [basic.stc.dynamic.deallocation]p2: + // A template instance is never a usual deallocation function, + // regardless of its signature. + if (getPrimaryTemplate()) + return false; + + // C++ [basic.stc.dynamic.deallocation]p2: + // If a class T has a member deallocation function named operator delete + // with exactly one parameter, then that function is a usual (non-placement) + // deallocation function. [...] + if (getNumParams() == 1) + return true; + + // C++ [basic.stc.dynamic.deallocation]p2: + // [...] If class T does not declare such an operator delete but does + // declare a member deallocation function named operator delete with + // exactly two parameters, the second of which has type std::size_t (18.1), + // then this function is a usual deallocation function. + ASTContext &Context = getASTContext(); + if (getNumParams() != 2 || + !Context.hasSameUnqualifiedType(getParamDecl(1)->getType(), + Context.getSizeType())) + return false; + + // This function is a usual deallocation function if there are no + // single-parameter deallocation functions of the same kind. + for (DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); + R.first != R.second; ++R.first) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*R.first)) + if (FD->getNumParams() == 1) + return false; + } + + return true; +} + +bool CXXMethodDecl::isCopyAssignmentOperator() const { + // C++0x [class.copy]p17: + // A user-declared copy assignment operator X::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&. + if (/*operator=*/getOverloadedOperator() != OO_Equal || + /*non-static*/ isStatic() || + /*non-template*/getPrimaryTemplate() || getDescribedFunctionTemplate()) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (const LValueReferenceType *Ref = ParamType->getAs<LValueReferenceType>()) + ParamType = Ref->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + +bool CXXMethodDecl::isMoveAssignmentOperator() const { + // C++0x [class.copy]p19: + // A user-declared move assignment operator X::operator= is a non-static + // non-template member function of class X with exactly one parameter of type + // X&&, const X&&, volatile X&&, or const volatile X&&. + if (getOverloadedOperator() != OO_Equal || isStatic() || + getPrimaryTemplate() || getDescribedFunctionTemplate()) + return false; + + QualType ParamType = getParamDecl(0)->getType(); + if (!isa<RValueReferenceType>(ParamType)) + return false; + ParamType = ParamType->getPointeeType(); + + ASTContext &Context = getASTContext(); + QualType ClassType + = Context.getCanonicalType(Context.getTypeDeclType(getParent())); + return Context.hasSameUnqualifiedType(ClassType, ParamType); +} + +void CXXMethodDecl::addOverriddenMethod(const CXXMethodDecl *MD) { + assert(MD->isCanonicalDecl() && "Method is not canonical!"); + assert(!MD->getParent()->isDependentContext() && + "Can't add an overridden method to a class template!"); + + getASTContext().addOverriddenMethod(this, MD); +} + +CXXMethodDecl::method_iterator CXXMethodDecl::begin_overridden_methods() const { + return getASTContext().overridden_methods_begin(this); +} + +CXXMethodDecl::method_iterator CXXMethodDecl::end_overridden_methods() const { + return getASTContext().overridden_methods_end(this); +} + +unsigned CXXMethodDecl::size_overridden_methods() const { + return getASTContext().overridden_methods_size(this); +} + +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.getTypeDeclType(getParent()); + ClassTy = C.getQualifiedType(ClassTy, + Qualifiers::fromCVRMask(getTypeQualifiers())); + return C.getPointerType(ClassTy); +} + +bool CXXMethodDecl::hasInlineBody() const { + // If this function is a template instantiation, look at the template from + // which it was instantiated. + const FunctionDecl *CheckFn = getTemplateInstantiationPattern(); + if (!CheckFn) + CheckFn = this; + + const FunctionDecl *fn; + return CheckFn->hasBody(fn) && !fn->isOutOfLine(); +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + TypeSourceInfo *TInfo, bool IsVirtual, + SourceLocation L, Expr *Init, + SourceLocation R, + SourceLocation EllipsisLoc) + : Initializee(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false), + SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + IndirectFieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + SourceLocation D, SourceLocation L, + CXXConstructorDecl *Target, Expr *Init, + SourceLocation R) + : Initializee(Target), MemberOrEllipsisLocation(D), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(0) +{ +} + +CXXCtorInitializer::CXXCtorInitializer(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) + : Initializee(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init), + LParenLoc(L), RParenLoc(R), IsVirtual(false), + IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices) +{ + VarDecl **MyIndices = reinterpret_cast<VarDecl **> (this + 1); + memcpy(MyIndices, Indices, NumIndices * sizeof(VarDecl *)); +} + +CXXCtorInitializer *CXXCtorInitializer::Create(ASTContext &Context, + FieldDecl *Member, + SourceLocation MemberLoc, + SourceLocation L, Expr *Init, + SourceLocation R, + VarDecl **Indices, + unsigned NumIndices) { + void *Mem = Context.Allocate(sizeof(CXXCtorInitializer) + + sizeof(VarDecl *) * NumIndices, + llvm::alignOf<CXXCtorInitializer>()); + return new (Mem) CXXCtorInitializer(Context, Member, MemberLoc, L, Init, R, + Indices, NumIndices); +} + +TypeLoc CXXCtorInitializer::getBaseClassLoc() const { + if (isBaseInitializer()) + return Initializee.get<TypeSourceInfo*>()->getTypeLoc(); + else + return TypeLoc(); +} + +const Type *CXXCtorInitializer::getBaseClass() const { + if (isBaseInitializer()) + return Initializee.get<TypeSourceInfo*>()->getType().getTypePtr(); + else + return 0; +} + +SourceLocation CXXCtorInitializer::getSourceLocation() const { + if (isAnyMemberInitializer() || isDelegatingInitializer()) + return getMemberLocation(); + + if (isInClassMemberInitializer()) + return getAnyMember()->getLocation(); + + return getBaseClassLoc().getLocalSourceRange().getBegin(); +} + +SourceRange CXXCtorInitializer::getSourceRange() const { + if (isInClassMemberInitializer()) { + FieldDecl *D = getAnyMember(); + if (Expr *I = D->getInClassInitializer()) + return I->getSourceRange(); + return SourceRange(); + } + + return SourceRange(getSourceLocation(), getRParenLoc()); +} + +CXXConstructorDecl * +CXXConstructorDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXConstructorDecl(0, SourceLocation(), DeclarationNameInfo(), + QualType(), 0, false, false, false); +} + +CXXConstructorDecl * +CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isExplicit, + bool isInline, + bool isImplicitlyDeclared) { + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXConstructorName && + "Name must refer to a constructor"); + return new (C) CXXConstructorDecl(RD, StartLoc, NameInfo, T, TInfo, + 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)->hasDefaultArg()); +} + +bool +CXXConstructorDecl::isCopyConstructor(unsigned &TypeQuals) const { + return isCopyOrMoveConstructor(TypeQuals) && + getParamDecl(0)->getType()->isLValueReferenceType(); +} + +bool CXXConstructorDecl::isMoveConstructor(unsigned &TypeQuals) const { + return isCopyOrMoveConstructor(TypeQuals) && + getParamDecl(0)->getType()->isRValueReferenceType(); +} + +/// \brief Determine whether this is a copy or move constructor. +bool CXXConstructorDecl::isCopyOrMoveConstructor(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). + // C++0x [class.copy]p3: + // A non-template constructor for class X is a move 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. + if ((getNumParams() < 1) || + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() != 0) || + (getDescribedFunctionTemplate() != 0)) + return false; + + const ParmVarDecl *Param = getParamDecl(0); + + // Do we have a reference type? + const ReferenceType *ParamRefType = Param->getType()->getAs<ReferenceType>(); + if (!ParamRefType) + return false; + + // Is it a reference to our class type? + ASTContext &Context = getASTContext(); + + CanQualType PointeeType + = Context.getCanonicalType(ParamRefType->getPointeeType()); + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); + if (PointeeType.getUnqualifiedType() != ClassTy) + return false; + + // FIXME: other qualifiers? + + // We have a copy or move constructor. + TypeQuals = PointeeType.getCVRQualifiers(); + return true; +} + +bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) 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() && !AllowExplicit) + return false; + + return (getNumParams() == 0 && + getType()->getAs<FunctionProtoType>()->isVariadic()) || + (getNumParams() == 1) || + (getNumParams() > 1 && getParamDecl(1)->hasDefaultArg()); +} + +bool CXXConstructorDecl::isSpecializationCopyingObject() const { + if ((getNumParams() < 1) || + (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || + (getPrimaryTemplate() == 0) || + (getDescribedFunctionTemplate() != 0)) + return false; + + const ParmVarDecl *Param = getParamDecl(0); + + ASTContext &Context = getASTContext(); + CanQualType ParamType = Context.getCanonicalType(Param->getType()); + + // Is it the same as our our class type? + CanQualType ClassTy + = Context.getCanonicalType(Context.getTagDeclType(getParent())); + if (ParamType.getUnqualifiedType() != ClassTy) + return false; + + return true; +} + +const CXXConstructorDecl *CXXConstructorDecl::getInheritedConstructor() const { + // Hack: we store the inherited constructor in the overridden method table + method_iterator It = begin_overridden_methods(); + if (It == end_overridden_methods()) + return 0; + + return cast<CXXConstructorDecl>(*It); +} + +void +CXXConstructorDecl::setInheritedConstructor(const CXXConstructorDecl *BaseCtor){ + // Hack: we store the inherited constructor in the overridden method table + assert(size_overridden_methods() == 0 && "Base ctor already set."); + addOverriddenMethod(BaseCtor); +} + +CXXDestructorDecl * +CXXDestructorDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXDestructorDecl(0, SourceLocation(), DeclarationNameInfo(), + QualType(), 0, false, false); +} + +CXXDestructorDecl * +CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, + bool isImplicitlyDeclared) { + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXDestructorName && + "Name must refer to a destructor"); + return new (C) CXXDestructorDecl(RD, StartLoc, NameInfo, T, TInfo, isInline, + isImplicitlyDeclared); +} + +CXXConversionDecl * +CXXConversionDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) CXXConversionDecl(0, SourceLocation(), DeclarationNameInfo(), + QualType(), 0, false, false, + SourceLocation()); +} + +CXXConversionDecl * +CXXConversionDecl::Create(ASTContext &C, CXXRecordDecl *RD, + SourceLocation StartLoc, + const DeclarationNameInfo &NameInfo, + QualType T, TypeSourceInfo *TInfo, + bool isInline, bool isExplicit, + SourceLocation EndLocation) { + assert(NameInfo.getName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + "Name must refer to a conversion function"); + return new (C) CXXConversionDecl(RD, StartLoc, NameInfo, T, TInfo, + isInline, isExplicit, EndLocation); +} + +LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation ExternLoc, + SourceLocation LangLoc, + LanguageIDs Lang, + SourceLocation RBraceLoc) { + return new (C) LinkageSpecDecl(DC, ExternLoc, LangLoc, Lang, RBraceLoc); +} + +UsingDirectiveDecl *UsingDirectiveDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + SourceLocation NamespaceLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Used, + DeclContext *CommonAncestor) { + if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Used)) + Used = NS->getOriginalNamespace(); + return new (C) UsingDirectiveDecl(DC, L, NamespaceLoc, QualifierLoc, + IdentLoc, Used, CommonAncestor); +} + +NamespaceDecl *UsingDirectiveDecl::getNominatedNamespace() { + if (NamespaceAliasDecl *NA = + dyn_cast_or_null<NamespaceAliasDecl>(NominatedNamespace)) + return NA->getNamespace(); + return cast_or_null<NamespaceDecl>(NominatedNamespace); +} + +NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation AliasLoc, + IdentifierInfo *Alias, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation IdentLoc, + NamedDecl *Namespace) { + if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace)) + Namespace = NS->getOriginalNamespace(); + return new (C) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias, + QualifierLoc, IdentLoc, Namespace); +} + +UsingDecl *UsingShadowDecl::getUsingDecl() const { + const UsingShadowDecl *Shadow = this; + while (const UsingShadowDecl *NextShadow = + dyn_cast<UsingShadowDecl>(Shadow->UsingOrNextShadow)) + Shadow = NextShadow; + return cast<UsingDecl>(Shadow->UsingOrNextShadow); +} + +void UsingDecl::addShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) == shadow_end() && + "declaration already in set"); + assert(S->getUsingDecl() == this); + + if (FirstUsingShadow) + S->UsingOrNextShadow = FirstUsingShadow; + FirstUsingShadow = S; +} + +void UsingDecl::removeShadowDecl(UsingShadowDecl *S) { + assert(std::find(shadow_begin(), shadow_end(), S) != shadow_end() && + "declaration not in set"); + assert(S->getUsingDecl() == this); + + // Remove S from the shadow decl chain. This is O(n) but hopefully rare. + + if (FirstUsingShadow == S) { + FirstUsingShadow = dyn_cast<UsingShadowDecl>(S->UsingOrNextShadow); + S->UsingOrNextShadow = this; + return; + } + + UsingShadowDecl *Prev = FirstUsingShadow; + while (Prev->UsingOrNextShadow != S) + Prev = cast<UsingShadowDecl>(Prev->UsingOrNextShadow); + Prev->UsingOrNextShadow = S->UsingOrNextShadow; + S->UsingOrNextShadow = this; +} + +UsingDecl *UsingDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UL, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool IsTypeNameArg) { + return new (C) UsingDecl(DC, UL, QualifierLoc, NameInfo, IsTypeNameArg); +} + +UnresolvedUsingValueDecl * +UnresolvedUsingValueDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo) { + return new (C) UnresolvedUsingValueDecl(DC, C.DependentTy, UsingLoc, + QualifierLoc, NameInfo); +} + +UnresolvedUsingTypenameDecl * +UnresolvedUsingTypenameDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation UsingLoc, + SourceLocation TypenameLoc, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TargetNameLoc, + DeclarationName TargetName) { + return new (C) UnresolvedUsingTypenameDecl(DC, UsingLoc, TypenameLoc, + QualifierLoc, TargetNameLoc, + TargetName.getAsIdentifierInfo()); +} + +StaticAssertDecl *StaticAssertDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StaticAssertLoc, + Expr *AssertExpr, + StringLiteral *Message, + SourceLocation RParenLoc) { + return new (C) StaticAssertDecl(DC, StaticAssertLoc, AssertExpr, Message, + RParenLoc); +} + +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/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp b/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp new file mode 100644 index 000000000000..99bfe40c31f4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclFriend.cpp @@ -0,0 +1,45 @@ +//===--- DeclFriend.cpp - C++ Friend 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 AST classes related to C++ friend +// declarations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclTemplate.h" +using namespace clang; + +FriendDecl *FriendDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + FriendUnion Friend, + SourceLocation FriendL) { +#ifndef NDEBUG + if (Friend.is<NamedDecl*>()) { + NamedDecl *D = Friend.get<NamedDecl*>(); + assert(isa<FunctionDecl>(D) || + isa<CXXRecordDecl>(D) || + isa<FunctionTemplateDecl>(D) || + isa<ClassTemplateDecl>(D)); + + // As a temporary hack, we permit template instantiation to point + // to the original declaration when instantiating members. + assert(D->getFriendObjectKind() || + (cast<CXXRecordDecl>(DC)->getTemplateSpecializationKind())); + } +#endif + + FriendDecl *FD = new (C) FriendDecl(DC, L, Friend, FriendL); + cast<CXXRecordDecl>(DC)->pushFriendDecl(FD); + return FD; +} + +FriendDecl *FriendDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) FriendDecl(Empty); +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp b/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp new file mode 100644 index 000000000000..036acc2d77a5 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclGroup.cpp @@ -0,0 +1,32 @@ +//===--- 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)); +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp new file mode 100644 index 000000000000..e2c4f38ff9be --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclObjC.cpp @@ -0,0 +1,1017 @@ +//===--- 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::set(void *const* InList, unsigned Elts, ASTContext &Ctx) { + List = 0; + 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); +} + +void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, + const SourceLocation *Locs, ASTContext &Ctx) { + if (Elts == 0) + return; + + Locations = new (Ctx) SourceLocation[Elts]; + memcpy(Locations, Locs, sizeof(SourceLocation) * Elts); + set(InList, Elts, Ctx); +} + +//===----------------------------------------------------------------------===// +// ObjCInterfaceDecl +//===----------------------------------------------------------------------===// + +/// getIvarDecl - This method looks up an ivar in this ContextDecl. +/// +ObjCIvarDecl * +ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { + lookup_const_iterator Ivar, IvarEnd; + for (llvm::tie(Ivar, IvarEnd) = lookup(Id); Ivar != IvarEnd; ++Ivar) { + if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) + return ivar; + } + return 0; +} + +// Get the local instance/class method declared in this interface. +ObjCMethodDecl * +ObjCContainerDecl::getMethod(Selector Sel, bool isInstance) 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(Sel); Meth != MethEnd; ++Meth) { + ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); + if (MD && MD->isInstanceMethod() == isInstance) + return MD; + } + return 0; +} + +ObjCPropertyDecl * +ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, + IdentifierInfo *propertyID) { + + DeclContext::lookup_const_iterator I, E; + llvm::tie(I, E) = DC->lookup(propertyID); + for ( ; I != E; ++I) + if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) + return PD; + + return 0; +} + +/// FindPropertyDeclaration - Finds declaration of the property given its name +/// in 'PropertyId' and returns it. It returns 0, if not found. +ObjCPropertyDecl * +ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { + + if (ObjCPropertyDecl *PD = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) + return PD; + + switch (getKind()) { + default: + break; + case Decl::ObjCProtocol: { + const ObjCProtocolDecl *PID = cast<ObjCProtocolDecl>(this); + for (ObjCProtocolDecl::protocol_iterator I = PID->protocol_begin(), + E = PID->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + break; + } + case Decl::ObjCInterface: { + const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(this); + // Look through categories. + for (ObjCCategoryDecl *Cat = OID->getCategoryList(); + Cat; Cat = Cat->getNextClassCategory()) + if (!Cat->IsClassExtension()) + if (ObjCPropertyDecl *P = Cat->FindPropertyDeclaration(PropertyId)) + return P; + + // Look through protocols. + for (ObjCInterfaceDecl::all_protocol_iterator + I = OID->all_referenced_protocol_begin(), + E = OID->all_referenced_protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + + // Finally, check the super class. + if (const ObjCInterfaceDecl *superClass = OID->getSuperClass()) + return superClass->FindPropertyDeclaration(PropertyId); + break; + } + case Decl::ObjCCategory: { + const ObjCCategoryDecl *OCD = cast<ObjCCategoryDecl>(this); + // Look through protocols. + if (!OCD->IsClassExtension()) + for (ObjCCategoryDecl::protocol_iterator + I = OCD->protocol_begin(), E = OCD->protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + + break; + } + } + return 0; +} + +/// FindPropertyVisibleInPrimaryClass - Finds declaration of the property +/// with name 'PropertyId' in the primary class; including those in protocols +/// (direct or indirect) used by the primary class. +/// +ObjCPropertyDecl * +ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( + IdentifierInfo *PropertyId) const { + if (ExternallyCompleted) + LoadExternalDefinition(); + + if (ObjCPropertyDecl *PD = + ObjCPropertyDecl::findPropertyDecl(cast<DeclContext>(this), PropertyId)) + return PD; + + // Look through protocols. + for (ObjCInterfaceDecl::all_protocol_iterator + I = all_referenced_protocol_begin(), + E = all_referenced_protocol_end(); I != E; ++I) + if (ObjCPropertyDecl *P = (*I)->FindPropertyDeclaration(PropertyId)) + return P; + + return 0; +} + +void ObjCInterfaceDecl::mergeClassExtensionProtocolList( + ObjCProtocolDecl *const* ExtList, unsigned ExtNum, + ASTContext &C) +{ + if (ExternallyCompleted) + LoadExternalDefinition(); + + if (AllReferencedProtocols.empty() && ReferencedProtocols.empty()) { + AllReferencedProtocols.set(ExtList, ExtNum, C); + return; + } + + // Check for duplicate protocol in class's protocol list. + // This is O(n*m). But it is extremely rare and number of protocols in + // class or its extension are very few. + llvm::SmallVector<ObjCProtocolDecl*, 8> ProtocolRefs; + for (unsigned i = 0; i < ExtNum; i++) { + bool protocolExists = false; + ObjCProtocolDecl *ProtoInExtension = ExtList[i]; + for (all_protocol_iterator + p = all_referenced_protocol_begin(), + e = all_referenced_protocol_end(); p != e; ++p) { + ObjCProtocolDecl *Proto = (*p); + if (C.ProtocolCompatibleWithProtocol(ProtoInExtension, Proto)) { + protocolExists = true; + break; + } + } + // Do we want to warn on a protocol in extension class which + // already exist in the class? Probably not. + if (!protocolExists) + ProtocolRefs.push_back(ProtoInExtension); + } + + if (ProtocolRefs.empty()) + return; + + // Merge ProtocolRefs into class's protocol list; + for (all_protocol_iterator p = all_referenced_protocol_begin(), + e = all_referenced_protocol_end(); p != e; ++p) { + ProtocolRefs.push_back(*p); + } + + AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(), C); +} + +/// getFirstClassExtension - Find first class extension of the given class. +ObjCCategoryDecl* ObjCInterfaceDecl::getFirstClassExtension() const { + for (ObjCCategoryDecl *CDecl = getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + return CDecl; + return 0; +} + +/// getNextClassCategory - Find next class extension in list of categories. +const ObjCCategoryDecl* ObjCCategoryDecl::getNextClassExtension() const { + for (const ObjCCategoryDecl *CDecl = getNextClassCategory(); CDecl; + CDecl = CDecl->getNextClassCategory()) + if (CDecl->IsClassExtension()) + return CDecl; + return 0; +} + +ObjCIvarDecl *ObjCInterfaceDecl::lookupInstanceVariable(IdentifierInfo *ID, + ObjCInterfaceDecl *&clsDeclared) { + ObjCInterfaceDecl* ClassDecl = this; + while (ClassDecl != NULL) { + if (ObjCIvarDecl *I = ClassDecl->getIvarDecl(ID)) { + clsDeclared = ClassDecl; + return I; + } + for (const ObjCCategoryDecl *CDecl = ClassDecl->getFirstClassExtension(); + CDecl; CDecl = CDecl->getNextClassExtension()) { + if (ObjCIvarDecl *I = CDecl->getIvarDecl(ID)) { + clsDeclared = ClassDecl; + return I; + } + } + + 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; +} + +/// lookupMethod - This method returns an instance/class method by looking in +/// the class, its categories, and its super classes (using a linear search). +ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, + bool isInstance) const { + const ObjCInterfaceDecl* ClassDecl = this; + ObjCMethodDecl *MethodDecl = 0; + + if (ExternallyCompleted) + LoadExternalDefinition(); + + while (ClassDecl != NULL) { + if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance))) + 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)->lookupMethod(Sel, isInstance))) + return MethodDecl; + + // Didn't find one yet - now look through categories. + ObjCCategoryDecl *CatDecl = ClassDecl->getCategoryList(); + while (CatDecl) { + if ((MethodDecl = CatDecl->getMethod(Sel, isInstance))) + 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)->lookupMethod(Sel, isInstance))) + return MethodDecl; + CatDecl = CatDecl->getNextClassCategory(); + } + ClassDecl = ClassDecl->getSuperClass(); + } + return NULL; +} + +ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod( + const Selector &Sel, + bool Instance) { + ObjCMethodDecl *Method = 0; + if (ObjCImplementationDecl *ImpDecl = getImplementation()) + Method = Instance ? ImpDecl->getInstanceMethod(Sel) + : ImpDecl->getClassMethod(Sel); + + if (!Method && getSuperClass()) + return getSuperClass()->lookupPrivateMethod(Sel, Instance); + return Method; +} + +//===----------------------------------------------------------------------===// +// ObjCMethodDecl +//===----------------------------------------------------------------------===// + +ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, + SourceLocation beginLoc, + SourceLocation endLoc, + Selector SelInfo, QualType T, + TypeSourceInfo *ResultTInfo, + DeclContext *contextDecl, + bool isInstance, + bool isVariadic, + bool isSynthesized, + bool isDefined, + ImplementationControl impControl, + bool HasRelatedResultType, + unsigned numSelectorArgs) { + return new (C) ObjCMethodDecl(beginLoc, endLoc, + SelInfo, T, ResultTInfo, contextDecl, + isInstance, + isVariadic, isSynthesized, isDefined, + impControl, + HasRelatedResultType, + numSelectorArgs); +} + +/// \brief A definition will return its interface declaration. +/// An interface declaration will return its definition. +/// Otherwise it will return itself. +ObjCMethodDecl *ObjCMethodDecl::getNextRedeclaration() { + ASTContext &Ctx = getASTContext(); + ObjCMethodDecl *Redecl = 0; + Decl *CtxD = cast<Decl>(getDeclContext()); + + if (ObjCInterfaceDecl *IFD = dyn_cast<ObjCInterfaceDecl>(CtxD)) { + if (ObjCImplementationDecl *ImplD = Ctx.getObjCImplementation(IFD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(CtxD)) { + if (ObjCCategoryImplDecl *ImplD = Ctx.getObjCImplementation(CD)) + Redecl = ImplD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCImplementationDecl *ImplD = + dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + Redecl = IFD->getMethod(getSelector(), isInstanceMethod()); + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) + Redecl = CatD->getMethod(getSelector(), isInstanceMethod()); + } + + return Redecl ? Redecl : this; +} + +ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { + Decl *CtxD = cast<Decl>(getDeclContext()); + + if (ObjCImplementationDecl *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) { + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) + if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + + } else if (ObjCCategoryImplDecl *CImplD = + dyn_cast<ObjCCategoryImplDecl>(CtxD)) { + if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) + if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), + isInstanceMethod())) + return MD; + } + + return this; +} + +ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { + ObjCMethodFamily family = static_cast<ObjCMethodFamily>(Family); + if (family != static_cast<unsigned>(InvalidObjCMethodFamily)) + return family; + + // Check for an explicit attribute. + if (const ObjCMethodFamilyAttr *attr = getAttr<ObjCMethodFamilyAttr>()) { + // The unfortunate necessity of mapping between enums here is due + // to the attributes framework. + switch (attr->getFamily()) { + case ObjCMethodFamilyAttr::OMF_None: family = OMF_None; break; + case ObjCMethodFamilyAttr::OMF_alloc: family = OMF_alloc; break; + case ObjCMethodFamilyAttr::OMF_copy: family = OMF_copy; break; + case ObjCMethodFamilyAttr::OMF_init: family = OMF_init; break; + case ObjCMethodFamilyAttr::OMF_mutableCopy: family = OMF_mutableCopy; break; + case ObjCMethodFamilyAttr::OMF_new: family = OMF_new; break; + } + Family = static_cast<unsigned>(family); + return family; + } + + family = getSelector().getMethodFamily(); + switch (family) { + case OMF_None: break; + + // init only has a conventional meaning for an instance method, and + // it has to return an object. + case OMF_init: + if (!isInstanceMethod() || !getResultType()->isObjCObjectPointerType()) + family = OMF_None; + break; + + // alloc/copy/new have a conventional meaning for both class and + // instance methods, but they require an object return. + case OMF_alloc: + case OMF_copy: + case OMF_mutableCopy: + case OMF_new: + if (!getResultType()->isObjCObjectPointerType()) + family = OMF_None; + break; + + // These selectors have a conventional meaning only for instance methods. + case OMF_dealloc: + case OMF_retain: + case OMF_release: + case OMF_autorelease: + case OMF_retainCount: + case OMF_self: + if (!isInstanceMethod()) + family = OMF_None; + break; + } + + // Cache the result. + Family = static_cast<unsigned>(family); + return family; +} + +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.getObjCObjectPointerType(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())); +} + +ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(getDeclContext())) + return ID; + if (ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(getDeclContext())) + return CD->getClassInterface(); + if (ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(getDeclContext())) + return IMD->getClassInterface(); + + assert(!isa<ObjCProtocolDecl>(getDeclContext()) && "It's a protocol method"); + 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), IvarList(0), + ForwardDecl(FD), InternalInterface(isInternal), ExternallyCompleted(false), + ClassLoc(CLoc) { +} + +void ObjCInterfaceDecl::LoadExternalDefinition() const { + assert(ExternallyCompleted && "Class is not externally completed"); + ExternallyCompleted = false; + getASTContext().getExternalSource()->CompleteType( + const_cast<ObjCInterfaceDecl *>(this)); +} + +void ObjCInterfaceDecl::setExternallyCompleted() { + assert(getASTContext().getExternalSource() && + "Class can't be externally completed without an external source"); + assert(!ForwardDecl && + "Forward declarations can't be externally completed"); + ExternallyCompleted = true; +} + +ObjCImplementationDecl *ObjCInterfaceDecl::getImplementation() const { + if (ExternallyCompleted) + LoadExternalDefinition(); + + return getASTContext().getObjCImplementation( + const_cast<ObjCInterfaceDecl*>(this)); +} + +void ObjCInterfaceDecl::setImplementation(ObjCImplementationDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + +/// all_declared_ivar_begin - return first ivar declared in this class, +/// its extensions and its implementation. Lazily build the list on first +/// access. +ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { + if (IvarList) + return IvarList; + + ObjCIvarDecl *curIvar = 0; + if (!ivar_empty()) { + ObjCInterfaceDecl::ivar_iterator I = ivar_begin(), E = ivar_end(); + IvarList = (*I); ++I; + for (curIvar = IvarList; I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + + for (const ObjCCategoryDecl *CDecl = getFirstClassExtension(); CDecl; + CDecl = CDecl->getNextClassExtension()) { + if (!CDecl->ivar_empty()) { + ObjCCategoryDecl::ivar_iterator I = CDecl->ivar_begin(), + E = CDecl->ivar_end(); + if (!IvarList) { + IvarList = (*I); ++I; + curIvar = IvarList; + } + for ( ;I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + } + + if (ObjCImplementationDecl *ImplDecl = getImplementation()) { + if (!ImplDecl->ivar_empty()) { + ObjCImplementationDecl::ivar_iterator I = ImplDecl->ivar_begin(), + E = ImplDecl->ivar_end(); + if (!IvarList) { + IvarList = (*I); ++I; + curIvar = IvarList; + } + for ( ;I != E; curIvar = *I, ++I) + curIvar->setNextIvar(*I); + } + } + return IvarList; +} + +/// 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 { + if (ExternallyCompleted) + LoadExternalDefinition(); + + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (Category->getIdentifier() == CategoryId) + return Category; + return 0; +} + +ObjCMethodDecl * +ObjCInterfaceDecl::getCategoryInstanceMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getInstanceMethod(Sel)) + return MD; + return 0; +} + +ObjCMethodDecl *ObjCInterfaceDecl::getCategoryClassMethod(Selector Sel) const { + for (ObjCCategoryDecl *Category = getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (ObjCCategoryImplDecl *Impl = Category->getImplementation()) + if (ObjCMethodDecl *MD = Impl->getClassMethod(Sel)) + return MD; + return 0; +} + +/// ClassImplementsProtocol - Checks that 'lProto' protocol +/// has been implemented in IDecl class, its super class or categories (if +/// lookupCategory is true). +bool ObjCInterfaceDecl::ClassImplementsProtocol(ObjCProtocolDecl *lProto, + bool lookupCategory, + bool RHSIsQualifiedID) { + ObjCInterfaceDecl *IDecl = this; + // 1st, look up the class. + const ObjCList<ObjCProtocolDecl> &Protocols = + IDecl->getReferencedProtocols(); + + for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), + E = Protocols.end(); PI != E; ++PI) { + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + // This is dubious and is added to be compatible with gcc. In gcc, it is + // also allowed assigning a protocol-qualified 'id' type to a LHS object + // when protocol in qualified LHS is in list of protocols in the rhs 'id' + // object. This IMO, should be a bug. + // FIXME: Treat this as an extension, and flag this as an error when GCC + // extensions are not enabled. + if (RHSIsQualifiedID && + getASTContext().ProtocolCompatibleWithProtocol(*PI, lProto)) + return true; + } + + // 2nd, look up the category. + if (lookupCategory) + for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; + CDecl = CDecl->getNextClassCategory()) { + for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), + E = CDecl->protocol_end(); PI != E; ++PI) + if (getASTContext().ProtocolCompatibleWithProtocol(lProto, *PI)) + return true; + } + + // 3rd, look up the super class(s) + if (IDecl->getSuperClass()) + return + IDecl->getSuperClass()->ClassImplementsProtocol(lProto, lookupCategory, + RHSIsQualifiedID); + + return false; +} + +//===----------------------------------------------------------------------===// +// ObjCIvarDecl +//===----------------------------------------------------------------------===// + +ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, IdentifierInfo *Id, + QualType T, TypeSourceInfo *TInfo, + AccessControl ac, Expr *BW, + bool synthesized) { + if (DC) { + // Ivar's can only appear in interfaces, implementations (via synthesized + // properties), and class extensions (via direct declaration, or synthesized + // properties). + // + // FIXME: This should really be asserting this: + // (isa<ObjCCategoryDecl>(DC) && + // cast<ObjCCategoryDecl>(DC)->IsClassExtension())) + // but unfortunately we sometimes place ivars into non-class extension + // categories on error. This breaks an AST invariant, and should not be + // fixed. + assert((isa<ObjCInterfaceDecl>(DC) || isa<ObjCImplementationDecl>(DC) || + isa<ObjCCategoryDecl>(DC)) && + "Invalid ivar decl context!"); + // Once a new ivar is created in any of class/class-extension/implementation + // decl contexts, the previously built IvarList must be rebuilt. + ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(DC); + if (!ID) { + if (ObjCImplementationDecl *IM = dyn_cast<ObjCImplementationDecl>(DC)) { + ID = IM->getClassInterface(); + if (BW) + IM->setHasSynthBitfield(true); + } + else { + ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC); + ID = CD->getClassInterface(); + if (BW) + CD->setHasSynthBitfield(true); + } + } + ID->setIvarList(0); + } + + return new (C) ObjCIvarDecl(DC, StartLoc, IdLoc, Id, T, TInfo, + ac, BW, synthesized); +} + +const ObjCInterfaceDecl *ObjCIvarDecl::getContainingInterface() const { + const ObjCContainerDecl *DC = cast<ObjCContainerDecl>(getDeclContext()); + + switch (DC->getKind()) { + default: + case ObjCCategoryImpl: + case ObjCProtocol: + assert(0 && "invalid ivar container!"); + return 0; + + // Ivars can only appear in class extension categories. + case ObjCCategory: { + const ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(DC); + assert(CD->IsClassExtension() && "invalid container for ivar!"); + return CD->getClassInterface(); + } + + case ObjCImplementation: + return cast<ObjCImplementationDecl>(DC)->getClassInterface(); + + case ObjCInterface: + return cast<ObjCInterfaceDecl>(DC); + } +} + +//===----------------------------------------------------------------------===// +// ObjCAtDefsFieldDecl +//===----------------------------------------------------------------------===// + +ObjCAtDefsFieldDecl +*ObjCAtDefsFieldDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + IdentifierInfo *Id, QualType T, Expr *BW) { + return new (C) ObjCAtDefsFieldDecl(DC, StartLoc, IdLoc, Id, T, BW); +} + +//===----------------------------------------------------------------------===// +// ObjCProtocolDecl +//===----------------------------------------------------------------------===// + +ObjCProtocolDecl *ObjCProtocolDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + IdentifierInfo *Id) { + return new (C) ObjCProtocolDecl(DC, L, Id); +} + +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; +} + +// lookupMethod - Lookup a instance/class method in the protocol and protocols +// it inherited. +ObjCMethodDecl *ObjCProtocolDecl::lookupMethod(Selector Sel, + bool isInstance) const { + ObjCMethodDecl *MethodDecl = NULL; + + if ((MethodDecl = getMethod(Sel, isInstance))) + return MethodDecl; + + for (protocol_iterator I = protocol_begin(), E = protocol_end(); I != E; ++I) + if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) + return MethodDecl; + return NULL; +} + +//===----------------------------------------------------------------------===// +// ObjCClassDecl +//===----------------------------------------------------------------------===// + +ObjCClassDecl::ObjCClassDecl(DeclContext *DC, SourceLocation L, + ObjCInterfaceDecl *const *Elts, + const SourceLocation *Locs, + unsigned nElts, + ASTContext &C) + : Decl(ObjCClass, DC, L) { + setClassList(C, Elts, Locs, nElts); +} + +void ObjCClassDecl::setClassList(ASTContext &C, ObjCInterfaceDecl*const*List, + const SourceLocation *Locs, unsigned Num) { + ForwardDecls = (ObjCClassRef*) C.Allocate(sizeof(ObjCClassRef)*Num, + llvm::alignOf<ObjCClassRef>()); + for (unsigned i = 0; i < Num; ++i) + new (&ForwardDecls[i]) ObjCClassRef(List[i], Locs[i]); + + NumDecls = Num; +} + +ObjCClassDecl *ObjCClassDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCInterfaceDecl *const *Elts, + const SourceLocation *Locs, + unsigned nElts) { + return new (C) ObjCClassDecl(DC, L, Elts, Locs, nElts, C); +} + +SourceRange ObjCClassDecl::getSourceRange() const { + // FIXME: We should include the semicolon + assert(NumDecls); + return SourceRange(getLocation(), ForwardDecls[NumDecls-1].getLocation()); +} + +//===----------------------------------------------------------------------===// +// ObjCForwardProtocolDecl +//===----------------------------------------------------------------------===// + +ObjCForwardProtocolDecl:: +ObjCForwardProtocolDecl(DeclContext *DC, SourceLocation L, + ObjCProtocolDecl *const *Elts, unsigned nElts, + const SourceLocation *Locs, ASTContext &C) +: Decl(ObjCForwardProtocol, DC, L) { + ReferencedProtocols.set(Elts, nElts, Locs, C); +} + + +ObjCForwardProtocolDecl * +ObjCForwardProtocolDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCProtocolDecl *const *Elts, + unsigned NumElts, + const SourceLocation *Locs) { + return new (C) ObjCForwardProtocolDecl(DC, L, Elts, NumElts, Locs, C); +} + +//===----------------------------------------------------------------------===// +// ObjCCategoryDecl +//===----------------------------------------------------------------------===// + +ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation AtLoc, + SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, + IdentifierInfo *Id) { + return new (C) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id); +} + +ObjCCategoryImplDecl *ObjCCategoryDecl::getImplementation() const { + return getASTContext().getObjCImplementation( + const_cast<ObjCCategoryDecl*>(this)); +} + +void ObjCCategoryDecl::setImplementation(ObjCCategoryImplDecl *ImplD) { + getASTContext().setObjCImplementation(this, ImplD); +} + + +//===----------------------------------------------------------------------===// +// ObjCCategoryImplDecl +//===----------------------------------------------------------------------===// + +ObjCCategoryImplDecl * +ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L,IdentifierInfo *Id, + ObjCInterfaceDecl *ClassInterface) { + return new (C) ObjCCategoryImplDecl(DC, L, Id, ClassInterface); +} + +ObjCCategoryDecl *ObjCCategoryImplDecl::getCategoryDecl() const { + // The class interface might be NULL if we are working with invalid code. + if (const ObjCInterfaceDecl *ID = getClassInterface()) + return ID->FindCategoryDeclaration(getIdentifier()); + return 0; +} + + +void ObjCImplDecl::addPropertyImplementation(ObjCPropertyImplDecl *property) { + // FIXME: The context should be correct before we get here. + property->setLexicalDeclContext(this); + addDecl(property); +} + +void ObjCImplDecl::setClassInterface(ObjCInterfaceDecl *IFace) { + ASTContext &Ctx = getASTContext(); + + if (ObjCImplementationDecl *ImplD + = dyn_cast_or_null<ObjCImplementationDecl>(this)) { + if (IFace) + Ctx.setObjCImplementation(IFace, ImplD); + + } else if (ObjCCategoryImplDecl *ImplD = + dyn_cast_or_null<ObjCCategoryImplDecl>(this)) { + if (ObjCCategoryDecl *CD = IFace->FindCategoryDeclaration(getIdentifier())) + Ctx.setObjCImplementation(CD, ImplD); + } + + ClassInterface = IFace; +} + +/// 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(IdentifierInfo *ivarId) const { + for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); 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(IdentifierInfo *Id) const { + for (propimpl_iterator i = propimpl_begin(), e = propimpl_end(); i != e; ++i){ + ObjCPropertyImplDecl *PID = *i; + if (PID->getPropertyDecl()->getIdentifier() == Id) + return PID; + } + return 0; +} + +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCCategoryImplDecl *CID) { + OS << CID->getName(); + return OS; +} + +//===----------------------------------------------------------------------===// +// ObjCImplementationDecl +//===----------------------------------------------------------------------===// + +ObjCImplementationDecl * +ObjCImplementationDecl::Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + ObjCInterfaceDecl *ClassInterface, + ObjCInterfaceDecl *SuperDecl) { + return new (C) ObjCImplementationDecl(DC, L, ClassInterface, SuperDecl); +} + +llvm::raw_ostream &clang::operator<<(llvm::raw_ostream &OS, + const ObjCImplementationDecl *ID) { + OS << ID->getName(); + return OS; +} + +//===----------------------------------------------------------------------===// +// 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, + SourceLocation AtLoc, + TypeSourceInfo *T, + PropertyControl propControl) { + return new (C) ObjCPropertyDecl(DC, L, Id, AtLoc, T); +} + +//===----------------------------------------------------------------------===// +// ObjCPropertyImplDecl +//===----------------------------------------------------------------------===// + +ObjCPropertyImplDecl *ObjCPropertyImplDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation atLoc, + SourceLocation L, + ObjCPropertyDecl *property, + Kind PK, + ObjCIvarDecl *ivar, + SourceLocation ivarLoc) { + return new (C) ObjCPropertyImplDecl(DC, atLoc, L, property, PK, ivar, + ivarLoc); +} + +SourceRange ObjCPropertyImplDecl::getSourceRange() const { + SourceLocation EndLoc = getLocation(); + if (IvarLoc.isValid()) + EndLoc = IvarLoc; + + return SourceRange(AtLoc, EndLoc); +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp new file mode 100644 index 000000000000..421770ea70fb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclPrinter.cpp @@ -0,0 +1,987 @@ +//===--- 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/ExprCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class DeclPrinter : public DeclVisitor<DeclPrinter> { + llvm::raw_ostream &Out; + ASTContext &Context; + PrintingPolicy Policy; + unsigned Indentation; + + llvm::raw_ostream& Indent() { return Indent(Indentation); } + llvm::raw_ostream& Indent(unsigned Indentation); + void ProcessDeclGroup(llvm::SmallVectorImpl<Decl*>& Decls); + + void Print(AccessSpecifier AS); + + 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 VisitTypeAliasDecl(TypeAliasDecl *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 VisitLabelDecl(LabelDecl *D); + void VisitParmVarDecl(ParmVarDecl *D); + void VisitFileScopeAsmDecl(FileScopeAsmDecl *D); + void VisitStaticAssertDecl(StaticAssertDecl *D); + void VisitNamespaceDecl(NamespaceDecl *D); + void VisitUsingDirectiveDecl(UsingDirectiveDecl *D); + void VisitNamespaceAliasDecl(NamespaceAliasDecl *D); + void VisitCXXRecordDecl(CXXRecordDecl *D); + void VisitLinkageSpecDecl(LinkageSpecDecl *D); + void VisitTemplateDecl(const 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 VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + void VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); + void VisitUsingDecl(UsingDecl *D); + void VisitUsingShadowDecl(UsingShadowDecl *D); + }; +} + +void Decl::print(llvm::raw_ostream &Out, unsigned Indentation) const { + print(Out, getASTContext().PrintingPolicy, Indentation); +} + +void Decl::print(llvm::raw_ostream &Out, const PrintingPolicy &Policy, + unsigned Indentation) const { + DeclPrinter Printer(Out, getASTContext(), Policy, Indentation); + Printer.Visit(const_cast<Decl*>(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->getAs<PointerType>()) + BaseType = PTy->getPointeeType(); + else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) + BaseType = ATy->getElementType(); + else if (const FunctionType* FTy = BaseType->getAs<FunctionType>()) + BaseType = FTy->getResultType(); + else if (const VectorType *VTy = BaseType->getAs<VectorType>()) + BaseType = VTy->getElementType(); + else + assert(0 && "Unknown declarator!"); + } + return BaseType; +} + +static QualType getDeclType(Decl* D) { + if (TypedefNameDecl* TDD = dyn_cast<TypedefNameDecl>(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, const PrintingPolicy &Policy, + unsigned Indentation) { + if (NumDecls == 1) { + (*Begin)->print(Out, 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, 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, SubPolicy, Indentation); + } +} + +void DeclContext::dumpDeclContext() const { + // Get the translation unit + const DeclContext *DC = this; + while (!DC->isTranslationUnit()) + DC = DC->getParent(); + + ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); + DeclPrinter Printer(llvm::errs(), Ctx, Ctx.PrintingPolicy, 0); + Printer.VisitDeclContext(const_cast<DeclContext *>(this), /*Indent=*/false); +} + +void Decl::dump() const { + print(llvm::errs()); +} + +llvm::raw_ostream& DeclPrinter::Indent(unsigned Indentation) { + 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, Policy, Indentation); + Out << ";\n"; + Decls.clear(); + +} + +void DeclPrinter::Print(AccessSpecifier AS) { + switch(AS) { + case AS_none: assert(0 && "No access specifier!"); break; + case AS_public: Out << "public"; break; + case AS_protected: Out << "protected"; break; + case AS_private: Out << "private"; break; + } +} + +//---------------------------------------------------------------------------- +// 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(), DEnd = DC->decls_end(); + D != DEnd; ++D) { + + // Don't print ObjCIvarDecls, as they are printed when visiting the + // containing ObjCInterfaceDecl. + if (isa<ObjCIvarDecl>(*D)) + continue; + + 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 or __[u]int128_t. There should be some other way + // to check that. + if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) { + if (IdentifierInfo *II = ND->getIdentifier()) { + if (II->isStr("__builtin_va_list") || + II->isStr("__int128_t") || II->isStr("__uint128_t")) + 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; + } + + if (isa<AccessSpecDecl>(*D)) { + Indentation -= Policy.Indentation; + this->Indent(); + Print(D->getAccess()); + Out << ":\n"; + Indentation += Policy.Indentation; + 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::VisitTypeAliasDecl(TypeAliasDecl *D) { + Out << "using " << D->getNameAsString() << " = " + << D->getUnderlyingType().getAsString(Policy); +} + +void DeclPrinter::VisitEnumDecl(EnumDecl *D) { + Out << "enum "; + if (D->isScoped()) { + if (D->isScopedUsingClassTag()) + Out << "class "; + else + Out << "struct "; + } + Out << D; + + if (D->isFixed()) { + std::string Underlying; + D->getIntegerType().getAsStringInternal(Underlying, Policy); + Out << " : " << Underlying; + } + + if (D->isDefinition()) { + Out << " {\n"; + VisitDeclContext(D); + Indent() << "}"; + } +} + +void DeclPrinter::VisitRecordDecl(RecordDecl *D) { + Out << D->getKindName(); + if (D->getIdentifier()) + Out << ' ' << D; + + if (D->isDefinition()) { + Out << " {\n"; + VisitDeclContext(D); + Indent() << "}"; + } +} + +void DeclPrinter::VisitEnumConstantDecl(EnumConstantDecl *D) { + Out << D; + 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 SC_None: break; + case SC_Extern: Out << "extern "; break; + case SC_Static: Out << "static "; break; + case SC_PrivateExtern: Out << "__private_extern__ "; break; + case SC_Auto: case SC_Register: llvm_unreachable("invalid for functions"); + } + + if (D->isInlineSpecified()) Out << "inline "; + if (D->isVirtualAsWritten()) Out << "virtual "; + } + + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressSpecifiers = false; + std::string Proto = D->getNameInfo().getAsString(); + + QualType Ty = D->getType(); + while (const ParenType *PT = dyn_cast<ParenType>(Ty)) { + Proto = '(' + Proto + ')'; + Ty = PT->getInnerType(); + } + + if (isa<FunctionType>(Ty)) { + const FunctionType *AFT = Ty->getAs<FunctionType>(); + 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->doesThisDeclarationHaveABody() && !D->hasPrototype()) { + for (unsigned i = 0, e = D->getNumParams(); i != e; ++i) { + if (i) + Proto += ", "; + Proto += D->getParamDecl(i)->getNameAsString(); + } + } + + Proto += ")"; + + if (FT && FT->getTypeQuals()) { + unsigned TypeQuals = FT->getTypeQuals(); + if (TypeQuals & Qualifiers::Const) + Proto += " const"; + if (TypeQuals & Qualifiers::Volatile) + Proto += " volatile"; + if (TypeQuals & Qualifiers::Restrict) + Proto += " restrict"; + } + + if (FT && FT->hasDynamicExceptionSpec()) { + Proto += " throw("; + if (FT->getExceptionSpecType() == EST_MSAny) + Proto += "..."; + else + for (unsigned I = 0, N = FT->getNumExceptions(); I != N; ++I) { + if (I) + Proto += ", "; + + std::string ExceptionType; + FT->getExceptionType(I).getAsStringInternal(ExceptionType, SubPolicy); + Proto += ExceptionType; + } + Proto += ")"; + } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { + Proto += " noexcept"; + if (FT->getExceptionSpecType() == EST_ComputedNoexcept) { + Proto += "("; + llvm::raw_string_ostream EOut(Proto); + FT->getNoexceptExpr()->printPretty(EOut, Context, 0, SubPolicy, + Indentation); + EOut.flush(); + Proto += EOut.str(); + Proto += ")"; + } + } + + if (D->hasAttr<NoReturnAttr>()) + Proto += " __attribute((noreturn))"; + if (CXXConstructorDecl *CDecl = dyn_cast<CXXConstructorDecl>(D)) { + bool HasInitializerList = false; + for (CXXConstructorDecl::init_const_iterator B = CDecl->init_begin(), + E = CDecl->init_end(); + B != E; ++B) { + CXXCtorInitializer * BMInitializer = (*B); + if (BMInitializer->isInClassMemberInitializer()) + continue; + + if (!HasInitializerList) { + Proto += " : "; + Out << Proto; + Proto.clear(); + HasInitializerList = true; + } else + Out << ", "; + + if (BMInitializer->isAnyMemberInitializer()) { + FieldDecl *FD = BMInitializer->getAnyMember(); + Out << FD; + } else { + Out << QualType(BMInitializer->getBaseClass(), + 0).getAsString(Policy); + } + + Out << "("; + if (!BMInitializer->getInit()) { + // Nothing to print + } else { + Expr *Init = BMInitializer->getInit(); + if (ExprWithCleanups *Tmp = dyn_cast<ExprWithCleanups>(Init)) + Init = Tmp->getSubExpr(); + + Init = Init->IgnoreParens(); + + Expr *SimpleInit = 0; + Expr **Args = 0; + unsigned NumArgs = 0; + if (ParenListExpr *ParenList = dyn_cast<ParenListExpr>(Init)) { + Args = ParenList->getExprs(); + NumArgs = ParenList->getNumExprs(); + } else if (CXXConstructExpr *Construct + = dyn_cast<CXXConstructExpr>(Init)) { + Args = Construct->getArgs(); + NumArgs = Construct->getNumArgs(); + } else + SimpleInit = Init; + + if (SimpleInit) + SimpleInit->printPretty(Out, Context, 0, Policy, Indentation); + else { + for (unsigned I = 0; I != NumArgs; ++I) { + if (isa<CXXDefaultArgExpr>(Args[I])) + break; + + if (I) + Out << ", "; + Args[I]->printPretty(Out, Context, 0, Policy, Indentation); + } + } + } + Out << ")"; + } + } + else + AFT->getResultType().getAsStringInternal(Proto, Policy); + } else { + Ty.getAsStringInternal(Proto, Policy); + } + + Out << Proto; + + if (D->isPure()) + Out << " = 0"; + else if (D->isDeletedAsWritten()) + Out << " = delete"; + else if (D->doesThisDeclarationHaveABody()) { + 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()->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); + } + + Expr *Init = D->getInClassInitializer(); + if (!Policy.SuppressInitializers && Init) { + Out << " = "; + Init->printPretty(Out, Context, 0, Policy, Indentation); + } +} + +void DeclPrinter::VisitLabelDecl(LabelDecl *D) { + Out << D->getNameAsString() << ":"; +} + + +void DeclPrinter::VisitVarDecl(VarDecl *D) { + if (!Policy.SuppressSpecifiers && D->getStorageClass() != SC_None) + Out << VarDecl::getStorageClassSpecifierString(D->getStorageClass()) << " "; + + if (!Policy.SuppressSpecifiers && D->isThreadSpecified()) + Out << "__thread "; + + std::string Name = D->getNameAsString(); + QualType T = D->getType(); + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) + T = Parm->getOriginalType(); + T.getAsStringInternal(Name, Policy); + Out << Name; + Expr *Init = D->getInit(); + if (!Policy.SuppressInitializers && Init) { + if (D->hasCXXDirectInitializer()) + Out << "("; + else { + CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init); + if (!CCE || CCE->getConstructor()->isCopyConstructor()) + Out << " = "; + } + Init->printPretty(Out, Context, 0, Policy, Indentation); + if (D->hasCXXDirectInitializer()) + Out << ")"; + } +} + +void DeclPrinter::VisitParmVarDecl(ParmVarDecl *D) { + VisitVarDecl(D); +} + +void DeclPrinter::VisitFileScopeAsmDecl(FileScopeAsmDecl *D) { + Out << "__asm ("; + D->getAsmString()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ")"; +} + +void DeclPrinter::VisitStaticAssertDecl(StaticAssertDecl *D) { + Out << "static_assert("; + D->getAssertExpr()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ", "; + D->getMessage()->printPretty(Out, Context, 0, Policy, Indentation); + Out << ")"; +} + +//---------------------------------------------------------------------------- +// C++ declarations +//---------------------------------------------------------------------------- +void DeclPrinter::VisitNamespaceDecl(NamespaceDecl *D) { + Out << "namespace " << D << " {\n"; + VisitDeclContext(D); + Indent() << "}"; +} + +void DeclPrinter::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { + Out << "using namespace "; + if (D->getQualifier()) + D->getQualifier()->print(Out, Policy); + Out << D->getNominatedNamespaceAsWritten(); +} + +void DeclPrinter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { + Out << "namespace " << D << " = "; + if (D->getQualifier()) + D->getQualifier()->print(Out, Policy); + Out << D->getAliasedNamespace(); +} + +void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { + Out << D->getKindName(); + if (D->getIdentifier()) + Out << ' ' << D; + + 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 "; + + AccessSpecifier AS = Base->getAccessSpecifierAsWritten(); + if (AS != AS_none) + Print(AS); + Out << " " << Base->getType().getAsString(Policy); + + if (Base->isPackExpansion()) + Out << "..."; + } + } + + // 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()); +} + +void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { + Out << "template <"; + + TemplateParameterList *Params = D->getTemplateParameters(); + for (unsigned i = 0, e = Params->size(); i != e; ++i) { + if (i != 0) + Out << ", "; + + const Decl *Param = Params->getParam(i); + if (const TemplateTypeParmDecl *TTP = + dyn_cast<TemplateTypeParmDecl>(Param)) { + + if (TTP->wasDeclaredWithTypename()) + Out << "typename "; + else + Out << "class "; + + if (TTP->isParameterPack()) + Out << "... "; + + Out << TTP->getNameAsString(); + + if (TTP->hasDefaultArgument()) { + Out << " = "; + Out << TTP->getDefaultArgument().getAsString(Policy); + }; + } else if (const NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Out << NTTP->getType().getAsString(Policy); + + if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType())) + Out << "..."; + + if (IdentifierInfo *Name = NTTP->getIdentifier()) { + Out << ' '; + Out << Name->getName(); + } + + if (NTTP->hasDefaultArgument()) { + Out << " = "; + NTTP->getDefaultArgument()->printPretty(Out, Context, 0, Policy, + Indentation); + } + } else if (const TemplateTemplateParmDecl *TTPD = + dyn_cast<TemplateTemplateParmDecl>(Param)) { + VisitTemplateDecl(TTPD); + // FIXME: print the default argument, if present. + } + } + + Out << "> "; + + if (const TemplateTemplateParmDecl *TTP = + dyn_cast<TemplateTemplateParmDecl>(D)) { + Out << "class "; + if (TTP->isParameterPack()) + Out << "..."; + Out << D->getName(); + } else { + 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->getInterface(); + } +} + +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; + 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; + 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; + 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; + } + + 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 << ";\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; + } +} + +void DeclPrinter::VisitObjCProtocolDecl(ObjCProtocolDecl *PID) { + Out << "@protocol " << PID << '\n'; + VisitDeclContext(PID, false); + Out << "@end"; +} + +void DeclPrinter::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *PID) { + Out << "@implementation " << PID->getClassInterface() << '(' << PID << ")\n"; + + VisitDeclContext(PID, false); + Out << "@end"; + // FIXME: implement the rest... +} + +void DeclPrinter::VisitObjCCategoryDecl(ObjCCategoryDecl *PID) { + Out << "@interface " << PID->getClassInterface() << '(' << PID << ")\n"; + VisitDeclContext(PID, false); + Out << "@end"; + + // FIXME: implement the rest... +} + +void DeclPrinter::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *AID) { + Out << "@compatibility_alias " << AID + << ' ' << AID->getClassInterface() << ";\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; + } + if (PDecl->getPropertyAttributes() & + ObjCPropertyDecl::OBJC_PR_atomic) { + Out << (first ? ' ' : ',') << "atomic"; + first = false; + } + Out << " )"; + } + Out << ' ' << PDecl->getType().getAsString(Policy) << ' ' << PDecl; +} + +void DeclPrinter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *PID) { + if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) + Out << "@synthesize "; + else + Out << "@dynamic "; + Out << PID->getPropertyDecl(); + if (PID->getPropertyIvarDecl()) + Out << '=' << PID->getPropertyIvarDecl(); +} + +void DeclPrinter::VisitUsingDecl(UsingDecl *D) { + Out << "using "; + D->getQualifier()->print(Out, Policy); + Out << D; +} + +void +DeclPrinter::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { + Out << "using typename "; + D->getQualifier()->print(Out, Policy); + Out << D->getDeclName(); +} + +void DeclPrinter::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { + Out << "using "; + D->getQualifier()->print(Out, Policy); + Out << D->getDeclName(); +} + +void DeclPrinter::VisitUsingShadowDecl(UsingShadowDecl *D) { + // ignore +} diff --git a/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp new file mode 100644 index 000000000000..bc375d0ad2d3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclTemplate.cpp @@ -0,0 +1,768 @@ +//===--- DeclTemplate.cpp - Template 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/ExprCXX.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/ASTMutationListener.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/STLExtras.h" +#include <memory> +using namespace clang; + +//===----------------------------------------------------------------------===// +// TemplateParameterList Implementation +//===----------------------------------------------------------------------===// + +TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + NamedDecl **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(const ASTContext &C, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, NamedDecl **Params, + unsigned NumParams, SourceLocation RAngleLoc) { + unsigned Size = sizeof(TemplateParameterList) + + sizeof(NamedDecl *) * 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 = 0; + for (iterator P = const_cast<TemplateParameterList *>(this)->begin(), + PEnd = const_cast<TemplateParameterList *>(this)->end(); + P != PEnd; ++P) { + if ((*P)->isTemplateParameterPack()) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) + if (NTTP->isExpandedParameterPack()) { + NumRequiredArgs += NTTP->getNumExpansionTypes(); + continue; + } + + break; + } + + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + if (TTP->hasDefaultArgument()) + break; + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (NTTP->hasDefaultArgument()) + break; + } else if (cast<TemplateTemplateParmDecl>(*P)->hasDefaultArgument()) + break; + + ++NumRequiredArgs; + } + + return NumRequiredArgs; +} + +unsigned TemplateParameterList::getDepth() const { + if (size() == 0) + return 0; + + const NamedDecl *FirstParm = getParam(0); + if (const TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(FirstParm)) + return TTP->getDepth(); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(FirstParm)) + return NTTP->getDepth(); + else + return cast<TemplateTemplateParmDecl>(FirstParm)->getDepth(); +} + +static void AdoptTemplateParameterList(TemplateParameterList *Params, + DeclContext *Owner) { + for (TemplateParameterList::iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + (*P)->setDeclContext(Owner); + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*P)) + AdoptTemplateParameterList(TTP->getTemplateParameters(), Owner); + } +} + +//===----------------------------------------------------------------------===// +// RedeclarableTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() { + // Find the first declaration of this function template. + RedeclarableTemplateDecl *First = getCanonicalDecl(); + + if (First->CommonOrPrev.isNull()) { + CommonBase *CommonPtr = First->newCommon(getASTContext()); + First->CommonOrPrev = CommonPtr; + CommonPtr->Latest = First; + } + return First->CommonOrPrev.get<CommonBase*>(); +} + + +RedeclarableTemplateDecl *RedeclarableTemplateDecl::getCanonicalDeclImpl() { + RedeclarableTemplateDecl *Tmpl = this; + while (Tmpl->getPreviousDeclaration()) + Tmpl = Tmpl->getPreviousDeclaration(); + return Tmpl; +} + +void RedeclarableTemplateDecl::setPreviousDeclarationImpl( + RedeclarableTemplateDecl *Prev) { + if (Prev) { + CommonBase *Common = Prev->getCommonPtr(); + Prev = Common->Latest; + Common->Latest = this; + CommonOrPrev = Prev; + } else { + assert(CommonOrPrev.is<CommonBase*>() && "Cannot reset TemplateDecl Prev"); + } +} + +RedeclarableTemplateDecl *RedeclarableTemplateDecl::getNextRedeclaration() { + if (CommonOrPrev.is<RedeclarableTemplateDecl*>()) + return CommonOrPrev.get<RedeclarableTemplateDecl*>(); + CommonBase *Common = CommonOrPrev.get<CommonBase*>(); + return Common ? Common->Latest : this; +} + +template <class EntryType> +typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType* +RedeclarableTemplateDecl::findSpecializationImpl( + llvm::FoldingSet<EntryType> &Specs, + const TemplateArgument *Args, unsigned NumArgs, + void *&InsertPos) { + typedef SpecEntryTraits<EntryType> SETraits; + llvm::FoldingSetNodeID ID; + EntryType::Profile(ID,Args,NumArgs, getASTContext()); + EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); + return Entry ? SETraits::getMostRecentDeclaration(Entry) : 0; +} + +/// \brief Generate the injected template arguments for the given template +/// parameter list, e.g., for the injected-class-name of a class template. +static void GenerateInjectedTemplateArgs(ASTContext &Context, + TemplateParameterList *Params, + TemplateArgument *Args) { + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + TemplateArgument Arg; + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) { + QualType ArgType = Context.getTypeDeclType(TTP); + if (TTP->isParameterPack()) + ArgType = Context.getPackExpansionType(ArgType, + llvm::Optional<unsigned>()); + + Arg = TemplateArgument(ArgType); + } else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + Expr *E = new (Context) DeclRefExpr(NTTP, + NTTP->getType().getNonLValueExprType(Context), + Expr::getValueKindForType(NTTP->getType()), + NTTP->getLocation()); + + if (NTTP->isParameterPack()) + E = new (Context) PackExpansionExpr(Context.DependentTy, E, + NTTP->getLocation(), + llvm::Optional<unsigned>()); + Arg = TemplateArgument(E); + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); + if (TTP->isParameterPack()) + Arg = TemplateArgument(TemplateName(TTP), llvm::Optional<unsigned>()); + else + Arg = TemplateArgument(TemplateName(TTP)); + } + + if ((*Param)->isTemplateParameterPack()) + Arg = TemplateArgument::CreatePackCopy(Context, &Arg, 1); + + *Args++ = Arg; + } +} + +//===----------------------------------------------------------------------===// +// FunctionTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void FunctionTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl) { + AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); + return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); +} + +FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C, EmptyShell) { + return new (C) FunctionTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + +RedeclarableTemplateDecl::CommonBase * +FunctionTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +FunctionDecl * +FunctionTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void FunctionTemplateDecl::addSpecialization( + FunctionTemplateSpecializationInfo *Info, void *InsertPos) { + getSpecializations().InsertNode(Info, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, Info->Function); +} + +std::pair<const TemplateArgument *, unsigned> +FunctionTemplateDecl::getInjectedTemplateArgs() { + TemplateParameterList *Params = getTemplateParameters(); + Common *CommonPtr = getCommonPtr(); + if (!CommonPtr->InjectedArgs) { + CommonPtr->InjectedArgs + = new (getASTContext()) TemplateArgument [Params->size()]; + GenerateInjectedTemplateArgs(getASTContext(), Params, + CommonPtr->InjectedArgs); + } + + return std::make_pair(CommonPtr->InjectedArgs, Params->size()); +} + +//===----------------------------------------------------------------------===// +// ClassTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +void ClassTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} + +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl, + ClassTemplateDecl *PrevDecl) { + AdoptTemplateParameterList(Params, cast<DeclContext>(Decl)); + ClassTemplateDecl *New = new (C) ClassTemplateDecl(DC, L, Name, Params, Decl); + New->setPreviousDeclaration(PrevDecl); + return New; +} + +ClassTemplateDecl *ClassTemplateDecl::Create(ASTContext &C, EmptyShell Empty) { + return new (C) ClassTemplateDecl(Empty); +} + +void ClassTemplateDecl::LoadLazySpecializations() { + Common *CommonPtr = getCommonPtr(); + if (CommonPtr->LazySpecializations) { + ASTContext &Context = getASTContext(); + uint32_t *Specs = CommonPtr->LazySpecializations; + CommonPtr->LazySpecializations = 0; + for (uint32_t I = 0, N = *Specs++; I != N; ++I) + (void)Context.getExternalSource()->GetExternalDecl(Specs[I]); + } +} + +llvm::FoldingSet<ClassTemplateSpecializationDecl> & +ClassTemplateDecl::getSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->Specializations; +} + +llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> & +ClassTemplateDecl::getPartialSpecializations() { + LoadLazySpecializations(); + return getCommonPtr()->PartialSpecializations; +} + +RedeclarableTemplateDecl::CommonBase * +ClassTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + +ClassTemplateSpecializationDecl * +ClassTemplateDecl::findSpecialization(const TemplateArgument *Args, + unsigned NumArgs, void *&InsertPos) { + return findSpecializationImpl(getSpecializations(), Args, NumArgs, InsertPos); +} + +void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, + void *InsertPos) { + getSpecializations().InsertNode(D, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecialization(const TemplateArgument *Args, + unsigned NumArgs, + void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), Args, NumArgs, + InsertPos); +} + +void ClassTemplateDecl::AddPartialSpecialization( + ClassTemplatePartialSpecializationDecl *D, + void *InsertPos) { + getPartialSpecializations().InsertNode(D, InsertPos); + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(this, D); +} + +void ClassTemplateDecl::getPartialSpecializations( + llvm::SmallVectorImpl<ClassTemplatePartialSpecializationDecl *> &PS) { + llvm::FoldingSet<ClassTemplatePartialSpecializationDecl> &PartialSpecs + = getPartialSpecializations(); + PS.clear(); + PS.resize(PartialSpecs.size()); + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = PartialSpecs.begin(), PEnd = PartialSpecs.end(); + P != PEnd; ++P) { + assert(!PS[P->getSequenceNumber()]); + PS[P->getSequenceNumber()] = P->getMostRecentDeclaration(); + } +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecialization(QualType T) { + ASTContext &Context = getASTContext(); + typedef llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + partial_spec_iterator; + for (partial_spec_iterator P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (Context.hasSameType(P->getInjectedSpecializationType(), T)) + return P->getMostRecentDeclaration(); + } + + return 0; +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplateDecl::findPartialSpecInstantiatedFromMember( + ClassTemplatePartialSpecializationDecl *D) { + Decl *DCanon = D->getCanonicalDecl(); + for (llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>::iterator + P = getPartialSpecializations().begin(), + PEnd = getPartialSpecializations().end(); + P != PEnd; ++P) { + if (P->getInstantiatedFromMember()->getCanonicalDecl() == DCanon) + return P->getMostRecentDeclaration(); + } + + return 0; +} + +QualType +ClassTemplateDecl::getInjectedClassNameSpecialization() { + Common *CommonPtr = getCommonPtr(); + if (!CommonPtr->InjectedClassNameType.isNull()) + return CommonPtr->InjectedClassNameType; + + // C++0x [temp.dep.type]p2: + // The template argument list of a primary template is a template argument + // list in which the nth template argument has the value of the nth template + // parameter of the class template. If the nth template parameter is a + // template parameter pack (14.5.3), the nth template argument is a pack + // expansion (14.5.3) whose pattern is the name of the template parameter + // pack. + ASTContext &Context = getASTContext(); + TemplateParameterList *Params = getTemplateParameters(); + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + TemplateArgs.resize(Params->size()); + GenerateInjectedTemplateArgs(getASTContext(), Params, TemplateArgs.data()); + CommonPtr->InjectedClassNameType + = Context.getTemplateSpecializationType(TemplateName(this), + &TemplateArgs[0], + TemplateArgs.size()); + return CommonPtr->InjectedClassNameType; +} + +//===----------------------------------------------------------------------===// +// TemplateTypeParm Allocation/Deallocation Method Implementations +//===----------------------------------------------------------------------===// + +TemplateTypeParmDecl * +TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation KeyLoc, SourceLocation NameLoc, + unsigned D, unsigned P, IdentifierInfo *Id, + bool Typename, bool ParameterPack) { + TemplateTypeParmDecl *TTPDecl = + new (C) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename); + QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl); + TTPDecl->TypeForDecl = TTPType.getTypePtr(); + return TTPDecl; +} + +TemplateTypeParmDecl * +TemplateTypeParmDecl::Create(const ASTContext &C, EmptyShell Empty) { + return new (C) TemplateTypeParmDecl(0, SourceLocation(), SourceLocation(), + 0, false); +} + +SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { + return hasDefaultArgument() + ? DefaultArgument->getTypeLoc().getBeginLoc() + : SourceLocation(); +} + +SourceRange TemplateTypeParmDecl::getSourceRange() const { + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + return SourceRange(getLocStart(), + DefaultArgument->getTypeLoc().getEndLoc()); + else + return TypeDecl::getSourceRange(); +} + +unsigned TemplateTypeParmDecl::getDepth() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getDepth(); +} + +unsigned TemplateTypeParmDecl::getIndex() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->getIndex(); +} + +bool TemplateTypeParmDecl::isParameterPack() const { + return TypeForDecl->getAs<TemplateTypeParmType>()->isParameterPack(); +} + +//===----------------------------------------------------------------------===// +// NonTypeTemplateParmDecl Method Implementations +//===----------------------------------------------------------------------===// + +NonTypeTemplateParmDecl::NonTypeTemplateParmDecl(DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + unsigned D, unsigned P, + IdentifierInfo *Id, + QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos) + : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), + TemplateParmPosition(D, P), DefaultArgumentAndInherited(0, false), + ParameterPack(true), ExpandedParameterPack(true), + NumExpandedTypes(NumExpandedTypes) +{ + if (ExpandedTypes && ExpandedTInfos) { + void **TypesAndInfos = reinterpret_cast<void **>(this + 1); + for (unsigned I = 0; I != NumExpandedTypes; ++I) { + TypesAndInfos[2*I] = ExpandedTypes[I].getAsOpaquePtr(); + TypesAndInfos[2*I + 1] = ExpandedTInfos[I]; + } + } +} + +NonTypeTemplateParmDecl * +NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + unsigned D, unsigned P, IdentifierInfo *Id, + QualType T, bool ParameterPack, + TypeSourceInfo *TInfo) { + return new (C) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, D, P, Id, + T, ParameterPack, TInfo); +} + +NonTypeTemplateParmDecl * +NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + unsigned D, unsigned P, + IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, + const QualType *ExpandedTypes, + unsigned NumExpandedTypes, + TypeSourceInfo **ExpandedTInfos) { + unsigned Size = sizeof(NonTypeTemplateParmDecl) + + NumExpandedTypes * 2 * sizeof(void*); + void *Mem = C.Allocate(Size); + return new (Mem) NonTypeTemplateParmDecl(DC, StartLoc, IdLoc, + D, P, Id, T, TInfo, + ExpandedTypes, NumExpandedTypes, + ExpandedTInfos); +} + +SourceRange NonTypeTemplateParmDecl::getSourceRange() const { + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + return SourceRange(getOuterLocStart(), + getDefaultArgument()->getSourceRange().getEnd()); + return DeclaratorDecl::getSourceRange(); +} + +SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { + return hasDefaultArgument() + ? getDefaultArgument()->getSourceRange().getBegin() + : SourceLocation(); +} + +//===----------------------------------------------------------------------===// +// TemplateTemplateParmDecl Method Implementations +//===----------------------------------------------------------------------===// + +TemplateTemplateParmDecl * +TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + bool ParameterPack, IdentifierInfo *Id, + TemplateParameterList *Params) { + return new (C) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, + Params); +} + +//===----------------------------------------------------------------------===// +// TemplateArgumentList Implementation +//===----------------------------------------------------------------------===// +TemplateArgumentList * +TemplateArgumentList::CreateCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs) { + std::size_t Size = sizeof(TemplateArgumentList) + + NumArgs * sizeof(TemplateArgument); + void *Mem = Context.Allocate(Size); + TemplateArgument *StoredArgs + = reinterpret_cast<TemplateArgument *>( + static_cast<TemplateArgumentList *>(Mem) + 1); + std::uninitialized_copy(Args, Args + NumArgs, StoredArgs); + return new (Mem) TemplateArgumentList(StoredArgs, NumArgs, true); +} + +//===----------------------------------------------------------------------===// +// ClassTemplateSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ClassTemplateSpecializationDecl:: +ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, TagKind TK, + DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl) + : CXXRecordDecl(DK, TK, DC, StartLoc, IdLoc, + SpecializedTemplate->getIdentifier(), + PrevDecl), + SpecializedTemplate(SpecializedTemplate), + ExplicitInfo(0), + TemplateArgs(TemplateArgumentList::CreateCopy(Context, Args, NumArgs)), + SpecializationKind(TSK_Undeclared) { +} + +ClassTemplateSpecializationDecl::ClassTemplateSpecializationDecl(Kind DK) + : CXXRecordDecl(DK, TTK_Struct, 0, SourceLocation(), SourceLocation(), 0, 0), + ExplicitInfo(0), + SpecializationKind(TSK_Undeclared) { +} + +ClassTemplateSpecializationDecl * +ClassTemplateSpecializationDecl::Create(ASTContext &Context, TagKind TK, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + ClassTemplateSpecializationDecl *PrevDecl) { + ClassTemplateSpecializationDecl *Result + = new (Context)ClassTemplateSpecializationDecl(Context, + ClassTemplateSpecialization, + TK, DC, StartLoc, IdLoc, + SpecializedTemplate, + Args, NumArgs, + PrevDecl); + Context.getTypeDeclType(Result, PrevDecl); + return Result; +} + +ClassTemplateSpecializationDecl * +ClassTemplateSpecializationDecl::Create(ASTContext &Context, EmptyShell Empty) { + return + new (Context)ClassTemplateSpecializationDecl(ClassTemplateSpecialization); +} + +void +ClassTemplateSpecializationDecl::getNameForDiagnostic(std::string &S, + const PrintingPolicy &Policy, + bool Qualified) const { + NamedDecl::getNameForDiagnostic(S, Policy, Qualified); + + const TemplateArgumentList &TemplateArgs = getTemplateArgs(); + S += TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.data(), + TemplateArgs.size(), + Policy); +} + +ClassTemplateDecl * +ClassTemplateSpecializationDecl::getSpecializedTemplate() const { + if (SpecializedPartialSpecialization *PartialSpec + = SpecializedTemplate.dyn_cast<SpecializedPartialSpecialization*>()) + return PartialSpec->PartialSpecialization->getSpecializedTemplate(); + return SpecializedTemplate.get<ClassTemplateDecl*>(); +} + +SourceRange +ClassTemplateSpecializationDecl::getSourceRange() const { + if (!ExplicitInfo) + return SourceRange(); + SourceLocation Begin = getExternLoc(); + if (Begin.isInvalid()) + Begin = getTemplateKeywordLoc(); + SourceLocation End = getRBraceLoc(); + if (End.isInvalid()) + End = getTypeAsWritten()->getTypeLoc().getEndLoc(); + return SourceRange(Begin, End); +} + +//===----------------------------------------------------------------------===// +// ClassTemplatePartialSpecializationDecl Implementation +//===----------------------------------------------------------------------===// +ClassTemplatePartialSpecializationDecl:: +ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK, + DeclContext *DC, + SourceLocation StartLoc, + SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + TemplateArgumentLoc *ArgInfos, + unsigned NumArgInfos, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) + : ClassTemplateSpecializationDecl(Context, + ClassTemplatePartialSpecialization, + TK, DC, StartLoc, IdLoc, + SpecializedTemplate, + Args, NumArgs, PrevDecl), + TemplateParams(Params), ArgsAsWritten(ArgInfos), + NumArgsAsWritten(NumArgInfos), SequenceNumber(SequenceNumber), + InstantiatedFromMember(0, false) +{ + AdoptTemplateParameterList(Params, this); +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplatePartialSpecializationDecl:: +Create(ASTContext &Context, TagKind TK,DeclContext *DC, + SourceLocation StartLoc, SourceLocation IdLoc, + TemplateParameterList *Params, + ClassTemplateDecl *SpecializedTemplate, + const TemplateArgument *Args, + unsigned NumArgs, + const TemplateArgumentListInfo &ArgInfos, + QualType CanonInjectedType, + ClassTemplatePartialSpecializationDecl *PrevDecl, + unsigned SequenceNumber) { + unsigned N = ArgInfos.size(); + TemplateArgumentLoc *ClonedArgs = new (Context) TemplateArgumentLoc[N]; + for (unsigned I = 0; I != N; ++I) + ClonedArgs[I] = ArgInfos[I]; + + ClassTemplatePartialSpecializationDecl *Result + = new (Context)ClassTemplatePartialSpecializationDecl(Context, TK, DC, + StartLoc, IdLoc, + Params, + SpecializedTemplate, + Args, NumArgs, + ClonedArgs, N, + PrevDecl, + SequenceNumber); + Result->setSpecializationKind(TSK_ExplicitSpecialization); + + Context.getInjectedClassNameType(Result, CanonInjectedType); + return Result; +} + +ClassTemplatePartialSpecializationDecl * +ClassTemplatePartialSpecializationDecl::Create(ASTContext &Context, + EmptyShell Empty) { + return new (Context)ClassTemplatePartialSpecializationDecl(); +} + +//===----------------------------------------------------------------------===// +// FriendTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + DeclContext *DC, + SourceLocation L, + unsigned NParams, + TemplateParameterList **Params, + FriendUnion Friend, + SourceLocation FLoc) { + FriendTemplateDecl *Result + = new (Context) FriendTemplateDecl(DC, L, NParams, Params, Friend, FLoc); + return Result; +} + +FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, + EmptyShell Empty) { + return new (Context) FriendTemplateDecl(Empty); +} + +//===----------------------------------------------------------------------===// +// TypeAliasTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl) { + AdoptTemplateParameterList(Params, DC); + return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl); +} + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + EmptyShell) { + return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + +void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} +RedeclarableTemplateDecl::CommonBase * +TypeAliasTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + diff --git a/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp new file mode 100644 index 000000000000..cef54e97c93a --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DeclarationName.cpp @@ -0,0 +1,604 @@ +//===-- 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/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/Basic/IdentifierTable.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.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; +}; + +/// CXXLiberalOperatorName - Contains the actual identifier that makes up the +/// name. +/// +/// This identifier is stored here rather than directly in DeclarationName so as +/// to allow Objective-C selectors, which are about a million times more common, +/// to consume minimal memory. +class CXXLiteralOperatorIdName + : public DeclarationNameExtra, public llvm::FoldingSetNode { +public: + IdentifierInfo *ID; + + void Profile(llvm::FoldingSetNodeID &FSID) { + FSID.AddPointer(ID); + } +}; + +static int compareInt(unsigned A, unsigned B) { + return (A < B ? -1 : (A > B ? 1 : 0)); +} + +int DeclarationName::compare(DeclarationName LHS, DeclarationName RHS) { + if (LHS.getNameKind() != RHS.getNameKind()) + return (LHS.getNameKind() < RHS.getNameKind() ? -1 : 1); + + switch (LHS.getNameKind()) { + case DeclarationName::Identifier: { + IdentifierInfo *LII = LHS.getAsIdentifierInfo(); + IdentifierInfo *RII = RHS.getAsIdentifierInfo(); + if (!LII) return RII ? -1 : 0; + if (!RII) return 1; + + return LII->getName().compare(RII->getName()); + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: { + Selector LHSSelector = LHS.getObjCSelector(); + Selector RHSSelector = RHS.getObjCSelector(); + unsigned LN = LHSSelector.getNumArgs(), RN = RHSSelector.getNumArgs(); + for (unsigned I = 0, N = std::min(LN, RN); I != N; ++I) { + switch (LHSSelector.getNameForSlot(I).compare( + RHSSelector.getNameForSlot(I))) { + case -1: return true; + case 1: return false; + default: break; + } + } + + return compareInt(LN, RN); + } + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (QualTypeOrdering()(LHS.getCXXNameType(), RHS.getCXXNameType())) + return -1; + if (QualTypeOrdering()(RHS.getCXXNameType(), LHS.getCXXNameType())) + return 1; + return 0; + + case DeclarationName::CXXOperatorName: + return compareInt(LHS.getCXXOverloadedOperator(), + RHS.getCXXOverloadedOperator()); + + case DeclarationName::CXXLiteralOperatorName: + return LHS.getCXXLiteralIdentifier()->getName().compare( + RHS.getCXXLiteralIdentifier()->getName()); + + case DeclarationName::CXXUsingDirective: + return 0; + } + + return 0; +} + +} // end namespace clang + +DeclarationName::DeclarationName(Selector Sel) { + if (!Sel.getAsOpaquePtr()) { + Ptr = 0; + 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::CXXLiteralOperator: + return CXXLiteralOperatorName; + + 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; +} + +bool DeclarationName::isDependentName() const { + QualType T = getCXXNameType(); + return !T.isNull() && T->isDependentType(); +} + +std::string DeclarationName::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationName::printName(llvm::raw_ostream &OS) const { + switch (getNameKind()) { + case Identifier: + if (const IdentifierInfo *II = getAsIdentifierInfo()) + OS << II->getName(); + return; + + case ObjCZeroArgSelector: + case ObjCOneArgSelector: + case ObjCMultiArgSelector: + OS << getObjCSelector().getAsString(); + return; + + case CXXConstructorName: { + QualType ClassType = getCXXNameType(); + if (const RecordType *ClassRec = ClassType->getAs<RecordType>()) + OS << ClassRec->getDecl(); + else + OS << ClassType.getAsString(); + return; + } + + case CXXDestructorName: { + OS << '~'; + QualType Type = getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + OS << Rec->getDecl(); + else + OS << Type.getAsString(); + return; + } + + case CXXOperatorName: { + static const char* const 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"); + + OS << "operator"; + if (OpName[0] >= 'a' && OpName[0] <= 'z') + OS << ' '; + OS << OpName; + return; + } + + case CXXLiteralOperatorName: + OS << "operator \"\" " << getCXXLiteralIdentifier()->getName(); + return; + + case CXXConversionFunctionName: { + OS << "operator "; + QualType Type = getCXXNameType(); + if (const RecordType *Rec = Type->getAs<RecordType>()) + OS << Rec->getDecl(); + else + OS << Type.getAsString(); + return; + } + case CXXUsingDirective: + OS << "<using-directive>"; + return; + } + + assert(false && "Unexpected declaration name kind"); +} + +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; + } +} + +IdentifierInfo *DeclarationName::getCXXLiteralIdentifier() const { + if (CXXLiteralOperatorIdName *CXXLit = getAsCXXLiteralOperatorIdName()) + return CXXLit->ID; + else + return 0; +} + +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; + + case CXXLiteralOperatorName: + return getCXXLiteralIdentifier()->getFETokenInfo<void>(); + + 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; + + case CXXLiteralOperatorName: + getCXXLiteralIdentifier()->setFETokenInfo(T); + break; + + default: + assert(false && "Declaration name has no FETokenInfo"); + } +} + +DeclarationName DeclarationName::getUsingDirectiveName() { + // Single instance of DeclarationNameExtra for using-directive + static const DeclarationNameExtra UDirExtra = + { DeclarationNameExtra::CXXUsingDirective }; + + uintptr_t Ptr = reinterpret_cast<uintptr_t>(&UDirExtra); + Ptr |= StoredDeclarationNameExtra; + + return DeclarationName(Ptr); +} + +void DeclarationName::dump() const { + printName(llvm::errs()); + llvm::errs() << '\n'; +} + +DeclarationNameTable::DeclarationNameTable(const ASTContext &C) : Ctx(C) { + CXXSpecialNamesImpl = new llvm::FoldingSet<CXXSpecialName>; + CXXLiteralOperatorNames = new llvm::FoldingSet<CXXLiteralOperatorIdName>; + + // Initialize the overloaded operator names. + CXXOperatorNames = new (Ctx) 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> *SpecialNames = + static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + + delete SpecialNames; + delete LiteralNames; +} + +DeclarationName +DeclarationNameTable::getCXXSpecialName(DeclarationName::NameKind Kind, + CanQualType Ty) { + assert(Kind >= DeclarationName::CXXConstructorName && + Kind <= DeclarationName::CXXConversionFunctionName && + "Kind must be a C++ special name kind"); + llvm::FoldingSet<CXXSpecialName> *SpecialNames + = static_cast<llvm::FoldingSet<CXXSpecialName>*>(CXXSpecialNamesImpl); + + DeclarationNameExtra::ExtraKind EKind; + switch (Kind) { + case DeclarationName::CXXConstructorName: + EKind = DeclarationNameExtra::CXXConstructor; + assert(!Ty.hasQualifiers() &&"Constructor type must be unqualified"); + break; + case DeclarationName::CXXDestructorName: + EKind = DeclarationNameExtra::CXXDestructor; + assert(!Ty.hasQualifiers() && "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 (Ctx) 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]); +} + +DeclarationName +DeclarationNameTable::getCXXLiteralOperatorName(IdentifierInfo *II) { + llvm::FoldingSet<CXXLiteralOperatorIdName> *LiteralNames + = static_cast<llvm::FoldingSet<CXXLiteralOperatorIdName>*> + (CXXLiteralOperatorNames); + + llvm::FoldingSetNodeID ID; + ID.AddPointer(II); + + void *InsertPos = 0; + if (CXXLiteralOperatorIdName *Name = + LiteralNames->FindNodeOrInsertPos(ID, InsertPos)) + return DeclarationName (Name); + + CXXLiteralOperatorIdName *LiteralName = new (Ctx) CXXLiteralOperatorIdName; + LiteralName->ExtraKindOrNumArgs = DeclarationNameExtra::CXXLiteralOperator; + LiteralName->ID = II; + + LiteralNames->InsertNode(LiteralName, InsertPos); + return DeclarationName(LiteralName); +} + +unsigned +llvm::DenseMapInfo<clang::DeclarationName>:: +getHashValue(clang::DeclarationName N) { + return DenseMapInfo<void*>::getHashValue(N.getAsOpaquePtr()); +} + +DeclarationNameLoc::DeclarationNameLoc(DeclarationName Name) { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + break; + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + NamedType.TInfo = 0; + break; + case DeclarationName::CXXOperatorName: + CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); + CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); + break; + case DeclarationName::CXXLiteralOperatorName: + CXXLiteralOperatorName.OpNameLoc = SourceLocation().getRawEncoding(); + break; + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + // FIXME: ? + break; + case DeclarationName::CXXUsingDirective: + break; + } +} + +bool DeclarationNameInfo::containsUnexpandedParameterPack() const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + return false; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) + return TInfo->getType()->containsUnexpandedParameterPack(); + + return Name.getCXXNameType()->containsUnexpandedParameterPack(); + } + llvm_unreachable("All name kinds handled."); +} + +std::string DeclarationNameInfo::getAsString() const { + std::string Result; + llvm::raw_string_ostream OS(Result); + printName(OS); + return OS.str(); +} + +void DeclarationNameInfo::printName(llvm::raw_ostream &OS) const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXUsingDirective: + Name.printName(OS); + return; + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) { + if (Name.getNameKind() == DeclarationName::CXXDestructorName) + OS << '~'; + else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) + OS << "operator "; + OS << TInfo->getType().getAsString(); + } + else + Name.printName(OS); + return; + } + assert(false && "Unexpected declaration name kind"); +} + +SourceLocation DeclarationNameInfo::getEndLoc() const { + switch (Name.getNameKind()) { + case DeclarationName::Identifier: + return NameLoc; + + case DeclarationName::CXXOperatorName: { + unsigned raw = LocInfo.CXXOperatorName.EndOpNameLoc; + return SourceLocation::getFromRawEncoding(raw); + } + + case DeclarationName::CXXLiteralOperatorName: { + unsigned raw = LocInfo.CXXLiteralOperatorName.OpNameLoc; + return SourceLocation::getFromRawEncoding(raw); + } + + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXConversionFunctionName: + if (TypeSourceInfo *TInfo = LocInfo.NamedType.TInfo) + return TInfo->getTypeLoc().getEndLoc(); + else + return NameLoc; + + // DNInfo work in progress: FIXME. + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::CXXUsingDirective: + return NameLoc; + } + assert(false && "Unexpected declaration name kind"); + return SourceLocation(); +} diff --git a/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp new file mode 100644 index 000000000000..dfe0119f597d --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/DumpXML.cpp @@ -0,0 +1,1043 @@ +//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- 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 Decl::dumpXML() method, a debugging tool to +// print a detailed graph of an AST in an unspecified XML format. +// +// There is no guarantee of stability for this format. +// +//===----------------------------------------------------------------------===// + +// Only pay for this in code size in assertions-enabled builds. + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/StmtCXX.h" +#include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/TypeVisitor.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" + +using namespace clang; + +#ifndef NDEBUG + +namespace { + +enum NodeState { + NS_Attrs, NS_LazyChildren, NS_Children +}; + +struct Node { + llvm::StringRef Name; + NodeState State; + Node(llvm::StringRef name) : Name(name), State(NS_Attrs) {} + + bool isDoneWithAttrs() const { return State != NS_Attrs; } +}; + +template <class Impl> struct XMLDeclVisitor { +#define DISPATCH(NAME, CLASS) \ + static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) + + void dispatch(Decl *D) { + switch (D->getKind()) { + default: llvm_unreachable("Decl that isn't part of DeclNodes.inc!"); +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: \ + DISPATCH(dispatch##DERIVED##DeclAttrs, DERIVED##Decl); \ + static_cast<Impl*>(this)->completeAttrs(); \ + DISPATCH(dispatch##DERIVED##DeclChildren, DERIVED##Decl); \ + DISPATCH(dispatch##DERIVED##DeclAsContext, DERIVED##Decl); \ + break; +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" + } + } + +#define DECL(DERIVED, BASE) \ + void dispatch##DERIVED##DeclAttrs(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##Attrs, BASE); \ + DISPATCH(visit##DERIVED##DeclAttrs, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclAttrs(DERIVED##Decl *D) {} \ + void dispatch##DERIVED##DeclChildren(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##Children, BASE); \ + DISPATCH(visit##DERIVED##DeclChildren, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclChildren(DERIVED##Decl *D) {} \ + void dispatch##DERIVED##DeclAsContext(DERIVED##Decl *D) { \ + DISPATCH(dispatch##BASE##AsContext, BASE); \ + DISPATCH(visit##DERIVED##DeclAsContext, DERIVED##Decl); \ + } \ + void visit##DERIVED##DeclAsContext(DERIVED##Decl *D) {} +#include "clang/AST/DeclNodes.inc" + + void dispatchDeclAttrs(Decl *D) { + DISPATCH(visitDeclAttrs, Decl); + } + void visitDeclAttrs(Decl *D) {} + + void dispatchDeclChildren(Decl *D) { + DISPATCH(visitDeclChildren, Decl); + } + void visitDeclChildren(Decl *D) {} + + void dispatchDeclAsContext(Decl *D) { + DISPATCH(visitDeclAsContext, Decl); + } + void visitDeclAsContext(Decl *D) {} + +#undef DISPATCH +}; + +template <class Impl> struct XMLTypeVisitor { +#define DISPATCH(NAME, CLASS) \ + static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(T)) + + void dispatch(Type *T) { + switch (T->getTypeClass()) { + default: llvm_unreachable("Type that isn't part of TypeNodes.inc!"); +#define TYPE(DERIVED, BASE) \ + case Type::DERIVED: \ + DISPATCH(dispatch##DERIVED##TypeAttrs, DERIVED##Type); \ + static_cast<Impl*>(this)->completeAttrs(); \ + DISPATCH(dispatch##DERIVED##TypeChildren, DERIVED##Type); \ + break; +#define ABSTRACT_TYPE(DERIVED, BASE) +#include "clang/AST/TypeNodes.def" + } + } + +#define TYPE(DERIVED, BASE) \ + void dispatch##DERIVED##TypeAttrs(DERIVED##Type *T) { \ + DISPATCH(dispatch##BASE##Attrs, BASE); \ + DISPATCH(visit##DERIVED##TypeAttrs, DERIVED##Type); \ + } \ + void visit##DERIVED##TypeAttrs(DERIVED##Type *T) {} \ + void dispatch##DERIVED##TypeChildren(DERIVED##Type *T) { \ + DISPATCH(dispatch##BASE##Children, BASE); \ + DISPATCH(visit##DERIVED##TypeChildren, DERIVED##Type); \ + } \ + void visit##DERIVED##TypeChildren(DERIVED##Type *T) {} +#include "clang/AST/TypeNodes.def" + + void dispatchTypeAttrs(Type *T) { + DISPATCH(visitTypeAttrs, Type); + } + void visitTypeAttrs(Type *T) {} + + void dispatchTypeChildren(Type *T) { + DISPATCH(visitTypeChildren, Type); + } + void visitTypeChildren(Type *T) {} + +#undef DISPATCH +}; + +static llvm::StringRef getTypeKindName(Type *T) { + switch (T->getTypeClass()) { +#define TYPE(DERIVED, BASE) case Type::DERIVED: return #DERIVED "Type"; +#define ABSTRACT_TYPE(DERIVED, BASE) +#include "clang/AST/TypeNodes.def" + } + + llvm_unreachable("unknown type kind!"); + return "unknown_type"; +} + +struct XMLDumper : public XMLDeclVisitor<XMLDumper>, + public XMLTypeVisitor<XMLDumper> { + llvm::raw_ostream &out; + ASTContext &Context; + llvm::SmallVector<Node, 16> Stack; + unsigned Indent; + explicit XMLDumper(llvm::raw_ostream &OS, ASTContext &context) + : out(OS), Context(context), Indent(0) {} + + void indent() { + for (unsigned I = Indent; I; --I) + out << ' '; + } + + /// Push a new node on the stack. + void push(llvm::StringRef name) { + if (!Stack.empty()) { + assert(Stack.back().isDoneWithAttrs()); + if (Stack.back().State == NS_LazyChildren) { + Stack.back().State = NS_Children; + out << ">\n"; + } + Indent++; + indent(); + } + Stack.push_back(Node(name)); + out << '<' << name; + } + + /// Set the given attribute to the given value. + void set(llvm::StringRef attr, llvm::StringRef value) { + assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); + out << ' ' << attr << '=' << '"' << value << '"'; // TODO: quotation + } + + /// Finish attributes. + void completeAttrs() { + assert(!Stack.empty() && !Stack.back().isDoneWithAttrs()); + Stack.back().State = NS_LazyChildren; + } + + /// Pop a node. + void pop() { + assert(!Stack.empty() && Stack.back().isDoneWithAttrs()); + if (Stack.back().State == NS_LazyChildren) { + out << "/>\n"; + } else { + indent(); + out << "</" << Stack.back().Name << ">\n"; + } + if (Stack.size() > 1) Indent--; + Stack.pop_back(); + } + + //---- General utilities -------------------------------------------// + + void setPointer(llvm::StringRef prop, const void *p) { + llvm::SmallString<10> buffer; + llvm::raw_svector_ostream os(buffer); + os << p; + os.flush(); + set(prop, buffer); + } + + void setPointer(void *p) { + setPointer("ptr", p); + } + + void setInteger(llvm::StringRef prop, const llvm::APSInt &v) { + set(prop, v.toString(10)); + } + + void setInteger(llvm::StringRef prop, unsigned n) { + llvm::SmallString<10> buffer; + llvm::raw_svector_ostream os(buffer); + os << n; + os.flush(); + set(prop, buffer); + } + + void setFlag(llvm::StringRef prop, bool flag) { + if (flag) set(prop, "true"); + } + + void setName(DeclarationName Name) { + if (!Name) + return set("name", ""); + + // Common case. + if (Name.isIdentifier()) + return set("name", Name.getAsIdentifierInfo()->getName()); + + set("name", Name.getAsString()); + } + + class TemporaryContainer { + XMLDumper &Dumper; + public: + TemporaryContainer(XMLDumper &dumper, llvm::StringRef name) + : Dumper(dumper) { + Dumper.push(name); + Dumper.completeAttrs(); + } + + ~TemporaryContainer() { + Dumper.pop(); + } + }; + + void visitTemplateParameters(TemplateParameterList *L) { + push("template_parameters"); + completeAttrs(); + for (TemplateParameterList::iterator + I = L->begin(), E = L->end(); I != E; ++I) + dispatch(*I); + pop(); + } + + void visitTemplateArguments(const TemplateArgumentList &L) { + push("template_arguments"); + completeAttrs(); + for (unsigned I = 0, E = L.size(); I != E; ++I) + dispatch(L[I]); + pop(); + } + + /// Visits a reference to the given declaration. + void visitDeclRef(Decl *D) { + push(D->getDeclKindName()); + setPointer("ref", D); + completeAttrs(); + pop(); + } + void visitDeclRef(llvm::StringRef Name, Decl *D) { + TemporaryContainer C(*this, Name); + if (D) visitDeclRef(D); + } + + void dispatch(const TemplateArgument &A) { + switch (A.getKind()) { + case TemplateArgument::Null: { + TemporaryContainer C(*this, "null"); + break; + } + case TemplateArgument::Type: { + dispatch(A.getAsType()); + break; + } + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + // FIXME: Implement! + break; + + case TemplateArgument::Declaration: { + visitDeclRef(A.getAsDecl()); + break; + } + case TemplateArgument::Integral: { + push("integer"); + setInteger("value", *A.getAsIntegral()); + completeAttrs(); + pop(); + break; + } + case TemplateArgument::Expression: { + dispatch(A.getAsExpr()); + break; + } + case TemplateArgument::Pack: { + for (TemplateArgument::pack_iterator P = A.pack_begin(), + PEnd = A.pack_end(); + P != PEnd; ++P) + dispatch(*P); + break; + } + } + } + + void dispatch(const TemplateArgumentLoc &A) { + dispatch(A.getArgument()); + } + + //---- Declarations ------------------------------------------------// + // Calls are made in this order: + // # Enter a new node. + // push("FieldDecl") + // + // # In this phase, attributes are set on the node. + // visitDeclAttrs(D) + // visitNamedDeclAttrs(D) + // ... + // visitFieldDeclAttrs(D) + // + // # No more attributes after this point. + // completeAttrs() + // + // # Create "header" child nodes, i.e. those which logically + // # belong to the declaration itself. + // visitDeclChildren(D) + // visitNamedDeclChildren(D) + // ... + // visitFieldDeclChildren(D) + // + // # Create nodes for the lexical children. + // visitDeclAsContext(D) + // visitNamedDeclAsContext(D) + // ... + // visitFieldDeclAsContext(D) + // + // # Finish the node. + // pop(); + void dispatch(Decl *D) { + push(D->getDeclKindName()); + XMLDeclVisitor<XMLDumper>::dispatch(D); + pop(); + } + void visitDeclAttrs(Decl *D) { + setPointer(D); + } + + /// Visit all the lexical decls in the given context. + void visitDeclContext(DeclContext *DC) { + for (DeclContext::decl_iterator + I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) + dispatch(*I); + + // FIXME: point out visible declarations not in lexical context? + } + + /// Set the "access" attribute on the current node according to the + /// given specifier. + void setAccess(AccessSpecifier AS) { + switch (AS) { + case AS_public: return set("access", "public"); + case AS_protected: return set("access", "protected"); + case AS_private: return set("access", "private"); + case AS_none: llvm_unreachable("explicit forbidden access"); + } + } + + template <class T> void visitRedeclarableAttrs(T *D) { + if (T *Prev = D->getPreviousDeclaration()) + setPointer("previous", Prev); + } + + + // TranslationUnitDecl + void visitTranslationUnitDeclAsContext(TranslationUnitDecl *D) { + visitDeclContext(D); + } + + // LinkageSpecDecl + void visitLinkageSpecDeclAttrs(LinkageSpecDecl *D) { + llvm::StringRef lang = ""; + switch (D->getLanguage()) { + case LinkageSpecDecl::lang_c: lang = "C"; break; + case LinkageSpecDecl::lang_cxx: lang = "C++"; break; + } + set("lang", lang); + } + void visitLinkageSpecDeclAsContext(LinkageSpecDecl *D) { + visitDeclContext(D); + } + + // NamespaceDecl + void visitNamespaceDeclAttrs(NamespaceDecl *D) { + setFlag("inline", D->isInline()); + if (!D->isOriginalNamespace()) + setPointer("original", D->getOriginalNamespace()); + } + void visitNamespaceDeclAsContext(NamespaceDecl *D) { + visitDeclContext(D); + } + + // NamedDecl + void visitNamedDeclAttrs(NamedDecl *D) { + setName(D->getDeclName()); + } + + // ValueDecl + void visitValueDeclChildren(ValueDecl *D) { + dispatch(D->getType()); + } + + // DeclaratorDecl + void visitDeclaratorDeclChildren(DeclaratorDecl *D) { + //dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + + // VarDecl + void visitVarDeclAttrs(VarDecl *D) { + visitRedeclarableAttrs(D); + if (D->getStorageClass() != SC_None) + set("storage", + VarDecl::getStorageClassSpecifierString(D->getStorageClass())); + setFlag("directinit", D->hasCXXDirectInitializer()); + setFlag("nrvo", D->isNRVOVariable()); + // TODO: instantiation, etc. + } + void visitVarDeclChildren(VarDecl *D) { + if (D->hasInit()) dispatch(D->getInit()); + } + + // ParmVarDecl? + + // FunctionDecl + void visitFunctionDeclAttrs(FunctionDecl *D) { + visitRedeclarableAttrs(D); + setFlag("pure", D->isPure()); + setFlag("trivial", D->isTrivial()); + setFlag("returnzero", D->hasImplicitReturnZero()); + setFlag("prototype", D->hasWrittenPrototype()); + setFlag("deleted", D->isDeletedAsWritten()); + if (D->getStorageClass() != SC_None) + set("storage", + VarDecl::getStorageClassSpecifierString(D->getStorageClass())); + setFlag("inline", D->isInlineSpecified()); + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) + set("asmlabel", ALA->getLabel()); + // TODO: instantiation, etc. + } + void visitFunctionDeclChildren(FunctionDecl *D) { + for (FunctionDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + if (D->doesThisDeclarationHaveABody()) + dispatch(D->getBody()); + } + + // CXXMethodDecl ? + // CXXConstructorDecl ? + // CXXDestructorDecl ? + // CXXConversionDecl ? + + void dispatch(CXXCtorInitializer *Init) { + // TODO + } + + // FieldDecl + void visitFieldDeclAttrs(FieldDecl *D) { + setFlag("mutable", D->isMutable()); + } + void visitFieldDeclChildren(FieldDecl *D) { + if (D->isBitField()) { + TemporaryContainer C(*this, "bitwidth"); + dispatch(D->getBitWidth()); + } + // TODO: C++0x member initializer + } + + // EnumConstantDecl + void visitEnumConstantDeclChildren(EnumConstantDecl *D) { + // value in any case? + if (D->getInitExpr()) dispatch(D->getInitExpr()); + } + + // IndirectFieldDecl + void visitIndirectFieldDeclChildren(IndirectFieldDecl *D) { + for (IndirectFieldDecl::chain_iterator + I = D->chain_begin(), E = D->chain_end(); I != E; ++I) { + NamedDecl *VD = const_cast<NamedDecl*>(*I); + push(isa<VarDecl>(VD) ? "variable" : "field"); + setPointer("ptr", VD); + completeAttrs(); + pop(); + } + } + + // TypeDecl + void visitTypeDeclAttrs(TypeDecl *D) { + setPointer("typeptr", D->getTypeForDecl()); + } + + // TypedefDecl + void visitTypedefDeclAttrs(TypedefDecl *D) { + visitRedeclarableAttrs<TypedefNameDecl>(D); + } + void visitTypedefDeclChildren(TypedefDecl *D) { + dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + + // TypeAliasDecl + void visitTypeAliasDeclAttrs(TypeAliasDecl *D) { + visitRedeclarableAttrs<TypedefNameDecl>(D); + } + void visitTypeAliasDeclChildren(TypeAliasDecl *D) { + dispatch(D->getTypeSourceInfo()->getTypeLoc()); + } + + // TagDecl + void visitTagDeclAttrs(TagDecl *D) { + visitRedeclarableAttrs(D); + } + void visitTagDeclAsContext(TagDecl *D) { + visitDeclContext(D); + } + + // EnumDecl + void visitEnumDeclAttrs(EnumDecl *D) { + setFlag("scoped", D->isScoped()); + setFlag("fixed", D->isFixed()); + } + void visitEnumDeclChildren(EnumDecl *D) { + { + TemporaryContainer C(*this, "promotion_type"); + dispatch(D->getPromotionType()); + } + { + TemporaryContainer C(*this, "integer_type"); + dispatch(D->getIntegerType()); + } + } + + // RecordDecl ? + + void visitCXXRecordDeclChildren(CXXRecordDecl *D) { + if (!D->isThisDeclarationADefinition()) return; + + for (CXXRecordDecl::base_class_iterator + I = D->bases_begin(), E = D->bases_end(); I != E; ++I) { + push("base"); + setAccess(I->getAccessSpecifier()); + completeAttrs(); + dispatch(I->getTypeSourceInfo()->getTypeLoc()); + pop(); + } + } + + // ClassTemplateSpecializationDecl ? + + // FileScopeAsmDecl ? + + // BlockDecl + void visitBlockDeclAttrs(BlockDecl *D) { + setFlag("variadic", D->isVariadic()); + } + void visitBlockDeclChildren(BlockDecl *D) { + for (FunctionDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + dispatch(D->getBody()); + } + + // AccessSpecDecl + void visitAccessSpecDeclAttrs(AccessSpecDecl *D) { + setAccess(D->getAccess()); + } + + // TemplateDecl + void visitTemplateDeclChildren(TemplateDecl *D) { + visitTemplateParameters(D->getTemplateParameters()); + if (D->getTemplatedDecl()) + dispatch(D->getTemplatedDecl()); + } + + // FunctionTemplateDecl + void visitFunctionTemplateDeclAttrs(FunctionTemplateDecl *D) { + visitRedeclarableAttrs(D); + } + void visitFunctionTemplateDeclChildren(FunctionTemplateDecl *D) { + // Mention all the specializations which don't have explicit + // declarations elsewhere. + for (FunctionTemplateDecl::spec_iterator + I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { + FunctionTemplateSpecializationInfo *Info + = I->getTemplateSpecializationInfo(); + + bool Unknown = false; + switch (Info->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: Unknown = false; break; + case TSK_Undeclared: Unknown = true; break; + + // These will be covered at their respective sites. + case TSK_ExplicitSpecialization: continue; + case TSK_ExplicitInstantiationDeclaration: continue; + case TSK_ExplicitInstantiationDefinition: continue; + } + + TemporaryContainer C(*this, + Unknown ? "uninstantiated" : "instantiation"); + visitTemplateArguments(*Info->TemplateArguments); + dispatch(Info->Function); + } + } + + // ClasTemplateDecl + void visitClassTemplateDeclAttrs(ClassTemplateDecl *D) { + visitRedeclarableAttrs(D); + } + void visitClassTemplateDeclChildren(ClassTemplateDecl *D) { + // Mention all the specializations which don't have explicit + // declarations elsewhere. + for (ClassTemplateDecl::spec_iterator + I = D->spec_begin(), E = D->spec_end(); I != E; ++I) { + + bool Unknown = false; + switch (I->getTemplateSpecializationKind()) { + case TSK_ImplicitInstantiation: Unknown = false; break; + case TSK_Undeclared: Unknown = true; break; + + // These will be covered at their respective sites. + case TSK_ExplicitSpecialization: continue; + case TSK_ExplicitInstantiationDeclaration: continue; + case TSK_ExplicitInstantiationDefinition: continue; + } + + TemporaryContainer C(*this, + Unknown ? "uninstantiated" : "instantiation"); + visitTemplateArguments(I->getTemplateArgs()); + dispatch(*I); + } + } + + // TemplateTypeParmDecl + void visitTemplateTypeParmDeclAttrs(TemplateTypeParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitTemplateTypeParmDeclChildren(TemplateTypeParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgumentInfo()->getTypeLoc()); + // parameter pack? + } + + // NonTypeTemplateParmDecl + void visitNonTypeTemplateParmDeclAttrs(NonTypeTemplateParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitNonTypeTemplateParmDeclChildren(NonTypeTemplateParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgument()); + // parameter pack? + } + + // TemplateTemplateParmDecl + void visitTemplateTemplateParmDeclAttrs(TemplateTemplateParmDecl *D) { + setInteger("depth", D->getDepth()); + setInteger("index", D->getIndex()); + } + void visitTemplateTemplateParmDeclChildren(TemplateTemplateParmDecl *D) { + if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) + dispatch(D->getDefaultArgument()); + // parameter pack? + } + + // FriendDecl + void visitFriendDeclChildren(FriendDecl *D) { + if (TypeSourceInfo *T = D->getFriendType()) + dispatch(T->getTypeLoc()); + else + dispatch(D->getFriendDecl()); + } + + // UsingDirectiveDecl ? + // UsingDecl ? + // UsingShadowDecl ? + // NamespaceAliasDecl ? + // UnresolvedUsingValueDecl ? + // UnresolvedUsingTypenameDecl ? + // StaticAssertDecl ? + + // ObjCImplDecl + void visitObjCImplDeclChildren(ObjCImplDecl *D) { + visitDeclRef(D->getClassInterface()); + } + void visitObjCImplDeclAsContext(ObjCImplDecl *D) { + visitDeclContext(D); + } + + // ObjCClassDecl + void visitObjCClassDeclChildren(ObjCClassDecl *D) { + for (ObjCClassDecl::iterator I = D->begin(), E = D->end(); I != E; ++I) + visitDeclRef(I->getInterface()); + } + + // ObjCInterfaceDecl + void visitCategoryList(ObjCCategoryDecl *D) { + if (!D) return; + + TemporaryContainer C(*this, "categories"); + for (; D; D = D->getNextClassCategory()) + visitDeclRef(D); + } + void visitObjCInterfaceDeclAttrs(ObjCInterfaceDecl *D) { + setPointer("typeptr", D->getTypeForDecl()); + setFlag("forward_decl", D->isForwardDecl()); + setFlag("implicit_interface", D->isImplicitInterfaceDecl()); + } + void visitObjCInterfaceDeclChildren(ObjCInterfaceDecl *D) { + visitDeclRef("super", D->getSuperClass()); + visitDeclRef("implementation", D->getImplementation()); + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCInterfaceDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + visitCategoryList(D->getCategoryList()); + } + void visitObjCInterfaceDeclAsContext(ObjCInterfaceDecl *D) { + visitDeclContext(D); + } + + // ObjCCategoryDecl + void visitObjCCategoryDeclAttrs(ObjCCategoryDecl *D) { + setFlag("extension", D->IsClassExtension()); + setFlag("synth_bitfield", D->hasSynthBitfield()); + } + void visitObjCCategoryDeclChildren(ObjCCategoryDecl *D) { + visitDeclRef("interface", D->getClassInterface()); + visitDeclRef("implementation", D->getImplementation()); + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCCategoryDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + } + void visitObjCCategoryDeclAsContext(ObjCCategoryDecl *D) { + visitDeclContext(D); + } + + // ObjCCategoryImplDecl + void visitObjCCategoryImplDeclAttrs(ObjCCategoryImplDecl *D) { + set("identifier", D->getName()); + } + void visitObjCCategoryImplDeclChildren(ObjCCategoryImplDecl *D) { + visitDeclRef(D->getCategoryDecl()); + } + + // ObjCImplementationDecl + void visitObjCImplementationDeclAttrs(ObjCImplementationDecl *D) { + setFlag("synth_bitfield", D->hasSynthBitfield()); + set("identifier", D->getName()); + } + void visitObjCImplementationDeclChildren(ObjCImplementationDecl *D) { + visitDeclRef("super", D->getSuperClass()); + if (D->init_begin() != D->init_end()) { + TemporaryContainer C(*this, "initializers"); + for (ObjCImplementationDecl::init_iterator + I = D->init_begin(), E = D->init_end(); I != E; ++I) + dispatch(*I); + } + } + + // ObjCForwardProtocolDecl + void visitObjCForwardProtocolDeclChildren(ObjCForwardProtocolDecl *D) { + for (ObjCForwardProtocolDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + + // ObjCProtocolDecl + void visitObjCProtocolDeclAttrs(ObjCProtocolDecl *D) { + setFlag("forward_decl", D->isForwardDecl()); + } + void visitObjCProtocolDeclChildren(ObjCProtocolDecl *D) { + if (D->protocol_begin() != D->protocol_end()) { + TemporaryContainer C(*this, "protocols"); + for (ObjCInterfaceDecl::protocol_iterator + I = D->protocol_begin(), E = D->protocol_end(); I != E; ++I) + visitDeclRef(*I); + } + } + void visitObjCProtocolDeclAsContext(ObjCProtocolDecl *D) { + visitDeclContext(D); + } + + // ObjCMethodDecl + void visitObjCMethodDeclAttrs(ObjCMethodDecl *D) { + // decl qualifier? + // implementation control? + + setFlag("instance", D->isInstanceMethod()); + setFlag("variadic", D->isVariadic()); + setFlag("synthesized", D->isSynthesized()); + setFlag("defined", D->isDefined()); + setFlag("related_result_type", D->hasRelatedResultType()); + } + void visitObjCMethodDeclChildren(ObjCMethodDecl *D) { + dispatch(D->getResultType()); + for (ObjCMethodDecl::param_iterator + I = D->param_begin(), E = D->param_end(); I != E; ++I) + dispatch(*I); + if (D->isThisDeclarationADefinition()) + dispatch(D->getBody()); + } + + // ObjCIvarDecl + void setAccessControl(llvm::StringRef prop, ObjCIvarDecl::AccessControl AC) { + switch (AC) { + case ObjCIvarDecl::None: return set(prop, "none"); + case ObjCIvarDecl::Private: return set(prop, "private"); + case ObjCIvarDecl::Protected: return set(prop, "protected"); + case ObjCIvarDecl::Public: return set(prop, "public"); + case ObjCIvarDecl::Package: return set(prop, "package"); + } + } + void visitObjCIvarDeclAttrs(ObjCIvarDecl *D) { + setFlag("synthesize", D->getSynthesize()); + setAccessControl("access", D->getAccessControl()); + } + + // ObjCCompatibleAliasDecl + void visitObjCCompatibleAliasDeclChildren(ObjCCompatibleAliasDecl *D) { + visitDeclRef(D->getClassInterface()); + } + + // FIXME: ObjCPropertyDecl + // FIXME: ObjCPropertyImplDecl + + //---- Types -----------------------------------------------------// + void dispatch(TypeLoc TL) { + dispatch(TL.getType()); // for now + } + + void dispatch(QualType T) { + if (T.hasLocalQualifiers()) { + push("QualType"); + Qualifiers Qs = T.getLocalQualifiers(); + setFlag("const", Qs.hasConst()); + setFlag("volatile", Qs.hasVolatile()); + setFlag("restrict", Qs.hasRestrict()); + if (Qs.hasAddressSpace()) setInteger("addrspace", Qs.getAddressSpace()); + if (Qs.hasObjCGCAttr()) { + switch (Qs.getObjCGCAttr()) { + case Qualifiers::Weak: set("gc", "weak"); break; + case Qualifiers::Strong: set("gc", "strong"); break; + case Qualifiers::GCNone: llvm_unreachable("explicit none"); + } + } + + completeAttrs(); + dispatch(QualType(T.getTypePtr(), 0)); + pop(); + return; + } + + Type *Ty = const_cast<Type*>(T.getTypePtr()); + push(getTypeKindName(Ty)); + XMLTypeVisitor<XMLDumper>::dispatch(const_cast<Type*>(T.getTypePtr())); + pop(); + } + + void setCallingConv(CallingConv CC) { + switch (CC) { + case CC_Default: return; + case CC_C: return set("cc", "cdecl"); + case CC_X86FastCall: return set("cc", "x86_fastcall"); + case CC_X86StdCall: return set("cc", "x86_stdcall"); + case CC_X86ThisCall: return set("cc", "x86_thiscall"); + case CC_X86Pascal: return set("cc", "x86_pascal"); + case CC_AAPCS: return set("cc", "aapcs"); + case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); + } + } + + void visitTypeAttrs(Type *D) { + setPointer(D); + setFlag("dependent", D->isDependentType()); + setFlag("variably_modified", D->isVariablyModifiedType()); + + setPointer("canonical", D->getCanonicalTypeInternal().getAsOpaquePtr()); + } + + void visitPointerTypeChildren(PointerType *T) { + dispatch(T->getPointeeType()); + } + void visitReferenceTypeChildren(ReferenceType *T) { + dispatch(T->getPointeeType()); + } + void visitObjCObjectPointerTypeChildren(ObjCObjectPointerType *T) { + dispatch(T->getPointeeType()); + } + void visitBlockPointerTypeChildren(BlockPointerType *T) { + dispatch(T->getPointeeType()); + } + + // Types that just wrap declarations. + void visitTagTypeChildren(TagType *T) { + visitDeclRef(T->getDecl()); + } + void visitTypedefTypeChildren(TypedefType *T) { + visitDeclRef(T->getDecl()); + } + void visitObjCInterfaceTypeChildren(ObjCInterfaceType *T) { + visitDeclRef(T->getDecl()); + } + void visitUnresolvedUsingTypeChildren(UnresolvedUsingType *T) { + visitDeclRef(T->getDecl()); + } + void visitInjectedClassNameTypeChildren(InjectedClassNameType *T) { + visitDeclRef(T->getDecl()); + } + + void visitFunctionTypeAttrs(FunctionType *T) { + setFlag("noreturn", T->getNoReturnAttr()); + setCallingConv(T->getCallConv()); + if (T->getHasRegParm()) setInteger("regparm", T->getRegParmType()); + } + void visitFunctionTypeChildren(FunctionType *T) { + dispatch(T->getResultType()); + } + + void visitFunctionProtoTypeAttrs(FunctionProtoType *T) { + setFlag("const", T->getTypeQuals() & Qualifiers::Const); + setFlag("volatile", T->getTypeQuals() & Qualifiers::Volatile); + setFlag("restrict", T->getTypeQuals() & Qualifiers::Restrict); + } + void visitFunctionProtoTypeChildren(FunctionProtoType *T) { + push("parameters"); + setFlag("variadic", T->isVariadic()); + completeAttrs(); + for (FunctionProtoType::arg_type_iterator + I = T->arg_type_begin(), E = T->arg_type_end(); I != E; ++I) + dispatch(*I); + pop(); + + if (T->hasDynamicExceptionSpec()) { + push("exception_specifiers"); + setFlag("any", T->getExceptionSpecType() == EST_MSAny); + completeAttrs(); + for (FunctionProtoType::exception_iterator + I = T->exception_begin(), E = T->exception_end(); I != E; ++I) + dispatch(*I); + pop(); + } + // FIXME: noexcept specifier + } + + void visitTemplateSpecializationTypeChildren(TemplateSpecializationType *T) { + if (const RecordType *RT = T->getAs<RecordType>()) + visitDeclRef(RT->getDecl()); + + // TODO: TemplateName + + push("template_arguments"); + completeAttrs(); + for (unsigned I = 0, E = T->getNumArgs(); I != E; ++I) + dispatch(T->getArg(I)); + pop(); + } + + //---- Statements ------------------------------------------------// + void dispatch(Stmt *S) { + // FIXME: this is not really XML at all + push("Stmt"); + out << ">\n"; + Stack.back().State = NS_Children; // explicitly become non-lazy + S->dump(out, Context.getSourceManager()); + out << '\n'; + pop(); + } +}; +} + +void Decl::dumpXML() const { + dumpXML(llvm::errs()); +} + +void Decl::dumpXML(llvm::raw_ostream &out) const { + XMLDumper(out, getASTContext()).dispatch(const_cast<Decl*>(this)); +} + +#else /* ifndef NDEBUG */ + +void Decl::dumpXML() const {} +void Decl::dumpXML(llvm::raw_ostream &out) const {} + +#endif diff --git a/contrib/llvm/tools/clang/lib/AST/Expr.cpp b/contrib/llvm/tools/clang/lib/AST/Expr.cpp new file mode 100644 index 000000000000..987213907e45 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Expr.cpp @@ -0,0 +1,3045 @@ +//===--- 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/ExprCXX.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/Lex/LiteralSupport.h" +#include "clang/Lex/Lexer.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +using namespace clang; + +/// isKnownToHaveBooleanValue - Return true if this is an integer expression +/// that is known to return 0 or 1. This happens for _Bool/bool expressions +/// but also int expressions which are produced by things like comparisons in +/// C. +bool Expr::isKnownToHaveBooleanValue() const { + const Expr *E = IgnoreParens(); + + // If this value has _Bool type, it is obvious 0/1. + if (E->getType()->isBooleanType()) return true; + // If this is a non-scalar-integer type, we don't care enough to try. + if (!E->getType()->isIntegralOrEnumerationType()) return false; + + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + switch (UO->getOpcode()) { + case UO_Plus: + return UO->getSubExpr()->isKnownToHaveBooleanValue(); + default: + return false; + } + } + + // Only look through implicit casts. If the user writes + // '(int) (a && b)' treat it as an arbitrary int. + if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) + return CE->getSubExpr()->isKnownToHaveBooleanValue(); + + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + switch (BO->getOpcode()) { + default: return false; + case BO_LT: // Relational operators. + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: // Equality operators. + case BO_NE: + case BO_LAnd: // AND operator. + case BO_LOr: // Logical OR operator. + return true; + + case BO_And: // Bitwise AND operator. + case BO_Xor: // Bitwise XOR operator. + case BO_Or: // Bitwise OR operator. + // Handle things like (x==2)|(y==12). + return BO->getLHS()->isKnownToHaveBooleanValue() && + BO->getRHS()->isKnownToHaveBooleanValue(); + + case BO_Comma: + case BO_Assign: + return BO->getRHS()->isKnownToHaveBooleanValue(); + } + } + + if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) + return CO->getTrueExpr()->isKnownToHaveBooleanValue() && + CO->getFalseExpr()->isKnownToHaveBooleanValue(); + + return false; +} + +// Amusing macro metaprogramming hack: check whether a class provides +// a more specific implementation of getExprLoc(). +namespace { + /// This implementation is used when a class provides a custom + /// implementation of getExprLoc. + template <class E, class T> + SourceLocation getExprLocImpl(const Expr *expr, + SourceLocation (T::*v)() const) { + return static_cast<const E*>(expr)->getExprLoc(); + } + + /// This implementation is used when a class doesn't provide + /// a custom implementation of getExprLoc. Overload resolution + /// should pick it over the implementation above because it's + /// more specialized according to function template partial ordering. + template <class E> + SourceLocation getExprLocImpl(const Expr *expr, + SourceLocation (Expr::*v)() const) { + return static_cast<const E*>(expr)->getSourceRange().getBegin(); + } +} + +SourceLocation Expr::getExprLoc() const { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: llvm_unreachable(#type " is not an Expr"); break; +#define EXPR(type, base) \ + case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind"); + return SourceLocation(); +} + +//===----------------------------------------------------------------------===// +// Primary Expressions. +//===----------------------------------------------------------------------===// + +void ExplicitTemplateArgumentList::initializeFrom( + const TemplateArgumentListInfo &Info) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); +} + +void ExplicitTemplateArgumentList::initializeFrom( + const TemplateArgumentListInfo &Info, + bool &Dependent, + bool &ContainsUnexpandedParameterPack) { + LAngleLoc = Info.getLAngleLoc(); + RAngleLoc = Info.getRAngleLoc(); + NumTemplateArgs = Info.size(); + + TemplateArgumentLoc *ArgBuffer = getTemplateArgs(); + for (unsigned i = 0; i != NumTemplateArgs; ++i) { + Dependent = Dependent || Info[i].getArgument().isDependent(); + ContainsUnexpandedParameterPack + = ContainsUnexpandedParameterPack || + Info[i].getArgument().containsUnexpandedParameterPack(); + + new (&ArgBuffer[i]) TemplateArgumentLoc(Info[i]); + } +} + +void ExplicitTemplateArgumentList::copyInto( + TemplateArgumentListInfo &Info) const { + Info.setLAngleLoc(LAngleLoc); + Info.setRAngleLoc(RAngleLoc); + for (unsigned I = 0; I != NumTemplateArgs; ++I) + Info.addArgument(getTemplateArgs()[I]); +} + +std::size_t ExplicitTemplateArgumentList::sizeFor(unsigned NumTemplateArgs) { + return sizeof(ExplicitTemplateArgumentList) + + sizeof(TemplateArgumentLoc) * NumTemplateArgs; +} + +std::size_t ExplicitTemplateArgumentList::sizeFor( + const TemplateArgumentListInfo &Info) { + return sizeFor(Info.size()); +} + +/// \brief Compute the type- and value-dependence of a declaration reference +/// based on the declaration being referenced. +static void computeDeclRefDependence(NamedDecl *D, QualType T, + bool &TypeDependent, + bool &ValueDependent) { + TypeDependent = false; + ValueDependent = false; + + + // (TD) C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // + // and + // + // (VD) C++ [temp.dep.constexpr]p2: + // An identifier is value-dependent if it is: + + // (TD) - an identifier that was declared with dependent type + // (VD) - a name declared with a dependent type, + if (T->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + return; + } + + // (TD) - a conversion-function-id that specifies a dependent type + if (D->getDeclName().getNameKind() + == DeclarationName::CXXConversionFunctionName && + D->getDeclName().getCXXNameType()->isDependentType()) { + TypeDependent = true; + ValueDependent = true; + return; + } + // (VD) - the name of a non-type template parameter, + if (isa<NonTypeTemplateParmDecl>(D)) { + ValueDependent = true; + return; + } + + // (VD) - a constant with integral or enumeration type and is + // initialized with an expression that is value-dependent. + if (VarDecl *Var = dyn_cast<VarDecl>(D)) { + if (Var->getType()->isIntegralOrEnumerationType() && + Var->getType().getCVRQualifiers() == Qualifiers::Const) { + if (const Expr *Init = Var->getAnyInitializer()) + if (Init->isValueDependent()) + ValueDependent = true; + } + + // (VD) - FIXME: Missing from the standard: + // - a member function or a static data member of the current + // instantiation + else if (Var->isStaticDataMember() && + Var->getDeclContext()->isDependentContext()) + ValueDependent = true; + + return; + } + + // (VD) - FIXME: Missing from the standard: + // - a member function or a static data member of the current + // instantiation + if (isa<CXXMethodDecl>(D) && D->getDeclContext()->isDependentContext()) { + ValueDependent = true; + return; + } +} + +void DeclRefExpr::computeDependence() { + bool TypeDependent = false; + bool ValueDependent = false; + computeDeclRefDependence(getDecl(), getType(), TypeDependent, ValueDependent); + + // (TD) C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains: + // + // and + // + // (VD) C++ [temp.dep.constexpr]p2: + // An identifier is value-dependent if it is: + if (!TypeDependent && !ValueDependent && + hasExplicitTemplateArgs() && + TemplateSpecializationType::anyDependentTemplateArguments( + getTemplateArgs(), + getNumTemplateArgs())) { + TypeDependent = true; + ValueDependent = true; + } + + ExprBits.TypeDependent = TypeDependent; + ExprBits.ValueDependent = ValueDependent; + + // Is the declaration a parameter pack? + if (getDecl()->isParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; +} + +DeclRefExpr::DeclRefExpr(NestedNameSpecifierLoc QualifierLoc, + ValueDecl *D, const DeclarationNameInfo &NameInfo, + NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs, + QualType T, ExprValueKind VK) + : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false), + D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { + DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0; + if (QualifierLoc) + getInternalQualifierLoc() = QualifierLoc; + DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0; + if (FoundD) + getInternalFoundDecl() = FoundD; + DeclRefExprBits.HasExplicitTemplateArgs = TemplateArgs ? 1 : 0; + if (TemplateArgs) + getExplicitTemplateArgs().initializeFrom(*TemplateArgs); + + computeDependence(); +} + +DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, + NestedNameSpecifierLoc QualifierLoc, + ValueDecl *D, + SourceLocation NameLoc, + QualType T, + ExprValueKind VK, + NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs) { + return Create(Context, QualifierLoc, D, + DeclarationNameInfo(D->getDeclName(), NameLoc), + T, VK, FoundD, TemplateArgs); +} + +DeclRefExpr *DeclRefExpr::Create(ASTContext &Context, + NestedNameSpecifierLoc QualifierLoc, + ValueDecl *D, + const DeclarationNameInfo &NameInfo, + QualType T, + ExprValueKind VK, + NamedDecl *FoundD, + const TemplateArgumentListInfo *TemplateArgs) { + // Filter out cases where the found Decl is the same as the value refenenced. + if (D == FoundD) + FoundD = 0; + + std::size_t Size = sizeof(DeclRefExpr); + if (QualifierLoc != 0) + Size += sizeof(NestedNameSpecifierLoc); + if (FoundD) + Size += sizeof(NamedDecl *); + if (TemplateArgs) + Size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); + return new (Mem) DeclRefExpr(QualifierLoc, D, NameInfo, FoundD, TemplateArgs, + T, VK); +} + +DeclRefExpr *DeclRefExpr::CreateEmpty(ASTContext &Context, + bool HasQualifier, + bool HasFoundDecl, + bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { + std::size_t Size = sizeof(DeclRefExpr); + if (HasQualifier) + Size += sizeof(NestedNameSpecifierLoc); + if (HasFoundDecl) + Size += sizeof(NamedDecl *); + if (HasExplicitTemplateArgs) + Size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + + void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); + return new (Mem) DeclRefExpr(EmptyShell()); +} + +SourceRange DeclRefExpr::getSourceRange() const { + SourceRange R = getNameInfo().getSourceRange(); + if (hasQualifier()) + R.setBegin(getQualifierLoc().getBeginLoc()); + if (hasExplicitTemplateArgs()) + R.setEnd(getRAngleLoc()); + return R; +} + +// FIXME: Maybe this should use DeclPrinter with a special "print predefined +// expr" policy instead. +std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { + ASTContext &Context = CurrentDecl->getASTContext(); + + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { + if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual) + return FD->getNameAsString(); + + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); + + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isVirtual() && IT != PrettyFunctionNoVirtual) + Out << "virtual "; + if (MD->isStatic()) + Out << "static "; + } + + PrintingPolicy Policy(Context.getLangOptions()); + + std::string Proto = FD->getQualifiedNameAsString(Policy); + + const FunctionType *AFT = FD->getType()->getAs<FunctionType>(); + const FunctionProtoType *FT = 0; + if (FD->hasWrittenPrototype()) + FT = dyn_cast<FunctionProtoType>(AFT); + + Proto += "("; + if (FT) { + llvm::raw_string_ostream POut(Proto); + for (unsigned i = 0, e = FD->getNumParams(); i != e; ++i) { + if (i) POut << ", "; + std::string Param; + FD->getParamDecl(i)->getType().getAsStringInternal(Param, Policy); + POut << Param; + } + + if (FT->isVariadic()) { + if (FD->getNumParams()) POut << ", "; + POut << "..."; + } + } + Proto += ")"; + + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + Qualifiers ThisQuals = Qualifiers::fromCVRMask(MD->getTypeQualifiers()); + if (ThisQuals.hasConst()) + Proto += " const"; + if (ThisQuals.hasVolatile()) + Proto += " volatile"; + } + + if (!isa<CXXConstructorDecl>(FD) && !isa<CXXDestructorDecl>(FD)) + AFT->getResultType().getAsStringInternal(Proto, Policy); + + Out << Proto; + + Out.flush(); + return Name.str().str(); + } + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(CurrentDecl)) { + llvm::SmallString<256> Name; + llvm::raw_svector_ostream Out(Name); + Out << (MD->isInstanceMethod() ? '-' : '+'); + Out << '['; + + // For incorrect code, there might not be an ObjCInterfaceDecl. Do + // a null check to avoid a crash. + if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) + Out << ID; + + if (const ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(MD->getDeclContext())) + Out << '(' << CID << ')'; + + Out << ' '; + Out << MD->getSelector().getAsString(); + Out << ']'; + + Out.flush(); + return Name.str().str(); + } + if (isa<TranslationUnitDecl>(CurrentDecl) && IT == PrettyFunction) { + // __PRETTY_FUNCTION__ -> "top level", the others produce an empty string. + return "top level"; + } + return ""; +} + +void APNumericStorage::setIntValue(ASTContext &C, const llvm::APInt &Val) { + if (hasAllocation()) + C.Deallocate(pVal); + + BitWidth = Val.getBitWidth(); + unsigned NumWords = Val.getNumWords(); + const uint64_t* Words = Val.getRawData(); + if (NumWords > 1) { + pVal = new (C) uint64_t[NumWords]; + std::copy(Words, Words + NumWords, pVal); + } else if (NumWords == 1) + VAL = Words[0]; + else + VAL = 0; +} + +IntegerLiteral * +IntegerLiteral::Create(ASTContext &C, const llvm::APInt &V, + QualType type, SourceLocation l) { + return new (C) IntegerLiteral(C, V, type, l); +} + +IntegerLiteral * +IntegerLiteral::Create(ASTContext &C, EmptyShell Empty) { + return new (C) IntegerLiteral(Empty); +} + +FloatingLiteral * +FloatingLiteral::Create(ASTContext &C, const llvm::APFloat &V, + bool isexact, QualType Type, SourceLocation L) { + return new (C) FloatingLiteral(C, V, isexact, Type, L); +} + +FloatingLiteral * +FloatingLiteral::Create(ASTContext &C, EmptyShell Empty) { + return new (C) FloatingLiteral(Empty); +} + +/// 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, + bool Pascal, 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->IsPascal = Pascal; + 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; +} + +void StringLiteral::setString(ASTContext &C, llvm::StringRef Str) { + char *AStrData = new (C, 1) char[Str.size()]; + memcpy(AStrData, Str.data(), Str.size()); + StrData = AStrData; + ByteLength = Str.size(); +} + +/// getLocationOfByte - Return a source location that points to the specified +/// byte of this string literal. +/// +/// Strings are amazingly complex. They can be formed from multiple tokens and +/// can have escape sequences in them in addition to the usual trigraph and +/// escaped newline business. This routine handles this complexity. +/// +SourceLocation StringLiteral:: +getLocationOfByte(unsigned ByteNo, const SourceManager &SM, + const LangOptions &Features, const TargetInfo &Target) const { + assert(!isWide() && "This doesn't work for wide strings yet"); + + // Loop over all of the tokens in this string until we find the one that + // contains the byte we're looking for. + unsigned TokNo = 0; + while (1) { + assert(TokNo < getNumConcatenated() && "Invalid byte number!"); + SourceLocation StrTokLoc = getStrTokenLoc(TokNo); + + // Get the spelling of the string so that we can get the data that makes up + // the string literal, not the identifier for the macro it is potentially + // expanded through. + SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc); + + // Re-lex the token to get its length and original spelling. + std::pair<FileID, unsigned> LocInfo =SM.getDecomposedLoc(StrTokSpellingLoc); + bool Invalid = false; + llvm::StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return StrTokSpellingLoc; + + const char *StrData = Buffer.data()+LocInfo.second; + + // Create a langops struct and enable trigraphs. This is sufficient for + // relexing tokens. + LangOptions LangOpts; + LangOpts.Trigraphs = true; + + // Create a lexer starting at the beginning of this token. + Lexer TheLexer(StrTokSpellingLoc, Features, Buffer.begin(), StrData, + Buffer.end()); + Token TheTok; + TheLexer.LexFromRawLexer(TheTok); + + // Use the StringLiteralParser to compute the length of the string in bytes. + StringLiteralParser SLP(&TheTok, 1, SM, Features, Target); + unsigned TokNumBytes = SLP.GetStringLength(); + + // If the byte is in this token, return the location of the byte. + if (ByteNo < TokNumBytes || + (ByteNo == TokNumBytes && TokNo == getNumConcatenated())) { + unsigned Offset = SLP.getOffsetOfStringByte(TheTok, ByteNo); + + // Now that we know the offset of the token in the spelling, use the + // preprocessor to get the offset in the original source. + return Lexer::AdvanceToTokenCharacter(StrTokLoc, Offset, SM, Features); + } + + // Move to the next string token. + ++TokNo; + ByteNo -= TokNumBytes; + } +} + + + +/// 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 UO_PostInc: return "++"; + case UO_PostDec: return "--"; + case UO_PreInc: return "++"; + case UO_PreDec: return "--"; + case UO_AddrOf: return "&"; + case UO_Deref: return "*"; + case UO_Plus: return "+"; + case UO_Minus: return "-"; + case UO_Not: return "~"; + case UO_LNot: return "!"; + case UO_Real: return "__real"; + case UO_Imag: return "__imag"; + case UO_Extension: return "__extension__"; + } +} + +UnaryOperatorKind +UnaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO, bool Postfix) { + switch (OO) { + default: assert(false && "No unary operator for overloaded function"); + case OO_PlusPlus: return Postfix ? UO_PostInc : UO_PreInc; + case OO_MinusMinus: return Postfix ? UO_PostDec : UO_PreDec; + case OO_Amp: return UO_AddrOf; + case OO_Star: return UO_Deref; + case OO_Plus: return UO_Plus; + case OO_Minus: return UO_Minus; + case OO_Tilde: return UO_Not; + case OO_Exclaim: return UO_LNot; + } +} + +OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { + switch (Opc) { + case UO_PostInc: case UO_PreInc: return OO_PlusPlus; + case UO_PostDec: case UO_PreDec: return OO_MinusMinus; + case UO_AddrOf: return OO_Amp; + case UO_Deref: return OO_Star; + case UO_Plus: return OO_Plus; + case UO_Minus: return OO_Minus; + case UO_Not: return OO_Tilde; + case UO_LNot: return OO_Exclaim; + default: return OO_None; + } +} + + +//===----------------------------------------------------------------------===// +// Postfix Operators. +//===----------------------------------------------------------------------===// + +CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, + Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + SourceLocation rparenloc) + : Expr(SC, t, VK, OK_Ordinary, + fn->isTypeDependent(), + fn->isValueDependent(), + fn->containsUnexpandedParameterPack()), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i+PREARGS_START+NumPreArgs] = args[i]; + } + + CallExprBits.NumPreArgs = NumPreArgs; + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, + QualType t, ExprValueKind VK, SourceLocation rparenloc) + : Expr(CallExprClass, t, VK, OK_Ordinary, + fn->isTypeDependent(), + fn->isValueDependent(), + fn->containsUnexpandedParameterPack()), + NumArgs(numargs) { + + SubExprs = new (C) Stmt*[numargs+PREARGS_START]; + SubExprs[FN] = fn; + for (unsigned i = 0; i != numargs; ++i) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i+PREARGS_START] = args[i]; + } + + CallExprBits.NumPreArgs = 0; + RParenLoc = rparenloc; +} + +CallExpr::CallExpr(ASTContext &C, StmtClass SC, EmptyShell Empty) + : Expr(SC, Empty), SubExprs(0), NumArgs(0) { + // FIXME: Why do we allocate this? + SubExprs = new (C) Stmt*[PREARGS_START]; + CallExprBits.NumPreArgs = 0; +} + +CallExpr::CallExpr(ASTContext &C, StmtClass SC, unsigned NumPreArgs, + EmptyShell Empty) + : Expr(SC, Empty), SubExprs(0), NumArgs(0) { + // FIXME: Why do we allocate this? + SubExprs = new (C) Stmt*[PREARGS_START+NumPreArgs]; + CallExprBits.NumPreArgs = NumPreArgs; +} + +Decl *CallExpr::getCalleeDecl() { + Expr *CEE = getCallee()->IgnoreParenCasts(); + // If we're calling a dereference, look at the pointer instead. + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(CEE)) { + if (BO->isPtrMemOp()) + CEE = BO->getRHS()->IgnoreParenCasts(); + } else if (UnaryOperator *UO = dyn_cast<UnaryOperator>(CEE)) { + if (UO->getOpcode() == UO_Deref) + CEE = UO->getSubExpr()->IgnoreParenCasts(); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) + return DRE->getDecl(); + if (MemberExpr *ME = dyn_cast<MemberExpr>(CEE)) + return ME->getMemberDecl(); + + return 0; +} + +FunctionDecl *CallExpr::getDirectCallee() { + return dyn_cast_or_null<FunctionDecl>(getCalleeDecl()); +} + +/// 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()) { + this->NumArgs = NumArgs; + return; + } + + // Otherwise, we are growing the # arguments. New an bigger argument array. + unsigned NumPreArgs = getNumPreArgs(); + Stmt **NewSubExprs = new (C) Stmt*[NumArgs+PREARGS_START+NumPreArgs]; + // Copy over args. + for (unsigned i = 0; i != getNumArgs()+PREARGS_START+NumPreArgs; ++i) + NewSubExprs[i] = SubExprs[i]; + // Null out new args. + for (unsigned i = getNumArgs()+PREARGS_START+NumPreArgs; + i != NumArgs+PREARGS_START+NumPreArgs; ++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(const 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(); +} + +QualType CallExpr::getCallReturnType() const { + QualType CalleeType = getCallee()->getType(); + if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>()) + CalleeType = FnTypePtr->getPointeeType(); + else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>()) + CalleeType = BPT->getPointeeType(); + else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) + // This should never be overloaded and so should never return null. + CalleeType = Expr::findBoundMemberType(getCallee()); + + const FunctionType *FnType = CalleeType->castAs<FunctionType>(); + return FnType->getResultType(); +} + +SourceRange CallExpr::getSourceRange() const { + if (isa<CXXOperatorCallExpr>(this)) + return cast<CXXOperatorCallExpr>(this)->getSourceRange(); + + SourceLocation begin = getCallee()->getLocStart(); + if (begin.isInvalid() && getNumArgs() > 0) + begin = getArg(0)->getLocStart(); + SourceLocation end = getRParenLoc(); + if (end.isInvalid() && getNumArgs() > 0) + end = getArg(getNumArgs() - 1)->getLocEnd(); + return SourceRange(begin, end); +} + +OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, + SourceLocation OperatorLoc, + TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, + exprsPtr, numExprs, RParenLoc); +} + +OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, + unsigned numComps, unsigned numExprs) { + void *Mem = C.Allocate(sizeof(OffsetOfExpr) + + sizeof(OffsetOfNode) * numComps + + sizeof(Expr*) * numExprs); + return new (Mem) OffsetOfExpr(numComps, numExprs); +} + +OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, + SourceLocation OperatorLoc, TypeSourceInfo *tsi, + OffsetOfNode* compsPtr, unsigned numComps, + Expr** exprsPtr, unsigned numExprs, + SourceLocation RParenLoc) + : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, + /*TypeDependent=*/false, + /*ValueDependent=*/tsi->getType()->isDependentType(), + tsi->getType()->containsUnexpandedParameterPack()), + OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), + NumComps(numComps), NumExprs(numExprs) +{ + for(unsigned i = 0; i < numComps; ++i) { + setComponent(i, compsPtr[i]); + } + + for(unsigned i = 0; i < numExprs; ++i) { + if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (exprsPtr[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + setIndexExpr(i, exprsPtr[i]); + } +} + +IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { + assert(getKind() == Field || getKind() == Identifier); + if (getKind() == Field) + return getField()->getIdentifier(); + + return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask); +} + +MemberExpr *MemberExpr::Create(ASTContext &C, Expr *base, bool isarrow, + NestedNameSpecifierLoc QualifierLoc, + ValueDecl *memberdecl, + DeclAccessPair founddecl, + DeclarationNameInfo nameinfo, + const TemplateArgumentListInfo *targs, + QualType ty, + ExprValueKind vk, + ExprObjectKind ok) { + std::size_t Size = sizeof(MemberExpr); + + bool hasQualOrFound = (QualifierLoc || + founddecl.getDecl() != memberdecl || + founddecl.getAccess() != memberdecl->getAccess()); + if (hasQualOrFound) + Size += sizeof(MemberNameQualifier); + + if (targs) + Size += ExplicitTemplateArgumentList::sizeFor(*targs); + + void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>()); + MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, + ty, vk, ok); + + if (hasQualOrFound) { + // FIXME: Wrong. We should be looking at the member declaration we found. + if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { + E->setValueDependent(true); + E->setTypeDependent(true); + } + E->HasQualifierOrFoundDecl = true; + + MemberNameQualifier *NQ = E->getMemberQualifier(); + NQ->QualifierLoc = QualifierLoc; + NQ->FoundDecl = founddecl; + } + + if (targs) { + E->HasExplicitTemplateArgumentList = true; + E->getExplicitTemplateArgs().initializeFrom(*targs); + } + + return E; +} + +SourceRange MemberExpr::getSourceRange() const { + SourceLocation StartLoc; + if (isImplicitAccess()) { + if (hasQualifier()) + StartLoc = getQualifierLoc().getBeginLoc(); + else + StartLoc = MemberLoc; + } else { + // FIXME: We don't want this to happen. Rather, we should be able to + // detect all kinds of implicit accesses more cleanly. + StartLoc = getBase()->getLocStart(); + if (StartLoc.isInvalid()) + StartLoc = MemberLoc; + } + + SourceLocation EndLoc = + HasExplicitTemplateArgumentList? getRAngleLoc() + : getMemberNameInfo().getEndLoc(); + + return SourceRange(StartLoc, EndLoc); +} + +const char *CastExpr::getCastKindName() const { + switch (getCastKind()) { + case CK_Dependent: + return "Dependent"; + case CK_BitCast: + return "BitCast"; + case CK_LValueBitCast: + return "LValueBitCast"; + case CK_LValueToRValue: + return "LValueToRValue"; + case CK_GetObjCProperty: + return "GetObjCProperty"; + case CK_NoOp: + return "NoOp"; + case CK_BaseToDerived: + return "BaseToDerived"; + case CK_DerivedToBase: + return "DerivedToBase"; + case CK_UncheckedDerivedToBase: + return "UncheckedDerivedToBase"; + case CK_Dynamic: + return "Dynamic"; + case CK_ToUnion: + return "ToUnion"; + case CK_ArrayToPointerDecay: + return "ArrayToPointerDecay"; + case CK_FunctionToPointerDecay: + return "FunctionToPointerDecay"; + case CK_NullToMemberPointer: + return "NullToMemberPointer"; + case CK_NullToPointer: + return "NullToPointer"; + case CK_BaseToDerivedMemberPointer: + return "BaseToDerivedMemberPointer"; + case CK_DerivedToBaseMemberPointer: + return "DerivedToBaseMemberPointer"; + case CK_UserDefinedConversion: + return "UserDefinedConversion"; + case CK_ConstructorConversion: + return "ConstructorConversion"; + case CK_IntegralToPointer: + return "IntegralToPointer"; + case CK_PointerToIntegral: + return "PointerToIntegral"; + case CK_PointerToBoolean: + return "PointerToBoolean"; + case CK_ToVoid: + return "ToVoid"; + case CK_VectorSplat: + return "VectorSplat"; + case CK_IntegralCast: + return "IntegralCast"; + case CK_IntegralToBoolean: + return "IntegralToBoolean"; + case CK_IntegralToFloating: + return "IntegralToFloating"; + case CK_FloatingToIntegral: + return "FloatingToIntegral"; + case CK_FloatingCast: + return "FloatingCast"; + case CK_FloatingToBoolean: + return "FloatingToBoolean"; + case CK_MemberPointerToBoolean: + return "MemberPointerToBoolean"; + case CK_AnyPointerToObjCPointerCast: + return "AnyPointerToObjCPointerCast"; + case CK_AnyPointerToBlockPointerCast: + return "AnyPointerToBlockPointerCast"; + case CK_ObjCObjectLValueCast: + return "ObjCObjectLValueCast"; + case CK_FloatingRealToComplex: + return "FloatingRealToComplex"; + case CK_FloatingComplexToReal: + return "FloatingComplexToReal"; + case CK_FloatingComplexToBoolean: + return "FloatingComplexToBoolean"; + case CK_FloatingComplexCast: + return "FloatingComplexCast"; + case CK_FloatingComplexToIntegralComplex: + return "FloatingComplexToIntegralComplex"; + case CK_IntegralRealToComplex: + return "IntegralRealToComplex"; + case CK_IntegralComplexToReal: + return "IntegralComplexToReal"; + case CK_IntegralComplexToBoolean: + return "IntegralComplexToBoolean"; + case CK_IntegralComplexCast: + return "IntegralComplexCast"; + case CK_IntegralComplexToFloatingComplex: + return "IntegralComplexToFloatingComplex"; + } + + llvm_unreachable("Unhandled cast kind!"); + return 0; +} + +Expr *CastExpr::getSubExprAsWritten() { + Expr *SubExpr = 0; + CastExpr *E = this; + do { + SubExpr = E->getSubExpr(); + + // Skip any temporary bindings; they're implicit. + if (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(SubExpr)) + SubExpr = Binder->getSubExpr(); + + // Conversions by constructor and conversion functions have a + // subexpression describing the call; strip it off. + if (E->getCastKind() == CK_ConstructorConversion) + SubExpr = cast<CXXConstructExpr>(SubExpr)->getArg(0); + else if (E->getCastKind() == CK_UserDefinedConversion) + SubExpr = cast<CXXMemberCallExpr>(SubExpr)->getImplicitObjectArgument(); + + // If the subexpression we're left with is an implicit cast, look + // through that, too. + } while ((E = dyn_cast<ImplicitCastExpr>(SubExpr))); + + return SubExpr; +} + +CXXBaseSpecifier **CastExpr::path_buffer() { + switch (getStmtClass()) { +#define ABSTRACT_STMT(x) +#define CASTEXPR(Type, Base) \ + case Stmt::Type##Class: \ + return reinterpret_cast<CXXBaseSpecifier**>(static_cast<Type*>(this)+1); +#define STMT(Type, Base) +#include "clang/AST/StmtNodes.inc" + default: + llvm_unreachable("non-cast expressions not possible here"); + return 0; + } +} + +void CastExpr::setCastPath(const CXXCastPath &Path) { + assert(Path.size() == path_size()); + memcpy(path_buffer(), Path.data(), Path.size() * sizeof(CXXBaseSpecifier*)); +} + +ImplicitCastExpr *ImplicitCastExpr::Create(ASTContext &C, QualType T, + CastKind Kind, Expr *Operand, + const CXXCastPath *BasePath, + ExprValueKind VK) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + ImplicitCastExpr *E = + new (Buffer) ImplicitCastExpr(T, Kind, Operand, PathSize, VK); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +ImplicitCastExpr *ImplicitCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(ImplicitCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) ImplicitCastExpr(EmptyShell(), PathSize); +} + + +CStyleCastExpr *CStyleCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L, SourceLocation R) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + CStyleCastExpr *E = + new (Buffer) CStyleCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, R); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CStyleCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CStyleCastExpr(EmptyShell(), PathSize); +} + +/// getOpcodeStr - Turn an Opcode enum value into the punctuation char it +/// corresponds to, e.g. "<<=". +const char *BinaryOperator::getOpcodeStr(Opcode Op) { + switch (Op) { + case BO_PtrMemD: return ".*"; + case BO_PtrMemI: return "->*"; + case BO_Mul: return "*"; + case BO_Div: return "/"; + case BO_Rem: return "%"; + case BO_Add: return "+"; + case BO_Sub: return "-"; + case BO_Shl: return "<<"; + case BO_Shr: return ">>"; + case BO_LT: return "<"; + case BO_GT: return ">"; + case BO_LE: return "<="; + case BO_GE: return ">="; + case BO_EQ: return "=="; + case BO_NE: return "!="; + case BO_And: return "&"; + case BO_Xor: return "^"; + case BO_Or: return "|"; + case BO_LAnd: return "&&"; + case BO_LOr: return "||"; + case BO_Assign: return "="; + case BO_MulAssign: return "*="; + case BO_DivAssign: return "/="; + case BO_RemAssign: return "%="; + case BO_AddAssign: return "+="; + case BO_SubAssign: return "-="; + case BO_ShlAssign: return "<<="; + case BO_ShrAssign: return ">>="; + case BO_AndAssign: return "&="; + case BO_XorAssign: return "^="; + case BO_OrAssign: return "|="; + case BO_Comma: return ","; + } + + return ""; +} + +BinaryOperatorKind +BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) { + switch (OO) { + default: assert(false && "Not an overloadable binary operator"); + case OO_Plus: return BO_Add; + case OO_Minus: return BO_Sub; + case OO_Star: return BO_Mul; + case OO_Slash: return BO_Div; + case OO_Percent: return BO_Rem; + case OO_Caret: return BO_Xor; + case OO_Amp: return BO_And; + case OO_Pipe: return BO_Or; + case OO_Equal: return BO_Assign; + case OO_Less: return BO_LT; + case OO_Greater: return BO_GT; + case OO_PlusEqual: return BO_AddAssign; + case OO_MinusEqual: return BO_SubAssign; + case OO_StarEqual: return BO_MulAssign; + case OO_SlashEqual: return BO_DivAssign; + case OO_PercentEqual: return BO_RemAssign; + case OO_CaretEqual: return BO_XorAssign; + case OO_AmpEqual: return BO_AndAssign; + case OO_PipeEqual: return BO_OrAssign; + case OO_LessLess: return BO_Shl; + case OO_GreaterGreater: return BO_Shr; + case OO_LessLessEqual: return BO_ShlAssign; + case OO_GreaterGreaterEqual: return BO_ShrAssign; + case OO_EqualEqual: return BO_EQ; + case OO_ExclaimEqual: return BO_NE; + case OO_LessEqual: return BO_LE; + case OO_GreaterEqual: return BO_GE; + case OO_AmpAmp: return BO_LAnd; + case OO_PipePipe: return BO_LOr; + case OO_Comma: return BO_Comma; + case OO_ArrowStar: return BO_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(ASTContext &C, SourceLocation lbraceloc, + Expr **initExprs, unsigned numInits, + SourceLocation rbraceloc) + : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, + false), + InitExprs(C, numInits), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0), + HadArrayRangeDesignator(false) +{ + for (unsigned I = 0; I != numInits; ++I) { + if (initExprs[I]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (initExprs[I]->isValueDependent()) + ExprBits.ValueDependent = true; + if (initExprs[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + } + + InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); +} + +void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { + if (NumInits > InitExprs.size()) + InitExprs.reserve(C, NumInits); +} + +void InitListExpr::resizeInits(ASTContext &C, unsigned NumInits) { + InitExprs.resize(C, NumInits, 0); +} + +Expr *InitListExpr::updateInit(ASTContext &C, unsigned Init, Expr *expr) { + if (Init >= InitExprs.size()) { + InitExprs.insert(C, 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; +} + +void InitListExpr::setArrayFiller(Expr *filler) { + ArrayFillerOrUnionFieldInit = filler; + // Fill out any "holes" in the array due to designated initializers. + Expr **inits = getInits(); + for (unsigned i = 0, e = getNumInits(); i != e; ++i) + if (inits[i] == 0) + inits[i] = filler; +} + +SourceRange InitListExpr::getSourceRange() const { + if (SyntacticForm) + return SyntacticForm->getSourceRange(); + SourceLocation Beg = LBraceLoc, End = RBraceLoc; + if (Beg.isInvalid()) { + // Find the first non-null initializer. + for (InitExprsTy::const_iterator I = InitExprs.begin(), + E = InitExprs.end(); + I != E; ++I) { + if (Stmt *S = *I) { + Beg = S->getLocStart(); + break; + } + } + } + if (End.isInvalid()) { + // Find the first non-null initializer from the end. + for (InitExprsTy::const_reverse_iterator I = InitExprs.rbegin(), + E = InitExprs.rend(); + I != E; ++I) { + if (Stmt *S = *I) { + End = S->getSourceRange().getEnd(); + break; + } + } + } + return SourceRange(Beg, End); +} + +/// getFunctionType - Return the underlying function type for this block. +/// +const FunctionType *BlockExpr::getFunctionType() const { + return getType()->getAs<BlockPointerType>()-> + getPointeeType()->getAs<FunctionType>(); +} + +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, ASTContext &Ctx) 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: + if (getType()->isVoidType()) + return false; + Loc = getExprLoc(); + R1 = getSourceRange(); + return true; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr()-> + isUnusedResultAWarning(Loc, R1, R2, Ctx); + case GenericSelectionExprClass: + return cast<GenericSelectionExpr>(this)->getResultExpr()-> + isUnusedResultAWarning(Loc, R1, R2, Ctx); + case UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(this); + + switch (UO->getOpcode()) { + default: break; + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: // ++/-- + return false; // Not a warning. + case UO_Deref: + // Dereferencing a volatile pointer is a side-effect. + if (Ctx.getCanonicalType(getType()).isVolatileQualified()) + return false; + break; + case UO_Real: + case UO_Imag: + // accessing a piece of a volatile complex is a side-effect. + if (Ctx.getCanonicalType(UO->getSubExpr()->getType()) + .isVolatileQualified()) + return false; + break; + case UO_Extension: + return UO->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx); + } + Loc = UO->getOperatorLoc(); + R1 = UO->getSubExpr()->getSourceRange(); + return true; + } + case BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(this); + switch (BO->getOpcode()) { + default: + break; + // Consider the RHS of comma for side effects. LHS was checked by + // Sema::CheckCommaOperands. + case BO_Comma: + // ((foo = <blah>), 0) is an idiom for hiding the result (and + // lvalue-ness) of an assignment written in a macro. + if (IntegerLiteral *IE = + dyn_cast<IntegerLiteral>(BO->getRHS()->IgnoreParens())) + if (IE->getValue() == 0) + return false; + return BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); + // Consider '||', '&&' to have side effects if the LHS or RHS does. + case BO_LAnd: + case BO_LOr: + if (!BO->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx) || + !BO->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) + return false; + break; + } + if (BO->isAssignmentOp()) + return false; + Loc = BO->getOperatorLoc(); + R1 = BO->getLHS()->getSourceRange(); + R2 = BO->getRHS()->getSourceRange(); + return true; + } + case CompoundAssignOperatorClass: + case VAArgExprClass: + return false; + + case ConditionalOperatorClass: { + // If only one of the LHS or RHS is a warning, the operator might + // be being used for control flow. Only warn if both the LHS and + // RHS are warnings. + const ConditionalOperator *Exp = cast<ConditionalOperator>(this); + if (!Exp->getRHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx)) + return false; + if (!Exp->getLHS()) + return true; + return Exp->getLHS()->isUnusedResultAWarning(Loc, R1, R2, Ctx); + } + + case MemberExprClass: + // If the base pointer or element is to a volatile pointer/field, accessing + // it is a side effect. + if (Ctx.getCanonicalType(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 (Ctx.getCanonicalType(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); + if (const Decl *FD = CE->getCalleeDecl()) { + // If the callee has attribute pure, const, or warn_unused_result, warn + // about it. void foo() { strlen("bar"); } should warn. + // + // Note: If new cases are added here, DiagnoseUnusedExprResult should be + // updated to match for QoI. + 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 CXXTemporaryObjectExprClass: + case CXXConstructExprClass: + return false; + + case ObjCMessageExprClass: { + const ObjCMessageExpr *ME = cast<ObjCMessageExpr>(this); + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD && MD->getAttr<WarnUnusedResultAttr>()) { + Loc = getExprLoc(); + return true; + } + return false; + } + + case ObjCPropertyRefExprClass: + Loc = getExprLoc(); + R1 = getSourceRange(); + return true; + + 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, Ctx); + if (const LabelStmt *Label = dyn_cast<LabelStmt>(CS->body_back())) + if (const Expr *E = dyn_cast<Expr>(Label->getSubStmt())) + return E->isUnusedResultAWarning(Loc, R1, R2, Ctx); + } + + if (getType()->isVoidType()) + return false; + Loc = cast<StmtExpr>(this)->getLParenLoc(); + R1 = getSourceRange(); + return true; + } + case CStyleCastExprClass: + // If this is an explicit cast to void, allow it. People do this when they + // think they know what they're doing :). + if (getType()->isVoidType()) + return false; + Loc = cast<CStyleCastExpr>(this)->getLParenLoc(); + R1 = cast<CStyleCastExpr>(this)->getSubExpr()->getSourceRange(); + return true; + case CXXFunctionalCastExprClass: { + if (getType()->isVoidType()) + return false; + const CastExpr *CE = cast<CastExpr>(this); + + // If this is a cast to void or a constructor conversion, check the operand. + // Otherwise, the result of the cast is unused. + if (CE->getCastKind() == CK_ToVoid || + CE->getCastKind() == CK_ConstructorConversion) + return (cast<CastExpr>(this)->getSubExpr() + ->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + 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, Ctx)); + + case CXXDefaultArgExprClass: + return (cast<CXXDefaultArgExpr>(this) + ->getExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + + 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 CXXBindTemporaryExprClass: + return (cast<CXXBindTemporaryExpr>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + case ExprWithCleanupsClass: + return (cast<ExprWithCleanups>(this) + ->getSubExpr()->isUnusedResultAWarning(Loc, R1, R2, Ctx)); + } +} + +/// isOBJCGCCandidate - Check if an expression is objc gc'able. +/// returns true, if it is; false otherwise. +bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { + const Expr *E = IgnoreParens(); + switch (E->getStmtClass()) { + default: + return false; + case ObjCIvarRefExprClass: + return true; + case Expr::UnaryOperatorClass: + return cast<UnaryOperator>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case ImplicitCastExprClass: + return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case CStyleCastExprClass: + return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); + case DeclRefExprClass: { + const Decl *D = cast<DeclRefExpr>(E)->getDecl(); + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->hasGlobalStorage()) + return true; + QualType T = VD->getType(); + // dereferencing to a pointer is always a gc'able candidate, + // unless it is __weak. + return T->isPointerType() && + (Ctx.getObjCGCAttrKind(T) != Qualifiers::Weak); + } + return false; + } + case MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(E); + return M->getBase()->isOBJCGCCandidate(Ctx); + } + case ArraySubscriptExprClass: + return cast<ArraySubscriptExpr>(E)->getBase()->isOBJCGCCandidate(Ctx); + } +} + +bool Expr::isBoundMemberFunction(ASTContext &Ctx) const { + if (isTypeDependent()) + return false; + return ClassifyLValue(Ctx) == Expr::LV_MemberFunction; +} + +QualType Expr::findBoundMemberType(const Expr *expr) { + assert(expr->getType()->isSpecificPlaceholderType(BuiltinType::BoundMember)); + + // Bound member expressions are always one of these possibilities: + // x->m x.m x->*y x.*y + // (possibly parenthesized) + + expr = expr->IgnoreParens(); + if (const MemberExpr *mem = dyn_cast<MemberExpr>(expr)) { + assert(isa<CXXMethodDecl>(mem->getMemberDecl())); + return mem->getMemberDecl()->getType(); + } + + if (const BinaryOperator *op = dyn_cast<BinaryOperator>(expr)) { + QualType type = op->getRHS()->getType()->castAs<MemberPointerType>() + ->getPointeeType(); + assert(type->isFunctionType()); + return type; + } + + assert(isa<UnresolvedMemberExpr>(expr)); + return QualType(); +} + +static Expr::CanThrowResult MergeCanThrow(Expr::CanThrowResult CT1, + Expr::CanThrowResult CT2) { + // CanThrowResult constants are ordered so that the maximum is the correct + // merge result. + return CT1 > CT2 ? CT1 : CT2; +} + +static Expr::CanThrowResult CanSubExprsThrow(ASTContext &C, const Expr *CE) { + Expr *E = const_cast<Expr*>(CE); + Expr::CanThrowResult R = Expr::CT_Cannot; + for (Expr::child_range I = E->children(); I && R != Expr::CT_Can; ++I) { + R = MergeCanThrow(R, cast<Expr>(*I)->CanThrow(C)); + } + return R; +} + +static Expr::CanThrowResult CanCalleeThrow(ASTContext &Ctx, const Expr *E, + const Decl *D, + bool NullThrows = true) { + if (!D) + return NullThrows ? Expr::CT_Can : Expr::CT_Cannot; + + // See if we can get a function type from the decl somehow. + const ValueDecl *VD = dyn_cast<ValueDecl>(D); + if (!VD) // If we have no clue what we're calling, assume the worst. + return Expr::CT_Can; + + // As an extension, we assume that __attribute__((nothrow)) functions don't + // throw. + if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) + return Expr::CT_Cannot; + + QualType T = VD->getType(); + const FunctionProtoType *FT; + if ((FT = T->getAs<FunctionProtoType>())) { + } else if (const PointerType *PT = T->getAs<PointerType>()) + FT = PT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const ReferenceType *RT = T->getAs<ReferenceType>()) + FT = RT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const MemberPointerType *MT = T->getAs<MemberPointerType>()) + FT = MT->getPointeeType()->getAs<FunctionProtoType>(); + else if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) + FT = BT->getPointeeType()->getAs<FunctionProtoType>(); + + if (!FT) + return Expr::CT_Can; + + if (FT->getExceptionSpecType() == EST_Delayed) { + assert(isa<CXXConstructorDecl>(D) && + "only constructor exception specs can be unknown"); + Ctx.getDiagnostics().Report(E->getLocStart(), + diag::err_exception_spec_unknown) + << E->getSourceRange(); + return Expr::CT_Can; + } + + return FT->isNothrow(Ctx) ? Expr::CT_Cannot : Expr::CT_Can; +} + +static Expr::CanThrowResult CanDynamicCastThrow(const CXXDynamicCastExpr *DC) { + if (DC->isTypeDependent()) + return Expr::CT_Dependent; + + if (!DC->getTypeAsWritten()->isReferenceType()) + return Expr::CT_Cannot; + + if (DC->getSubExpr()->isTypeDependent()) + return Expr::CT_Dependent; + + return DC->getCastKind() == clang::CK_Dynamic? Expr::CT_Can : Expr::CT_Cannot; +} + +static Expr::CanThrowResult CanTypeidThrow(ASTContext &C, + const CXXTypeidExpr *DC) { + if (DC->isTypeOperand()) + return Expr::CT_Cannot; + + Expr *Op = DC->getExprOperand(); + if (Op->isTypeDependent()) + return Expr::CT_Dependent; + + const RecordType *RT = Op->getType()->getAs<RecordType>(); + if (!RT) + return Expr::CT_Cannot; + + if (!cast<CXXRecordDecl>(RT->getDecl())->isPolymorphic()) + return Expr::CT_Cannot; + + if (Op->Classify(C).isPRValue()) + return Expr::CT_Cannot; + + return Expr::CT_Can; +} + +Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const { + // C++ [expr.unary.noexcept]p3: + // [Can throw] if in a potentially-evaluated context the expression would + // contain: + switch (getStmtClass()) { + case CXXThrowExprClass: + // - a potentially evaluated throw-expression + return CT_Can; + + case CXXDynamicCastExprClass: { + // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), + // where T is a reference type, that requires a run-time check + CanThrowResult CT = CanDynamicCastThrow(cast<CXXDynamicCastExpr>(this)); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXTypeidExprClass: + // - a potentially evaluated typeid expression applied to a glvalue + // expression whose type is a polymorphic class type + return CanTypeidThrow(C, cast<CXXTypeidExpr>(this)); + + // - a potentially evaluated call to a function, member function, function + // pointer, or member function pointer that does not have a non-throwing + // exception-specification + case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: { + const CallExpr *CE = cast<CallExpr>(this); + CanThrowResult CT; + if (isTypeDependent()) + CT = CT_Dependent; + else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) + CT = CT_Cannot; + else + CT = CanCalleeThrow(C, this, CE->getCalleeDecl()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXConstructExprClass: + case CXXTemporaryObjectExprClass: { + CanThrowResult CT = CanCalleeThrow(C, this, + cast<CXXConstructExpr>(this)->getConstructor()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXNewExprClass: { + CanThrowResult CT; + if (isTypeDependent()) + CT = CT_Dependent; + else + CT = MergeCanThrow( + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()), + CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(), + /*NullThrows*/false)); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXDeleteExprClass: { + CanThrowResult CT; + QualType DTy = cast<CXXDeleteExpr>(this)->getDestroyedType(); + if (DTy.isNull() || DTy->isDependentType()) { + CT = CT_Dependent; + } else { + CT = CanCalleeThrow(C, this, + cast<CXXDeleteExpr>(this)->getOperatorDelete()); + if (const RecordType *RT = DTy->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + CT = MergeCanThrow(CT, CanCalleeThrow(C, this, RD->getDestructor())); + } + if (CT == CT_Can) + return CT; + } + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + case CXXBindTemporaryExprClass: { + // The bound temporary has to be destroyed again, which might throw. + CanThrowResult CT = CanCalleeThrow(C, this, + cast<CXXBindTemporaryExpr>(this)->getTemporary()->getDestructor()); + if (CT == CT_Can) + return CT; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + // ObjC message sends are like function calls, but never have exception + // specs. + case ObjCMessageExprClass: + case ObjCPropertyRefExprClass: + return CT_Can; + + // Many other things have subexpressions, so we have to test those. + // Some are simple: + case ParenExprClass: + case MemberExprClass: + case CXXReinterpretCastExprClass: + case CXXConstCastExprClass: + case ConditionalOperatorClass: + case CompoundLiteralExprClass: + case ExtVectorElementExprClass: + case InitListExprClass: + case DesignatedInitExprClass: + case ParenListExprClass: + case VAArgExprClass: + case CXXDefaultArgExprClass: + case ExprWithCleanupsClass: + case ObjCIvarRefExprClass: + case ObjCIsaExprClass: + case ShuffleVectorExprClass: + return CanSubExprsThrow(C, this); + + // Some might be dependent for other reasons. + case UnaryOperatorClass: + case ArraySubscriptExprClass: + case ImplicitCastExprClass: + case CStyleCastExprClass: + case CXXStaticCastExprClass: + case CXXFunctionalCastExprClass: + case BinaryOperatorClass: + case CompoundAssignOperatorClass: { + CanThrowResult CT = isTypeDependent() ? CT_Dependent : CT_Cannot; + return MergeCanThrow(CT, CanSubExprsThrow(C, this)); + } + + // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. + case StmtExprClass: + return CT_Can; + + case ChooseExprClass: + if (isTypeDependent() || isValueDependent()) + return CT_Dependent; + return cast<ChooseExpr>(this)->getChosenSubExpr(C)->CanThrow(C); + + case GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(this)->isResultDependent()) + return CT_Dependent; + return cast<GenericSelectionExpr>(this)->getResultExpr()->CanThrow(C); + + // Some expressions are always dependent. + case DependentScopeDeclRefExprClass: + case CXXUnresolvedConstructExprClass: + case CXXDependentScopeMemberExprClass: + return CT_Dependent; + + default: + // All other expressions don't have subexpressions, or else they are + // unevaluated. + return CT_Cannot; + } +} + +Expr* Expr::IgnoreParens() { + Expr* E = this; + while (true) { + if (ParenExpr* P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + 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(); + continue; + } + if (CastExpr *P = dyn_cast<CastExpr>(E)) { + E = P->getSubExpr(); + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + return E; + } +} + +/// IgnoreParenLValueCasts - Ignore parentheses and lvalue-to-rvalue +/// casts. This is intended purely as a temporary workaround for code +/// that hasn't yet been rewritten to do the right thing about those +/// casts, and may disappear along with the last internal use. +Expr *Expr::IgnoreParenLValueCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } else if (CastExpr *P = dyn_cast<CastExpr>(E)) { + if (P->getCastKind() == CK_LValueToRValue) { + E = P->getSubExpr(); + continue; + } + } else if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } else if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + break; + } + return E; +} + +Expr *Expr::IgnoreParenImpCasts() { + Expr *E = this; + while (true) { + if (ParenExpr *P = dyn_cast<ParenExpr>(E)) { + E = P->getSubExpr(); + continue; + } + if (ImplicitCastExpr *P = dyn_cast<ImplicitCastExpr>(E)) { + E = P->getSubExpr(); + continue; + } + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + return E; + } +} + +Expr *Expr::IgnoreConversionOperator() { + if (CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(this)) { + if (isa<CXXConversionDecl>(MCE->getMethodDecl())) + return MCE->getImplicitObjectArgument(); + } + return this; +} + +/// 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 identity casts. + Expr *SE = P->getSubExpr(); + + if (Ctx.hasSameUnqualifiedType(E->getType(), SE->getType())) { + E = SE; + continue; + } + + if ((E->getType()->isPointerType() || + E->getType()->isIntegralType(Ctx)) && + (SE->getType()->isPointerType() || + SE->getType()->isIntegralType(Ctx)) && + Ctx.getTypeSize(E->getType()) == Ctx.getTypeSize(SE->getType())) { + E = SE; + continue; + } + } + + if (UnaryOperator* P = dyn_cast<UnaryOperator>(E)) { + if (P->getOpcode() == UO_Extension) { + E = P->getSubExpr(); + continue; + } + } + + if (GenericSelectionExpr* P = dyn_cast<GenericSelectionExpr>(E)) { + if (!P->isResultDependent()) { + E = P->getResultExpr(); + continue; + } + } + + return E; + } +} + +bool Expr::isDefaultArgument() const { + const Expr *E = this; + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + E = ICE->getSubExprAsWritten(); + + return isa<CXXDefaultArgExpr>(E); +} + +/// \brief Skip over any no-op casts and any temporary-binding +/// expressions. +static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_NoOp) + E = ICE->getSubExpr(); + else + break; + } + + while (const CXXBindTemporaryExpr *BE = dyn_cast<CXXBindTemporaryExpr>(E)) + E = BE->getSubExpr(); + + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_NoOp) + E = ICE->getSubExpr(); + else + break; + } + + return E->IgnoreParens(); +} + +/// isTemporaryObject - Determines if this expression produces a +/// temporary of the given class type. +bool Expr::isTemporaryObject(ASTContext &C, const CXXRecordDecl *TempTy) const { + if (!C.hasSameUnqualifiedType(getType(), C.getTypeDeclType(TempTy))) + return false; + + const Expr *E = skipTemporaryBindingsNoOpCastsAndParens(this); + + // Temporaries are by definition pr-values of class type. + if (!E->Classify(C).isPRValue()) { + // In this context, property reference is a message call and is pr-value. + if (!isa<ObjCPropertyRefExpr>(E)) + return false; + } + + // Black-list a few cases which yield pr-values of class type that don't + // refer to temporaries of that type: + + // - implicit derived-to-base conversions + if (isa<ImplicitCastExpr>(E)) { + switch (cast<ImplicitCastExpr>(E)->getCastKind()) { + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + return false; + default: + break; + } + } + + // - member expressions (all) + if (isa<MemberExpr>(E)) + return false; + + // - opaque values (all) + if (isa<OpaqueValueExpr>(E)) + return false; + + return true; +} + +bool Expr::isImplicitCXXThis() const { + const Expr *E = this; + + // Strip away parentheses and casts we don't care about. + while (true) { + if (const ParenExpr *Paren = dyn_cast<ParenExpr>(E)) { + E = Paren->getSubExpr(); + continue; + } + + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_NoOp || + ICE->getCastKind() == CK_LValueToRValue || + ICE->getCastKind() == CK_DerivedToBase || + ICE->getCastKind() == CK_UncheckedDerivedToBase) { + E = ICE->getSubExpr(); + continue; + } + } + + if (const UnaryOperator* UnOp = dyn_cast<UnaryOperator>(E)) { + if (UnOp->getOpcode() == UO_Extension) { + E = UnOp->getSubExpr(); + continue; + } + } + + break; + } + + if (const CXXThisExpr *This = dyn_cast<CXXThisExpr>(E)) + return This->isImplicit(); + + return false; +} + +/// 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, bool IsForRef) 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. + + // If we ever capture reference-binding directly in the AST, we can + // kill the second parameter. + + if (IsForRef) { + EvalResult Result; + return EvaluateAsLValue(Result, Ctx) && !Result.HasSideEffects; + } + + switch (getStmtClass()) { + default: break; + case StringLiteralClass: + case ObjCStringLiteralClass: + case ObjCEncodeExprClass: + return true; + case CXXTemporaryObjectExprClass: + case CXXConstructExprClass: { + const CXXConstructExpr *CE = cast<CXXConstructExpr>(this); + + // Only if it's + // 1) an application of the trivial default constructor or + if (!CE->getConstructor()->isTrivial()) return false; + if (!CE->getNumArgs()) return true; + + // 2) an elidable trivial copy construction of an operand which is + // itself a constant initializer. Note that we consider the + // operand on its own, *not* as a reference binding. + return CE->isElidable() && + CE->getArg(0)->isConstantInitializer(Ctx, false); + } + 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, false); + } + 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, false)) + return false; + } + return true; + } + case ImplicitValueInitExprClass: + return true; + case ParenExprClass: + return cast<ParenExpr>(this)->getSubExpr() + ->isConstantInitializer(Ctx, IsForRef); + case GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(this)->isResultDependent()) + return false; + return cast<GenericSelectionExpr>(this)->getResultExpr() + ->isConstantInitializer(Ctx, IsForRef); + case ChooseExprClass: + return cast<ChooseExpr>(this)->getChosenSubExpr(Ctx) + ->isConstantInitializer(Ctx, IsForRef); + case UnaryOperatorClass: { + const UnaryOperator* Exp = cast<UnaryOperator>(this); + if (Exp->getOpcode() == UO_Extension) + return Exp->getSubExpr()->isConstantInitializer(Ctx, false); + break; + } + case BinaryOperatorClass: { + // Special case &&foo - &&bar. It would be nice to generalize this somehow + // but this handles the common case. + const BinaryOperator *Exp = cast<BinaryOperator>(this); + if (Exp->getOpcode() == BO_Sub && + isa<AddrLabelExpr>(Exp->getLHS()->IgnoreParenNoopCasts(Ctx)) && + isa<AddrLabelExpr>(Exp->getRHS()->IgnoreParenNoopCasts(Ctx))) + return true; + break; + } + case CXXFunctionalCastExprClass: + case CXXStaticCastExprClass: + 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, false); + + // Integer->integer casts can be handled here, which is important for + // things like (int)(&&x-&&y). Scary but true. + if (getType()->isIntegerType() && + cast<CastExpr>(this)->getSubExpr()->getType()->isIntegerType()) + return cast<CastExpr>(this)->getSubExpr() + ->isConstantInitializer(Ctx, false); + + break; + } + return isEvaluatable(Ctx); +} + +/// isNullPointerConstant - C99 6.3.2.3p3 - Return whether this is a null +/// pointer constant or not, as well as the specific kind of constant detected. +/// Null pointer constants can be integer constant expressions with the +/// value zero, casts of zero to void*, nullptr (C++0X), or __null +/// (a GNU extension). +Expr::NullPointerConstantKind +Expr::isNullPointerConstant(ASTContext &Ctx, + NullPointerConstantValueDependence NPC) const { + if (isValueDependent()) { + switch (NPC) { + case NPC_NeverValueDependent: + assert(false && "Unexpected value dependent expression!"); + // If the unthinkable happens, fall through to the safest alternative. + + case NPC_ValueDependentIsNull: + if (isTypeDependent() || getType()->isIntegralType(Ctx)) + return NPCK_ZeroInteger; + else + return NPCK_NotNull; + + case NPC_ValueDependentIsNotNull: + return NPCK_NotNull; + } + } + + // 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()->getAs<PointerType>()) { + QualType Pointee = PT->getPointeeType(); + if (!Pointee.hasQualifiers() && + Pointee->isVoidType() && // to void* + CE->getSubExpr()->getType()->isIntegerType()) // from int. + return CE->getSubExpr()->isNullPointerConstant(Ctx, NPC); + } + } + } else if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(this)) { + // Ignore the ImplicitCastExpr type entirely. + return ICE->getSubExpr()->isNullPointerConstant(Ctx, NPC); + } 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, NPC); + } else if (const GenericSelectionExpr *GE = + dyn_cast<GenericSelectionExpr>(this)) { + return GE->getResultExpr()->isNullPointerConstant(Ctx, NPC); + } else if (const CXXDefaultArgExpr *DefaultArg + = dyn_cast<CXXDefaultArgExpr>(this)) { + // See through default argument expressions + return DefaultArg->getExpr()->isNullPointerConstant(Ctx, NPC); + } else if (isa<GNUNullExpr>(this)) { + // The GNU __null extension is always a null pointer constant. + return NPCK_GNUNull; + } + + // C++0x nullptr_t is always a null pointer constant. + if (getType()->isNullPtrType()) + return NPCK_CXX0X_nullptr; + + if (const RecordType *UT = getType()->getAsUnionType()) + if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(this)){ + const Expr *InitExpr = CLE->getInitializer(); + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(InitExpr)) + return ILE->getInit(0)->isNullPointerConstant(Ctx, NPC); + } + // This expression must be an integer type. + if (!getType()->isIntegerType() || + (Ctx.getLangOptions().CPlusPlus && getType()->isEnumeralType())) + return NPCK_NotNull; + + // If we have an integer constant expression, we need to *evaluate* it and + // test for the value 0. + llvm::APSInt Result; + bool IsNull = isIntegerConstantExpr(Result, Ctx) && Result == 0; + + return (IsNull ? NPCK_ZeroInteger : NPCK_NotNull); +} + +/// \brief If this expression is an l-value for an Objective C +/// property, find the underlying property reference expression. +const ObjCPropertyRefExpr *Expr::getObjCProperty() const { + const Expr *E = this; + while (true) { + assert((E->getValueKind() == VK_LValue && + E->getObjectKind() == OK_ObjCProperty) && + "expression is not a property reference"); + E = E->IgnoreParenCasts(); + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->getOpcode() == BO_Comma) { + E = BO->getRHS(); + continue; + } + } + + break; + } + + return cast<ObjCPropertyRefExpr>(E); +} + +FieldDecl *Expr::getBitField() { + Expr *E = this->IgnoreParens(); + + while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_LValueToRValue || + (ICE->getValueKind() != VK_RValue && ICE->getCastKind() == CK_NoOp)) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + + if (MemberExpr *MemRef = dyn_cast<MemberExpr>(E)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(MemRef->getMemberDecl())) + if (Field->isBitField()) + return Field; + + if (DeclRefExpr *DeclRef = dyn_cast<DeclRefExpr>(E)) + if (FieldDecl *Field = dyn_cast<FieldDecl>(DeclRef->getDecl())) + if (Field->isBitField()) + return Field; + + if (BinaryOperator *BinOp = dyn_cast<BinaryOperator>(E)) + if (BinOp->isAssignmentOp() && BinOp->getLHS()) + return BinOp->getLHS()->getBitField(); + + return 0; +} + +bool Expr::refersToVectorElement() const { + const Expr *E = this->IgnoreParens(); + + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getValueKind() != VK_RValue && + ICE->getCastKind() == CK_NoOp) + E = ICE->getSubExpr()->IgnoreParens(); + else + break; + } + + if (const ArraySubscriptExpr *ASE = dyn_cast<ArraySubscriptExpr>(E)) + return ASE->getBase()->getType()->isVectorType(); + + if (isa<ExtVectorElementExpr>(E)) + return true; + + return false; +} + +/// 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()->getAs<VectorType>()) + return VT->getNumElements(); + return 1; +} + +/// containsDuplicateElements - Return true if any element access is repeated. +bool ExtVectorElementExpr::containsDuplicateElements() const { + // FIXME: Refactor this code to an accessor on the AST node which returns the + // "type" of component access, and share with code below and in Sema. + llvm::StringRef Comp = Accessor->getName(); + + // Halving swizzles do not contain duplicate elements. + if (Comp == "hi" || Comp == "lo" || Comp == "even" || Comp == "odd") + return false; + + // Advance past s-char prefix on hex swizzles. + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); + + for (unsigned i = 0, e = Comp.size(); i != e; ++i) + if (Comp.substr(i + 1).find(Comp[i]) != llvm::StringRef::npos) + return true; + + return false; +} + +/// getEncodedElementAccess - We encode the fields as a llvm ConstantArray. +void ExtVectorElementExpr::getEncodedElementAccess( + llvm::SmallVectorImpl<unsigned> &Elts) const { + llvm::StringRef Comp = Accessor->getName(); + if (Comp[0] == 's' || Comp[0] == 'S') + Comp = Comp.substr(1); + + bool isHi = Comp == "hi"; + bool isLo = Comp == "lo"; + bool isEven = Comp == "even"; + bool isOdd = Comp == "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(Comp[i]); + + Elts.push_back(Index); + } +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, + /*TypeDependent=*/false, /*ValueDependent=*/false, + /*ContainsUnexpandedParameterPack=*/false), + NumArgs(NumArgs), Kind(IsInstanceSuper? SuperInstance : SuperClass), + HasMethod(Method != 0), SuperLoc(SuperLoc), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(SuperType.getAsOpaquePtr()); + if (NumArgs) + memcpy(getArgs(), Args, NumArgs * sizeof(Expr *)); +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, T->isDependentType(), + T->isDependentType(), T->containsUnexpandedParameterPack()), + NumArgs(NumArgs), Kind(Class), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + Expr **MyArgs = getArgs(); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (Args[I]->isValueDependent()) + ExprBits.ValueDependent = true; + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + MyArgs[I] = Args[I]; + } +} + +ObjCMessageExpr::ObjCMessageExpr(QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) + : Expr(ObjCMessageExprClass, T, VK, OK_Ordinary, Receiver->isTypeDependent(), + Receiver->isTypeDependent(), + Receiver->containsUnexpandedParameterPack()), + NumArgs(NumArgs), Kind(Instance), HasMethod(Method != 0), + SelectorOrMethod(reinterpret_cast<uintptr_t>(Method? Method + : Sel.getAsOpaquePtr())), + SelectorLoc(SelLoc), LBracLoc(LBracLoc), RBracLoc(RBracLoc) +{ + setReceiverPointer(Receiver); + Expr **MyArgs = getArgs(); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (Args[I]->isValueDependent()) + ExprBits.ValueDependent = true; + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + MyArgs[I] = Args[I]; + } +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + SourceLocation SuperLoc, + bool IsInstanceSuper, + QualType SuperType, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, SuperLoc, IsInstanceSuper, + SuperType, Sel, SelLoc, Method, Args,NumArgs, + RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + TypeSourceInfo *Receiver, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, + Method, Args, NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::Create(ASTContext &Context, QualType T, + ExprValueKind VK, + SourceLocation LBracLoc, + Expr *Receiver, + Selector Sel, + SourceLocation SelLoc, + ObjCMethodDecl *Method, + Expr **Args, unsigned NumArgs, + SourceLocation RBracLoc) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(T, VK, LBracLoc, Receiver, Sel, SelLoc, + Method, Args, NumArgs, RBracLoc); +} + +ObjCMessageExpr *ObjCMessageExpr::CreateEmpty(ASTContext &Context, + unsigned NumArgs) { + unsigned Size = sizeof(ObjCMessageExpr) + sizeof(void *) + + NumArgs * sizeof(Expr *); + void *Mem = Context.Allocate(Size, llvm::AlignOf<ObjCMessageExpr>::Alignment); + return new (Mem) ObjCMessageExpr(EmptyShell(), NumArgs); +} + +SourceRange ObjCMessageExpr::getReceiverRange() const { + switch (getReceiverKind()) { + case Instance: + return getInstanceReceiver()->getSourceRange(); + + case Class: + return getClassReceiverTypeInfo()->getTypeLoc().getSourceRange(); + + case SuperInstance: + case SuperClass: + return getSuperLoc(); + } + + return SourceLocation(); +} + +Selector ObjCMessageExpr::getSelector() const { + if (HasMethod) + return reinterpret_cast<const ObjCMethodDecl *>(SelectorOrMethod) + ->getSelector(); + return Selector(SelectorOrMethod); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + switch (getReceiverKind()) { + case Instance: + if (const ObjCObjectPointerType *Ptr + = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + break; + + case Class: + if (const ObjCObjectType *Ty + = getClassReceiver()->getAs<ObjCObjectType>()) + return Ty->getInterface(); + break; + + case SuperInstance: + if (const ObjCObjectPointerType *Ptr + = getSuperType()->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + break; + + case SuperClass: + if (const ObjCObjectType *Iface + = getSuperType()->getAs<ObjCObjectType>()) + return Iface->getInterface(); + break; + } + + return 0; +} + +bool ChooseExpr::isConditionTrue(const ASTContext &C) const { + return getCond()->EvaluateAsInt(C) != 0; +} + +ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP) + : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, + Type->isDependentType(), Type->isDependentType(), + Type->containsUnexpandedParameterPack()), + BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) +{ + SubExprs = new (C) Stmt*[nexpr]; + for (unsigned i = 0; i < nexpr; i++) { + if (args[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i] = args[i]; + } +} + +void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, + unsigned NumExprs) { + if (SubExprs) C.Deallocate(SubExprs); + + SubExprs = new (C) Stmt* [NumExprs]; + this->NumExprs = NumExprs; + memcpy(SubExprs, Exprs, sizeof(Expr *) * NumExprs); +} + +GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack, + unsigned ResultIndex) + : Expr(GenericSelectionExprClass, + AssocExprs[ResultIndex]->getType(), + AssocExprs[ResultIndex]->getValueKind(), + AssocExprs[ResultIndex]->getObjectKind(), + AssocExprs[ResultIndex]->isTypeDependent(), + AssocExprs[ResultIndex]->isValueDependent(), + ContainsUnexpandedParameterPack), + AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), + SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), + ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), + RParenLoc(RParenLoc) { + SubExprs[CONTROLLING] = ControllingExpr; + std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); + std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); +} + +GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, + SourceLocation GenericLoc, Expr *ControllingExpr, + TypeSourceInfo **AssocTypes, Expr **AssocExprs, + unsigned NumAssocs, SourceLocation DefaultLoc, + SourceLocation RParenLoc, + bool ContainsUnexpandedParameterPack) + : Expr(GenericSelectionExprClass, + Context.DependentTy, + VK_RValue, + OK_Ordinary, + /*isTypeDependent=*/ true, + /*isValueDependent=*/ true, + ContainsUnexpandedParameterPack), + AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), + SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), + ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), + RParenLoc(RParenLoc) { + SubExprs[CONTROLLING] = ControllingExpr; + std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); + std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); +} + +//===----------------------------------------------------------------------===// +// 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(ASTContext &C, QualType Ty, + unsigned NumDesignators, + const Designator *Designators, + SourceLocation EqualOrColonLoc, + bool GNUSyntax, + Expr **IndexExprs, + unsigned NumIndexExprs, + Expr *Init) + : Expr(DesignatedInitExprClass, Ty, + Init->getValueKind(), Init->getObjectKind(), + Init->isTypeDependent(), Init->isValueDependent(), + Init->containsUnexpandedParameterPack()), + EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), + NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + this->Designators = new (C) Designator[NumDesignators]; + + // Record the initializer itself. + child_range Child = children(); + *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]; + if (Index->isTypeDependent() || Index->isValueDependent()) + ExprBits.ValueDependent = true; + + // Propagate unexpanded parameter packs. + if (Index->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + // 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]; + if (Start->isTypeDependent() || Start->isValueDependent() || + End->isTypeDependent() || End->isValueDependent()) + ExprBits.ValueDependent = true; + + // Propagate unexpanded parameter packs. + if (Start->containsUnexpandedParameterPack() || + End->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + // 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, 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(ASTContext &C, + const Designator *Desigs, + unsigned NumDesigs) { + Designators = new (C) Designator[NumDesigs]; + NumDesignators = NumDesigs; + for (unsigned I = 0; I != NumDesigs; ++I) + Designators[I] = Desigs[I]; +} + +SourceRange DesignatedInitExpr::getDesignatorsSourceRange() const { + DesignatedInitExpr *DIE = const_cast<DesignatedInitExpr*>(this); + if (size() == 1) + return DIE->getDesignator(0)->getSourceRange(); + return SourceRange(DIE->getDesignator(0)->getStartLocation(), + DIE->getDesignator(size()-1)->getEndLocation()); +} + +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(ASTContext &C, 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 (C) 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); + Designators = NewDesignators; + NumDesignators = NumDesignators - 1 + NumNewDesignators; +} + +ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, + Expr **exprs, unsigned nexprs, + SourceLocation rparenloc) + : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, + false, false, false), + NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { + + Exprs = new (C) Stmt*[nexprs]; + for (unsigned i = 0; i != nexprs; ++i) { + if (exprs[i]->isTypeDependent()) + ExprBits.TypeDependent = true; + if (exprs[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (exprs[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + Exprs[i] = exprs[i]; + } +} + +const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { + if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) + e = ewc->getSubExpr(); + e = cast<CXXConstructExpr>(e)->getArg(0); + while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) + e = ice->getSubExpr(); + return cast<OpaqueValueExpr>(e); +} + +//===----------------------------------------------------------------------===// +// 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 +//===----------------------------------------------------------------------===// + +// UnaryExprOrTypeTraitExpr +Stmt::child_range UnaryExprOrTypeTraitExpr::children() { + // 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 (const VariableArrayType* T = dyn_cast<VariableArrayType>( + getArgumentType().getTypePtr())) + return child_range(child_iterator(T), child_iterator()); + return child_range(); + } + return child_range(&Argument.Ex, &Argument.Ex + 1); +} + +// ObjCMessageExpr +Stmt::child_range ObjCMessageExpr::children() { + Stmt **begin; + if (getReceiverKind() == Instance) + begin = reinterpret_cast<Stmt **>(this + 1); + else + begin = reinterpret_cast<Stmt **>(getArgs()); + return child_range(begin, + reinterpret_cast<Stmt **>(getArgs() + getNumArgs())); +} + +// Blocks +BlockDeclRefExpr::BlockDeclRefExpr(VarDecl *d, QualType t, ExprValueKind VK, + SourceLocation l, bool ByRef, + bool constAdded) + : Expr(BlockDeclRefExprClass, t, VK, OK_Ordinary, false, false, + d->isParameterPack()), + D(d), Loc(l), IsByRef(ByRef), ConstQualAdded(constAdded) +{ + bool TypeDependent = false; + bool ValueDependent = false; + computeDeclRefDependence(D, getType(), TypeDependent, ValueDependent); + ExprBits.TypeDependent = TypeDependent; + ExprBits.ValueDependent = ValueDependent; +} diff --git a/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp new file mode 100644 index 000000000000..1a1a0a36a65b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ExprCXX.cpp @@ -0,0 +1,973 @@ +//===--- 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/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +using namespace clang; + + +//===----------------------------------------------------------------------===// +// Child Iterators for iterating over subexpressions/substatements +//===----------------------------------------------------------------------===// + +QualType CXXTypeidExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for typeid(expr)"); + return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + +QualType CXXUuidofExpr::getTypeOperand() const { + assert(isTypeOperand() && "Cannot call getTypeOperand for __uuidof(expr)"); + return Operand.get<TypeSourceInfo *>()->getType().getNonReferenceType() + .getUnqualifiedType(); +} + +// CXXScalarValueInitExpr +SourceRange CXXScalarValueInitExpr::getSourceRange() const { + SourceLocation Start = RParenLoc; + if (TypeInfo) + Start = TypeInfo->getTypeLoc().getBeginLoc(); + return SourceRange(Start, RParenLoc); +} + +// CXXNewExpr +CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, + Expr **placementArgs, unsigned numPlaceArgs, + SourceRange TypeIdParens, Expr *arraySize, + CXXConstructorDecl *constructor, bool initializer, + Expr **constructorArgs, unsigned numConsArgs, + FunctionDecl *operatorDelete, + bool usualArrayDeleteWantsSize, QualType ty, + TypeSourceInfo *AllocatedTypeInfo, + SourceLocation startLoc, SourceLocation endLoc, + SourceLocation constructorLParen, + SourceLocation constructorRParen) + : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, + ty->isDependentType(), ty->isDependentType(), + ty->containsUnexpandedParameterPack()), + GlobalNew(globalNew), Initializer(initializer), + UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize), + SubExprs(0), OperatorNew(operatorNew), + OperatorDelete(operatorDelete), Constructor(constructor), + AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens), + StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen), + ConstructorRParen(constructorRParen) { + AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs); + unsigned i = 0; + if (Array) { + if (arraySize->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i++] = arraySize; + } + + for (unsigned j = 0; j < NumPlacementArgs; ++j) { + if (placementArgs[j]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i++] = placementArgs[j]; + } + + for (unsigned j = 0; j < NumConstructorArgs; ++j) { + if (constructorArgs[j]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + SubExprs[i++] = constructorArgs[j]; + } +} + +void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, + unsigned numPlaceArgs, unsigned numConsArgs){ + assert(SubExprs == 0 && "SubExprs already allocated"); + Array = isArray; + NumPlacementArgs = numPlaceArgs; + NumConstructorArgs = numConsArgs; + + unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs; + SubExprs = new (C) Stmt*[TotalSize]; +} + +bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { + return getOperatorNew()->getType()-> + castAs<FunctionProtoType>()->isNothrow(Ctx); +} + +// CXXDeleteExpr +QualType CXXDeleteExpr::getDestroyedType() const { + const Expr *Arg = getArgument(); + while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Arg)) { + if (ICE->getCastKind() != CK_UserDefinedConversion && + ICE->getType()->isVoidPointerType()) + Arg = ICE->getSubExpr(); + else + break; + } + // The type-to-delete may not be a pointer if it's a dependent type. + const QualType ArgType = Arg->getType(); + + if (ArgType->isDependentType() && !ArgType->isPointerType()) + return QualType(); + + return ArgType->getAs<PointerType>()->getPointeeType(); +} + +// CXXPseudoDestructorExpr +PseudoDestructorTypeStorage::PseudoDestructorTypeStorage(TypeSourceInfo *Info) + : Type(Info) +{ + Location = Info->getTypeLoc().getLocalSourceRange().getBegin(); +} + +CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(ASTContext &Context, + Expr *Base, bool isArrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, TypeSourceInfo *ScopeType, + SourceLocation ColonColonLoc, SourceLocation TildeLoc, + PseudoDestructorTypeStorage DestroyedType) + : Expr(CXXPseudoDestructorExprClass, + Context.getPointerType(Context.getFunctionType(Context.VoidTy, 0, 0, + FunctionProtoType::ExtProtoInfo())), + VK_RValue, OK_Ordinary, + /*isTypeDependent=*/(Base->isTypeDependent() || + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType()->isDependentType())), + /*isValueDependent=*/Base->isValueDependent(), + // ContainsUnexpandedParameterPack + (Base->containsUnexpandedParameterPack() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()) || + (ScopeType && + ScopeType->getType()->containsUnexpandedParameterPack()) || + (DestroyedType.getTypeSourceInfo() && + DestroyedType.getTypeSourceInfo()->getType() + ->containsUnexpandedParameterPack()))), + Base(static_cast<Stmt *>(Base)), IsArrow(isArrow), + OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), + ScopeType(ScopeType), ColonColonLoc(ColonColonLoc), TildeLoc(TildeLoc), + DestroyedType(DestroyedType) { } + +QualType CXXPseudoDestructorExpr::getDestroyedType() const { + if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) + return TInfo->getType(); + + return QualType(); +} + +SourceRange CXXPseudoDestructorExpr::getSourceRange() const { + SourceLocation End = DestroyedType.getLocation(); + if (TypeSourceInfo *TInfo = DestroyedType.getTypeSourceInfo()) + End = TInfo->getTypeLoc().getLocalSourceRange().getEnd(); + return SourceRange(Base->getLocStart(), End); +} + + +// UnresolvedLookupExpr +UnresolvedLookupExpr * +UnresolvedLookupExpr::Create(ASTContext &C, + CXXRecordDecl *NamingClass, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + bool ADL, + const TemplateArgumentListInfo &Args, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) +{ + void *Mem = C.Allocate(sizeof(UnresolvedLookupExpr) + + ExplicitTemplateArgumentList::sizeFor(Args)); + return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, NameInfo, + ADL, /*Overload*/ true, &Args, + Begin, End, /*StdIsAssociated=*/false); +} + +UnresolvedLookupExpr * +UnresolvedLookupExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { + std::size_t size = sizeof(UnresolvedLookupExpr); + if (HasExplicitTemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedLookupExpr>()); + UnresolvedLookupExpr *E = new (Mem) UnresolvedLookupExpr(EmptyShell()); + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; + return E; +} + +OverloadExpr::OverloadExpr(StmtClass K, ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End, + bool KnownDependent, + bool KnownContainsUnexpandedParameterPack) + : Expr(K, C.OverloadTy, VK_LValue, OK_Ordinary, KnownDependent, + KnownDependent, + (KnownContainsUnexpandedParameterPack || + NameInfo.containsUnexpandedParameterPack() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()))), + Results(0), NumResults(End - Begin), NameInfo(NameInfo), + QualifierLoc(QualifierLoc), HasExplicitTemplateArgs(TemplateArgs != 0) +{ + NumResults = End - Begin; + if (NumResults) { + // Determine whether this expression is type-dependent. + for (UnresolvedSetImpl::const_iterator I = Begin; I != End; ++I) { + if ((*I)->getDeclContext()->isDependentContext() || + isa<UnresolvedUsingValueDecl>(*I)) { + ExprBits.TypeDependent = true; + ExprBits.ValueDependent = true; + } + } + + Results = static_cast<DeclAccessPair *>( + C.Allocate(sizeof(DeclAccessPair) * NumResults, + llvm::alignOf<DeclAccessPair>())); + memcpy(Results, &*Begin.getIterator(), + NumResults * sizeof(DeclAccessPair)); + } + + // If we have explicit template arguments, check for dependent + // template arguments and whether they contain any unexpanded pack + // expansions. + if (TemplateArgs) { + bool Dependent = false; + bool ContainsUnexpandedParameterPack = false; + getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + ContainsUnexpandedParameterPack); + + if (Dependent) { + ExprBits.TypeDependent = true; + ExprBits.ValueDependent = true; + } + if (ContainsUnexpandedParameterPack) + ExprBits.ContainsUnexpandedParameterPack = true; + } + + if (isTypeDependent()) + setType(C.DependentTy); +} + +void OverloadExpr::initializeResults(ASTContext &C, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { + assert(Results == 0 && "Results already initialized!"); + NumResults = End - Begin; + if (NumResults) { + Results = static_cast<DeclAccessPair *>( + C.Allocate(sizeof(DeclAccessPair) * NumResults, + + llvm::alignOf<DeclAccessPair>())); + memcpy(Results, &*Begin.getIterator(), + NumResults * sizeof(DeclAccessPair)); + } +} + +CXXRecordDecl *OverloadExpr::getNamingClass() const { + if (isa<UnresolvedLookupExpr>(this)) + return cast<UnresolvedLookupExpr>(this)->getNamingClass(); + else + return cast<UnresolvedMemberExpr>(this)->getNamingClass(); +} + +// DependentScopeDeclRefExpr +DependentScopeDeclRefExpr::DependentScopeDeclRefExpr(QualType T, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *Args) + : Expr(DependentScopeDeclRefExprClass, T, VK_LValue, OK_Ordinary, + true, true, + (NameInfo.containsUnexpandedParameterPack() || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()))), + QualifierLoc(QualifierLoc), NameInfo(NameInfo), + HasExplicitTemplateArgs(Args != 0) +{ + if (Args) { + bool Dependent = true; + bool ContainsUnexpandedParameterPack + = ExprBits.ContainsUnexpandedParameterPack; + + reinterpret_cast<ExplicitTemplateArgumentList*>(this+1) + ->initializeFrom(*Args, Dependent, ContainsUnexpandedParameterPack); + ExprBits.ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack; + } +} + +DependentScopeDeclRefExpr * +DependentScopeDeclRefExpr::Create(ASTContext &C, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *Args) { + std::size_t size = sizeof(DependentScopeDeclRefExpr); + if (Args) + size += ExplicitTemplateArgumentList::sizeFor(*Args); + void *Mem = C.Allocate(size); + return new (Mem) DependentScopeDeclRefExpr(C.DependentTy, QualifierLoc, + NameInfo, Args); +} + +DependentScopeDeclRefExpr * +DependentScopeDeclRefExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { + std::size_t size = sizeof(DependentScopeDeclRefExpr); + if (HasExplicitTemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + void *Mem = C.Allocate(size); + DependentScopeDeclRefExpr *E + = new (Mem) DependentScopeDeclRefExpr(QualType(), NestedNameSpecifierLoc(), + DeclarationNameInfo(), 0); + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; + return E; +} + +SourceRange CXXConstructExpr::getSourceRange() const { + if (isa<CXXTemporaryObjectExpr>(this)) + return cast<CXXTemporaryObjectExpr>(this)->getSourceRange(); + + if (ParenRange.isValid()) + return SourceRange(Loc, ParenRange.getEnd()); + + SourceLocation End = Loc; + for (unsigned I = getNumArgs(); I > 0; --I) { + const Expr *Arg = getArg(I-1); + if (!Arg->isDefaultArgument()) { + SourceLocation NewEnd = Arg->getLocEnd(); + if (NewEnd.isValid()) { + End = NewEnd; + break; + } + } + } + + return SourceRange(Loc, End); +} + +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().getBegin(), + getOperatorLoc()); + } else if (Kind == OO_Arrow) { + return getArg(0)->getSourceRange(); + } 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() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return MemExpr->getBase(); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + +CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return cast<CXXMethodDecl>(MemExpr->getMemberDecl()); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + + +CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() { + Expr* ThisArg = getImplicitObjectArgument(); + if (!ThisArg) + return 0; + + if (ThisArg->getType()->isAnyPointerType()) + return ThisArg->getType()->getPointeeType()->getAsCXXRecordDecl(); + + return ThisArg->getType()->getAsCXXRecordDecl(); +} + + +//===----------------------------------------------------------------------===// +// 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>"; + } +} + +CXXStaticCastExpr *CXXStaticCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L, + SourceLocation RParenLoc) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXStaticCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXStaticCastExpr *E = + new (Buffer) CXXStaticCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXStaticCastExpr *CXXStaticCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CXXStaticCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXStaticCastExpr(EmptyShell(), PathSize); +} + +CXXDynamicCastExpr *CXXDynamicCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, + SourceLocation L, + SourceLocation RParenLoc) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXDynamicCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXDynamicCastExpr *E = + new (Buffer) CXXDynamicCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXDynamicCastExpr *CXXDynamicCastExpr::CreateEmpty(ASTContext &C, + unsigned PathSize) { + void *Buffer = + C.Allocate(sizeof(CXXDynamicCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXDynamicCastExpr(EmptyShell(), PathSize); +} + +/// isAlwaysNull - Return whether the result of the dynamic_cast is proven +/// to always be null. For example: +/// +/// struct A { }; +/// struct B final : A { }; +/// struct C { }; +/// +/// C *f(B* b) { return dynamic_cast<C*>(b); } +bool CXXDynamicCastExpr::isAlwaysNull() const +{ + QualType SrcType = getSubExpr()->getType(); + QualType DestType = getType(); + + if (const PointerType *SrcPTy = SrcType->getAs<PointerType>()) { + SrcType = SrcPTy->getPointeeType(); + DestType = DestType->castAs<PointerType>()->getPointeeType(); + } + + const CXXRecordDecl *SrcRD = + cast<CXXRecordDecl>(SrcType->castAs<RecordType>()->getDecl()); + + if (!SrcRD->hasAttr<FinalAttr>()) + return false; + + const CXXRecordDecl *DestRD = + cast<CXXRecordDecl>(DestType->castAs<RecordType>()->getDecl()); + + return !DestRD->isDerivedFrom(SrcRD); +} + +CXXReinterpretCastExpr * +CXXReinterpretCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, + CastKind K, Expr *Op, + const CXXCastPath *BasePath, + TypeSourceInfo *WrittenTy, SourceLocation L, + SourceLocation RParenLoc) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = + C.Allocate(sizeof(CXXReinterpretCastExpr) + PathSize * sizeof(CXXBaseSpecifier*)); + CXXReinterpretCastExpr *E = + new (Buffer) CXXReinterpretCastExpr(T, VK, K, Op, PathSize, WrittenTy, L, + RParenLoc); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXReinterpretCastExpr * +CXXReinterpretCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = C.Allocate(sizeof(CXXReinterpretCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXReinterpretCastExpr(EmptyShell(), PathSize); +} + +CXXConstCastExpr *CXXConstCastExpr::Create(ASTContext &C, QualType T, + ExprValueKind VK, Expr *Op, + TypeSourceInfo *WrittenTy, + SourceLocation L, + SourceLocation RParenLoc) { + return new (C) CXXConstCastExpr(T, VK, Op, WrittenTy, L, RParenLoc); +} + +CXXConstCastExpr *CXXConstCastExpr::CreateEmpty(ASTContext &C) { + return new (C) CXXConstCastExpr(EmptyShell()); +} + +CXXFunctionalCastExpr * +CXXFunctionalCastExpr::Create(ASTContext &C, QualType T, ExprValueKind VK, + TypeSourceInfo *Written, SourceLocation L, + CastKind K, Expr *Op, const CXXCastPath *BasePath, + SourceLocation R) { + unsigned PathSize = (BasePath ? BasePath->size() : 0); + void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + CXXFunctionalCastExpr *E = + new (Buffer) CXXFunctionalCastExpr(T, VK, Written, L, K, Op, PathSize, R); + if (PathSize) E->setCastPath(*BasePath); + return E; +} + +CXXFunctionalCastExpr * +CXXFunctionalCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { + void *Buffer = C.Allocate(sizeof(CXXFunctionalCastExpr) + + PathSize * sizeof(CXXBaseSpecifier*)); + return new (Buffer) CXXFunctionalCastExpr(EmptyShell(), PathSize); +} + + +CXXDefaultArgExpr * +CXXDefaultArgExpr::Create(ASTContext &C, SourceLocation Loc, + ParmVarDecl *Param, Expr *SubExpr) { + void *Mem = C.Allocate(sizeof(CXXDefaultArgExpr) + sizeof(Stmt *)); + return new (Mem) CXXDefaultArgExpr(CXXDefaultArgExprClass, Loc, Param, + SubExpr); +} + +CXXTemporary *CXXTemporary::Create(ASTContext &C, + const CXXDestructorDecl *Destructor) { + return new (C) CXXTemporary(Destructor); +} + +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); +} + +CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, + CXXConstructorDecl *Cons, + TypeSourceInfo *Type, + Expr **Args, + unsigned NumArgs, + SourceRange parenRange, + bool ZeroInitialization) + : CXXConstructExpr(C, CXXTemporaryObjectExprClass, + Type->getType().getNonReferenceType(), + Type->getTypeLoc().getBeginLoc(), + Cons, false, Args, NumArgs, ZeroInitialization, + CXXConstructExpr::CK_Complete, parenRange), + Type(Type) { +} + +SourceRange CXXTemporaryObjectExpr::getSourceRange() const { + return SourceRange(Type->getTypeLoc().getBeginLoc(), + getParenRange().getEnd()); +} + +CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, + SourceLocation Loc, + CXXConstructorDecl *D, bool Elidable, + Expr **Args, unsigned NumArgs, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange) { + return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, + Elidable, Args, NumArgs, ZeroInitialization, + ConstructKind, ParenRange); +} + +CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, + SourceLocation Loc, + CXXConstructorDecl *D, bool elidable, + Expr **args, unsigned numargs, + bool ZeroInitialization, + ConstructionKind ConstructKind, + SourceRange ParenRange) + : Expr(SC, T, VK_RValue, OK_Ordinary, + T->isDependentType(), T->isDependentType(), + T->containsUnexpandedParameterPack()), + Constructor(D), Loc(Loc), ParenRange(ParenRange), Elidable(elidable), + ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), + Args(0), NumArgs(numargs) +{ + if (NumArgs) { + Args = new (C) Stmt*[NumArgs]; + + for (unsigned i = 0; i != NumArgs; ++i) { + assert(args[i] && "NULL argument in CXXConstructExpr"); + + if (args[i]->isValueDependent()) + ExprBits.ValueDependent = true; + if (args[i]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + Args[i] = args[i]; + } + } +} + +ExprWithCleanups::ExprWithCleanups(ASTContext &C, + Expr *subexpr, + CXXTemporary **temps, + unsigned numtemps) + : Expr(ExprWithCleanupsClass, subexpr->getType(), + subexpr->getValueKind(), subexpr->getObjectKind(), + subexpr->isTypeDependent(), subexpr->isValueDependent(), + subexpr->containsUnexpandedParameterPack()), + SubExpr(subexpr), Temps(0), NumTemps(0) { + if (numtemps) { + setNumTemporaries(C, numtemps); + for (unsigned i = 0; i != numtemps; ++i) + Temps[i] = temps[i]; + } +} + +void ExprWithCleanups::setNumTemporaries(ASTContext &C, unsigned N) { + assert(Temps == 0 && "Cannot resize with this"); + NumTemps = N; + Temps = new (C) CXXTemporary*[NumTemps]; +} + + +ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, + Expr *SubExpr, + CXXTemporary **Temps, + unsigned NumTemps) { + return new (C) ExprWithCleanups(C, SubExpr, Temps, NumTemps); +} + +CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) + : Expr(CXXUnresolvedConstructExprClass, + Type->getType().getNonReferenceType(), + VK_LValue, OK_Ordinary, + Type->getType()->isDependentType(), true, + Type->getType()->containsUnexpandedParameterPack()), + Type(Type), + LParenLoc(LParenLoc), + RParenLoc(RParenLoc), + NumArgs(NumArgs) { + Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I]->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + + StoredArgs[I] = Args[I]; + } +} + +CXXUnresolvedConstructExpr * +CXXUnresolvedConstructExpr::Create(ASTContext &C, + TypeSourceInfo *Type, + SourceLocation LParenLoc, + Expr **Args, + unsigned NumArgs, + SourceLocation RParenLoc) { + void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + + sizeof(Expr *) * NumArgs); + return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, + Args, NumArgs, RParenLoc); +} + +CXXUnresolvedConstructExpr * +CXXUnresolvedConstructExpr::CreateEmpty(ASTContext &C, unsigned NumArgs) { + Stmt::EmptyShell Empty; + void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + + sizeof(Expr *) * NumArgs); + return new (Mem) CXXUnresolvedConstructExpr(Empty, NumArgs); +} + +SourceRange CXXUnresolvedConstructExpr::getSourceRange() const { + return SourceRange(Type->getTypeLoc().getBeginLoc(), RParenLoc); +} + +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs) + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, + VK_LValue, OK_Ordinary, true, true, + ((Base && Base->containsUnexpandedParameterPack()) || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier() + ->containsUnexpandedParameterPack()) || + MemberNameInfo.containsUnexpandedParameterPack())), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(TemplateArgs != 0), + OperatorLoc(OperatorLoc), QualifierLoc(QualifierLoc), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + MemberNameInfo(MemberNameInfo) { + if (TemplateArgs) { + bool Dependent = true; + bool ContainsUnexpandedParameterPack = false; + getExplicitTemplateArgs().initializeFrom(*TemplateArgs, Dependent, + ContainsUnexpandedParameterPack); + if (ContainsUnexpandedParameterPack) + ExprBits.ContainsUnexpandedParameterPack = true; + } +} + +CXXDependentScopeMemberExpr::CXXDependentScopeMemberExpr(ASTContext &C, + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo) + : Expr(CXXDependentScopeMemberExprClass, C.DependentTy, + VK_LValue, OK_Ordinary, true, true, + ((Base && Base->containsUnexpandedParameterPack()) || + (QualifierLoc && + QualifierLoc.getNestedNameSpecifier()-> + containsUnexpandedParameterPack()) || + MemberNameInfo.containsUnexpandedParameterPack())), + Base(Base), BaseType(BaseType), IsArrow(IsArrow), + HasExplicitTemplateArgs(false), OperatorLoc(OperatorLoc), + QualifierLoc(QualifierLoc), + FirstQualifierFoundInScope(FirstQualifierFoundInScope), + MemberNameInfo(MemberNameInfo) { } + +CXXDependentScopeMemberExpr * +CXXDependentScopeMemberExpr::Create(ASTContext &C, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + NamedDecl *FirstQualifierFoundInScope, + DeclarationNameInfo MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs) { + if (!TemplateArgs) + return new (C) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + QualifierLoc, + FirstQualifierFoundInScope, + MemberNameInfo); + + std::size_t size = sizeof(CXXDependentScopeMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); + return new (Mem) CXXDependentScopeMemberExpr(C, Base, BaseType, + IsArrow, OperatorLoc, + QualifierLoc, + FirstQualifierFoundInScope, + MemberNameInfo, TemplateArgs); +} + +CXXDependentScopeMemberExpr * +CXXDependentScopeMemberExpr::CreateEmpty(ASTContext &C, + bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { + if (!HasExplicitTemplateArgs) + return new (C) CXXDependentScopeMemberExpr(C, 0, QualType(), + 0, SourceLocation(), + NestedNameSpecifierLoc(), 0, + DeclarationNameInfo()); + + std::size_t size = sizeof(CXXDependentScopeMemberExpr) + + ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + void *Mem = C.Allocate(size, llvm::alignOf<CXXDependentScopeMemberExpr>()); + CXXDependentScopeMemberExpr *E + = new (Mem) CXXDependentScopeMemberExpr(C, 0, QualType(), + 0, SourceLocation(), + NestedNameSpecifierLoc(), 0, + DeclarationNameInfo(), 0); + E->HasExplicitTemplateArgs = true; + return E; +} + +bool CXXDependentScopeMemberExpr::isImplicitAccess() const { + if (Base == 0) + return true; + + return cast<Expr>(Base)->isImplicitCXXThis(); +} + +static bool hasOnlyNonStaticMemberFunctions(UnresolvedSetIterator begin, + UnresolvedSetIterator end) { + do { + NamedDecl *decl = *begin; + if (isa<UnresolvedUsingValueDecl>(decl)) + return false; + if (isa<UsingShadowDecl>(decl)) + decl = cast<UsingShadowDecl>(decl)->getUnderlyingDecl(); + + // Unresolved member expressions should only contain methods and + // method templates. + assert(isa<CXXMethodDecl>(decl) || isa<FunctionTemplateDecl>(decl)); + + if (isa<FunctionTemplateDecl>(decl)) + decl = cast<FunctionTemplateDecl>(decl)->getTemplatedDecl(); + if (cast<CXXMethodDecl>(decl)->isStatic()) + return false; + } while (++begin != end); + + return true; +} + +UnresolvedMemberExpr::UnresolvedMemberExpr(ASTContext &C, + bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, + bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) + : OverloadExpr(UnresolvedMemberExprClass, C, QualifierLoc, MemberNameInfo, + TemplateArgs, Begin, End, + // Dependent + ((Base && Base->isTypeDependent()) || + BaseType->isDependentType()), + // Contains unexpanded parameter pack + ((Base && Base->containsUnexpandedParameterPack()) || + BaseType->containsUnexpandedParameterPack())), + IsArrow(IsArrow), HasUnresolvedUsing(HasUnresolvedUsing), + Base(Base), BaseType(BaseType), OperatorLoc(OperatorLoc) { + + // Check whether all of the members are non-static member functions, + // and if so, mark give this bound-member type instead of overload type. + if (hasOnlyNonStaticMemberFunctions(Begin, End)) + setType(C.BoundMemberTy); +} + +bool UnresolvedMemberExpr::isImplicitAccess() const { + if (Base == 0) + return true; + + return cast<Expr>(Base)->isImplicitCXXThis(); +} + +UnresolvedMemberExpr * +UnresolvedMemberExpr::Create(ASTContext &C, + bool HasUnresolvedUsing, + Expr *Base, QualType BaseType, bool IsArrow, + SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, + const DeclarationNameInfo &MemberNameInfo, + const TemplateArgumentListInfo *TemplateArgs, + UnresolvedSetIterator Begin, + UnresolvedSetIterator End) { + std::size_t size = sizeof(UnresolvedMemberExpr); + if (TemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(*TemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); + return new (Mem) UnresolvedMemberExpr(C, + HasUnresolvedUsing, Base, BaseType, + IsArrow, OperatorLoc, QualifierLoc, + MemberNameInfo, TemplateArgs, Begin, End); +} + +UnresolvedMemberExpr * +UnresolvedMemberExpr::CreateEmpty(ASTContext &C, bool HasExplicitTemplateArgs, + unsigned NumTemplateArgs) { + std::size_t size = sizeof(UnresolvedMemberExpr); + if (HasExplicitTemplateArgs) + size += ExplicitTemplateArgumentList::sizeFor(NumTemplateArgs); + + void *Mem = C.Allocate(size, llvm::alignOf<UnresolvedMemberExpr>()); + UnresolvedMemberExpr *E = new (Mem) UnresolvedMemberExpr(EmptyShell()); + E->HasExplicitTemplateArgs = HasExplicitTemplateArgs; + return E; +} + +CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { + // Unlike for UnresolvedLookupExpr, it is very easy to re-derive this. + + // If there was a nested name specifier, it names the naming class. + // It can't be dependent: after all, we were actually able to do the + // lookup. + CXXRecordDecl *Record = 0; + if (getQualifier()) { + const Type *T = getQualifier()->getAsType(); + assert(T && "qualifier in member expression does not name type"); + Record = T->getAsCXXRecordDecl(); + assert(Record && "qualifier in member expression does not name record"); + } + // Otherwise the naming class must have been the base class. + else { + QualType BaseType = getBaseType().getNonReferenceType(); + if (isArrow()) { + const PointerType *PT = BaseType->getAs<PointerType>(); + assert(PT && "base of arrow member access is not pointer"); + BaseType = PT->getPointeeType(); + } + + Record = BaseType->getAsCXXRecordDecl(); + assert(Record && "base of member expression does not name record"); + } + + return Record; +} + +SubstNonTypeTemplateParmPackExpr:: +SubstNonTypeTemplateParmPackExpr(QualType T, + NonTypeTemplateParmDecl *Param, + SourceLocation NameLoc, + const TemplateArgument &ArgPack) + : Expr(SubstNonTypeTemplateParmPackExprClass, T, VK_RValue, OK_Ordinary, + true, false, true), + Param(Param), Arguments(ArgPack.pack_begin()), + NumArguments(ArgPack.pack_size()), NameLoc(NameLoc) { } + +TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); +} + + diff --git a/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp new file mode 100644 index 000000000000..d177cb5cbc97 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ExprClassification.cpp @@ -0,0 +1,620 @@ +//===--- ExprClassification.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 Expr::classify. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/ErrorHandling.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclTemplate.h" +using namespace clang; + +typedef Expr::Classification Cl; + +static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E); +static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D); +static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T); +static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E); +static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E); +static Cl::Kinds ClassifyConditional(ASTContext &Ctx, + const Expr *trueExpr, + const Expr *falseExpr); +static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, + Cl::Kinds Kind, SourceLocation &Loc); + +static Cl::Kinds ClassifyExprValueKind(const LangOptions &Lang, + const Expr *E, + ExprValueKind Kind) { + switch (Kind) { + case VK_RValue: + return Lang.CPlusPlus && E->getType()->isRecordType() ? + Cl::CL_ClassTemporary : Cl::CL_PRValue; + case VK_LValue: + return Cl::CL_LValue; + case VK_XValue: + return Cl::CL_XValue; + } + llvm_unreachable("Invalid value category of implicit cast."); + return Cl::CL_PRValue; +} + +Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { + assert(!TR->isReferenceType() && "Expressions can't have reference type."); + + Cl::Kinds kind = ClassifyInternal(Ctx, this); + // C99 6.3.2.1: An lvalue is an expression with an object type or an + // incomplete type other than void. + if (!Ctx.getLangOptions().CPlusPlus) { + // Thus, no functions. + if (TR->isFunctionType() || TR == Ctx.OverloadTy) + kind = Cl::CL_Function; + // No void either, but qualified void is OK because it is "other than void". + // Void "lvalues" are classified as addressable void values, which are void + // expressions whose address can be taken. + else if (TR->isVoidType() && !TR.hasQualifiers()) + kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void); + } + + // Enable this assertion for testing. + switch (kind) { + case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break; + case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; + case Cl::CL_Function: + case Cl::CL_Void: + case Cl::CL_AddressableVoid: + case Cl::CL_DuplicateVectorComponents: + case Cl::CL_MemberFunction: + case Cl::CL_SubObjCPropertySetting: + case Cl::CL_ClassTemporary: + case Cl::CL_ObjCMessageRValue: + case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; + } + + Cl::ModifiableType modifiable = Cl::CM_Untested; + if (Loc) + modifiable = IsModifiable(Ctx, this, kind, *Loc); + return Classification(kind, modifiable); +} + +static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { + // This function takes the first stab at classifying expressions. + const LangOptions &Lang = Ctx.getLangOptions(); + + switch (E->getStmtClass()) { + // First come the expressions that are always lvalues, unconditionally. + case Stmt::NoStmtClass: +#define ABSTRACT_STMT(Kind) +#define STMT(Kind, Base) case Expr::Kind##Class: +#define EXPR(Kind, Base) +#include "clang/AST/StmtNodes.inc" + llvm_unreachable("cannot classify a statement"); + break; + case Expr::ObjCIsaExprClass: + // C++ [expr.prim.general]p1: A string literal is an lvalue. + case Expr::StringLiteralClass: + // @encode is equivalent to its string + case Expr::ObjCEncodeExprClass: + // __func__ and friends are too. + case Expr::PredefinedExprClass: + // Property references are lvalues + case Expr::ObjCPropertyRefExprClass: + // C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of... + case Expr::CXXTypeidExprClass: + // Unresolved lookups get classified as lvalues. + // FIXME: Is this wise? Should they get their own kind? + case Expr::UnresolvedLookupExprClass: + case Expr::UnresolvedMemberExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::DependentScopeDeclRefExprClass: + // ObjC instance variables are lvalues + // FIXME: ObjC++0x might have different rules + case Expr::ObjCIvarRefExprClass: + return Cl::CL_LValue; + // C99 6.5.2.5p5 says that compound literals are lvalues. + // In C++, they're class temporaries. + case Expr::CompoundLiteralExprClass: + return Ctx.getLangOptions().CPlusPlus? Cl::CL_ClassTemporary + : Cl::CL_LValue; + + // Expressions that are prvalues. + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnaryExprOrTypeTraitExprClass: + case Expr::CXXNewExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::ImaginaryLiteralClass: + case Expr::GNUNullExprClass: + case Expr::OffsetOfExprClass: + case Expr::CXXThrowExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::AddrLabelExprClass: + case Expr::CXXDeleteExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::BlockExprClass: + case Expr::FloatingLiteralClass: + case Expr::CXXNoexceptExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ParenListExprClass: + case Expr::InitListExprClass: + case Expr::SizeOfPackExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: + return Cl::CL_PRValue; + + // Next come the complicated cases. + + // C++ [expr.sub]p1: The result is an lvalue of type "T". + // However, subscripting vector types is more like member access. + case Expr::ArraySubscriptExprClass: + if (cast<ArraySubscriptExpr>(E)->getBase()->getType()->isVectorType()) + return ClassifyInternal(Ctx, cast<ArraySubscriptExpr>(E)->getBase()); + return Cl::CL_LValue; + + // C++ [expr.prim.general]p3: The result is an lvalue if the entity is a + // function or variable and a prvalue otherwise. + case Expr::DeclRefExprClass: + if (E->getType() == Ctx.UnknownAnyTy) + return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl()) + ? Cl::CL_PRValue : Cl::CL_LValue; + return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl()); + // We deal with names referenced from blocks the same way. + case Expr::BlockDeclRefExprClass: + return ClassifyDecl(Ctx, cast<BlockDeclRefExpr>(E)->getDecl()); + + // Member access is complex. + case Expr::MemberExprClass: + return ClassifyMemberExpr(Ctx, cast<MemberExpr>(E)); + + case Expr::UnaryOperatorClass: + switch (cast<UnaryOperator>(E)->getOpcode()) { + // C++ [expr.unary.op]p1: The unary * operator performs indirection: + // [...] the result is an lvalue referring to the object or function + // to which the expression points. + case UO_Deref: + return Cl::CL_LValue; + + // GNU extensions, simply look through them. + case UO_Extension: + return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr()); + + // Treat _Real and _Imag basically as if they were member + // expressions: l-value only if the operand is a true l-value. + case UO_Real: + case UO_Imag: { + const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + Cl::Kinds K = ClassifyInternal(Ctx, Op); + if (K != Cl::CL_LValue) return K; + + if (isa<ObjCPropertyRefExpr>(Op)) + return Cl::CL_SubObjCPropertySetting; + return Cl::CL_LValue; + } + + // C++ [expr.pre.incr]p1: The result is the updated operand; it is an + // lvalue, [...] + // Not so in C. + case UO_PreInc: + case UO_PreDec: + return Lang.CPlusPlus ? Cl::CL_LValue : Cl::CL_PRValue; + + default: + return Cl::CL_PRValue; + } + + case Expr::OpaqueValueExprClass: + return ClassifyExprValueKind(Lang, E, + cast<OpaqueValueExpr>(E)->getValueKind()); + + // Implicit casts are lvalues if they're lvalue casts. Other than that, we + // only specifically record class temporaries. + case Expr::ImplicitCastExprClass: + return ClassifyExprValueKind(Lang, E, + cast<ImplicitCastExpr>(E)->getValueKind()); + + // C++ [expr.prim.general]p4: The presence of parentheses does not affect + // whether the expression is an lvalue. + case Expr::ParenExprClass: + return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr()); + + // C1X 6.5.1.1p4: [A generic selection] is an lvalue, a function designator, + // or a void expression if its result expression is, respectively, an + // lvalue, a function designator, or a void expression. + case Expr::GenericSelectionExprClass: + if (cast<GenericSelectionExpr>(E)->isResultDependent()) + return Cl::CL_PRValue; + return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr()); + + case Expr::BinaryOperatorClass: + case Expr::CompoundAssignOperatorClass: + // C doesn't have any binary expressions that are lvalues. + if (Lang.CPlusPlus) + return ClassifyBinaryOp(Ctx, cast<BinaryOperator>(E)); + return Cl::CL_PRValue; + + case Expr::CallExprClass: + case Expr::CXXOperatorCallExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CUDAKernelCallExprClass: + return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType()); + + // __builtin_choose_expr is equivalent to the chosen expression. + case Expr::ChooseExprClass: + return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr(Ctx)); + + // Extended vector element access is an lvalue unless there are duplicates + // in the shuffle expression. + case Expr::ExtVectorElementExprClass: + return cast<ExtVectorElementExpr>(E)->containsDuplicateElements() ? + Cl::CL_DuplicateVectorComponents : Cl::CL_LValue; + + // Simply look at the actual default argument. + case Expr::CXXDefaultArgExprClass: + return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr()); + + // Same idea for temporary binding. + case Expr::CXXBindTemporaryExprClass: + return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); + + // And the cleanups guard. + case Expr::ExprWithCleanupsClass: + return ClassifyInternal(Ctx, cast<ExprWithCleanups>(E)->getSubExpr()); + + // Casts depend completely on the target type. All casts work the same. + case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: + // Only in C++ can casts be interesting at all. + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); + + case Expr::BinaryConditionalOperatorClass: { + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } + + case Expr::ConditionalOperatorClass: { + // Once again, only C++ is interesting. + if (!Lang.CPlusPlus) return Cl::CL_PRValue; + const ConditionalOperator *co = cast<ConditionalOperator>(E); + return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); + } + + // ObjC message sends are effectively function calls, if the target function + // is known. + case Expr::ObjCMessageExprClass: + if (const ObjCMethodDecl *Method = + cast<ObjCMessageExpr>(E)->getMethodDecl()) { + Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getResultType()); + return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind; + } + return Cl::CL_PRValue; + + // Some C++ expressions are always class temporaries. + case Expr::CXXConstructExprClass: + case Expr::CXXTemporaryObjectExprClass: + return Cl::CL_ClassTemporary; + + case Expr::VAArgExprClass: + return ClassifyUnnamed(Ctx, E->getType()); + + case Expr::DesignatedInitExprClass: + return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit()); + + case Expr::StmtExprClass: { + const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt(); + if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back())) + return ClassifyUnnamed(Ctx, LastExpr->getType()); + return Cl::CL_PRValue; + } + + case Expr::CXXUuidofExprClass: + return Cl::CL_LValue; + + case Expr::PackExpansionExprClass: + return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern()); + } + + llvm_unreachable("unhandled expression kind in classification"); + return Cl::CL_LValue; +} + +/// ClassifyDecl - Return the classification of an expression referencing the +/// given declaration. +static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { + // C++ [expr.prim.general]p6: The result is an lvalue if the entity is a + // function, variable, or data member and a prvalue otherwise. + // In C, functions are not lvalues. + // In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an + // lvalue unless it's a reference type (C++ [temp.param]p6), so we need to + // special-case this. + + if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) + return Cl::CL_MemberFunction; + + bool islvalue; + if (const NonTypeTemplateParmDecl *NTTParm = + dyn_cast<NonTypeTemplateParmDecl>(D)) + islvalue = NTTParm->getType()->isReferenceType(); + else + islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || + isa<IndirectFieldDecl>(D) || + (Ctx.getLangOptions().CPlusPlus && + (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D))); + + return islvalue ? Cl::CL_LValue : Cl::CL_PRValue; +} + +/// ClassifyUnnamed - Return the classification of an expression yielding an +/// unnamed value of the given type. This applies in particular to function +/// calls and casts. +static Cl::Kinds ClassifyUnnamed(ASTContext &Ctx, QualType T) { + // In C, function calls are always rvalues. + if (!Ctx.getLangOptions().CPlusPlus) return Cl::CL_PRValue; + + // C++ [expr.call]p10: A function call is an lvalue if the result type is an + // lvalue reference type or an rvalue reference to function type, an xvalue + // if the result type is an rvalue refernence to object type, and a prvalue + // otherwise. + if (T->isLValueReferenceType()) + return Cl::CL_LValue; + const RValueReferenceType *RV = T->getAs<RValueReferenceType>(); + if (!RV) // Could still be a class temporary, though. + return T->isRecordType() ? Cl::CL_ClassTemporary : Cl::CL_PRValue; + + return RV->getPointeeType()->isFunctionType() ? Cl::CL_LValue : Cl::CL_XValue; +} + +static Cl::Kinds ClassifyMemberExpr(ASTContext &Ctx, const MemberExpr *E) { + if (E->getType() == Ctx.UnknownAnyTy) + return (isa<FunctionDecl>(E->getMemberDecl()) + ? Cl::CL_PRValue : Cl::CL_LValue); + + // Handle C first, it's easier. + if (!Ctx.getLangOptions().CPlusPlus) { + // C99 6.5.2.3p3 + // For dot access, the expression is an lvalue if the first part is. For + // arrow access, it always is an lvalue. + if (E->isArrow()) + return Cl::CL_LValue; + // ObjC property accesses are not lvalues, but get special treatment. + Expr *Base = E->getBase()->IgnoreParens(); + if (isa<ObjCPropertyRefExpr>(Base)) + return Cl::CL_SubObjCPropertySetting; + return ClassifyInternal(Ctx, Base); + } + + NamedDecl *Member = E->getMemberDecl(); + // C++ [expr.ref]p3: E1->E2 is converted to the equivalent form (*(E1)).E2. + // 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 Cl::CL_LValue; + + // Otherwise, one of the following rules applies. + // -- If E2 is a static member [...] then E1.E2 is an lvalue. + if (isa<VarDecl>(Member) && Member->getDeclContext()->isRecord()) + return Cl::CL_LValue; + + // -- If E2 is a non-static data member [...]. If E1 is an lvalue, then + // E1.E2 is an lvalue; if E1 is an xvalue, then E1.E2 is an xvalue; + // otherwise, it is a prvalue. + if (isa<FieldDecl>(Member)) { + // *E1 is an lvalue + if (E->isArrow()) + return Cl::CL_LValue; + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + if (isa<ObjCPropertyRefExpr>(Base)) + return Cl::CL_SubObjCPropertySetting; + return ClassifyInternal(Ctx, E->getBase()); + } + + // -- If E2 is a [...] member function, [...] + // -- If it refers to a static member function [...], then E1.E2 is an + // lvalue; [...] + // -- Otherwise [...] E1.E2 is a prvalue. + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Member)) + return Method->isStatic() ? Cl::CL_LValue : Cl::CL_MemberFunction; + + // -- If E2 is a member enumerator [...], the expression E1.E2 is a prvalue. + // So is everything else we haven't handled yet. + return Cl::CL_PRValue; +} + +static Cl::Kinds ClassifyBinaryOp(ASTContext &Ctx, const BinaryOperator *E) { + assert(Ctx.getLangOptions().CPlusPlus && + "This is only relevant for C++."); + // C++ [expr.ass]p1: All [...] return an lvalue referring to the left operand. + // Except we override this for writes to ObjC properties. + if (E->isAssignmentOp()) + return (E->getLHS()->getObjectKind() == OK_ObjCProperty + ? Cl::CL_PRValue : Cl::CL_LValue); + + // C++ [expr.comma]p1: the result is of the same value category as its right + // operand, [...]. + if (E->getOpcode() == BO_Comma) + return ClassifyInternal(Ctx, E->getRHS()); + + // C++ [expr.mptr.oper]p6: The result of a .* expression whose second operand + // is a pointer to a data member is of the same value category as its first + // operand. + if (E->getOpcode() == BO_PtrMemD) + return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy) + ? Cl::CL_MemberFunction + : ClassifyInternal(Ctx, E->getLHS()); + + // C++ [expr.mptr.oper]p6: The result of an ->* expression is an lvalue if its + // second operand is a pointer to data member and a prvalue otherwise. + if (E->getOpcode() == BO_PtrMemI) + return (E->getType()->isFunctionType() || E->getType() == Ctx.BoundMemberTy) + ? Cl::CL_MemberFunction + : Cl::CL_LValue; + + // All other binary operations are prvalues. + return Cl::CL_PRValue; +} + +static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True, + const Expr *False) { + assert(Ctx.getLangOptions().CPlusPlus && + "This is only relevant for C++."); + + // C++ [expr.cond]p2 + // If either the second or the third operand has type (cv) void, [...] + // the result [...] is a prvalue. + if (True->getType()->isVoidType() || False->getType()->isVoidType()) + return Cl::CL_PRValue; + + // Note that at this point, we have already performed all conversions + // according to [expr.cond]p3. + // C++ [expr.cond]p4: If the second and third operands are glvalues of the + // same value category [...], the result is of that [...] value category. + // C++ [expr.cond]p5: Otherwise, the result is a prvalue. + Cl::Kinds LCl = ClassifyInternal(Ctx, True), + RCl = ClassifyInternal(Ctx, False); + return LCl == RCl ? LCl : Cl::CL_PRValue; +} + +static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, + Cl::Kinds Kind, SourceLocation &Loc) { + // As a general rule, we only care about lvalues. But there are some rvalues + // for which we want to generate special results. + if (Kind == Cl::CL_PRValue) { + // For the sake of better diagnostics, we want to specifically recognize + // use of the GCC cast-as-lvalue extension. + if (const ExplicitCastExpr *CE = + dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) { + if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) { + Loc = CE->getExprLoc(); + return Cl::CM_LValueCast; + } + } + } + if (Kind != Cl::CL_LValue) + return Cl::CM_RValue; + + // This is the lvalue case. + // Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6) + if (Ctx.getLangOptions().CPlusPlus && E->getType()->isFunctionType()) + return Cl::CM_Function; + + // You cannot assign to a variable outside a block from within the block if + // it is not marked __block, e.g. + // void takeclosure(void (^C)(void)); + // void func() { int x = 1; takeclosure(^{ x = 7; }); } + if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E)) { + if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl())) + return Cl::CM_NotBlockQualified; + } + + // Assignment to a property in ObjC is an implicit setter access. But a + // setter might not exist. + if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0) + return Cl::CM_NoSetterProperty; + } + + CanQualType CT = Ctx.getCanonicalType(E->getType()); + // Const stuff is obviously not modifiable. + if (CT.isConstQualified()) + return Cl::CM_ConstQualified; + // Arrays are not modifiable, only their elements are. + if (CT->isArrayType()) + return Cl::CM_ArrayType; + // Incomplete types are not modifiable. + if (CT->isIncompleteType()) + return Cl::CM_IncompleteType; + + // Records with any const fields (recursively) are not modifiable. + if (const RecordType *R = CT->getAs<RecordType>()) { + assert((E->getObjectKind() == OK_ObjCProperty || + !Ctx.getLangOptions().CPlusPlus) && + "C++ struct assignment should be resolved by the " + "copy assignment operator."); + if (R->hasConstFields()) + return Cl::CM_ConstQualified; + } + + return Cl::CM_Modifiable; +} + +Expr::LValueClassification Expr::ClassifyLValue(ASTContext &Ctx) const { + Classification VC = Classify(Ctx); + switch (VC.getKind()) { + case Cl::CL_LValue: return LV_Valid; + case Cl::CL_XValue: return LV_InvalidExpression; + case Cl::CL_Function: return LV_NotObjectType; + case Cl::CL_Void: return LV_InvalidExpression; + case Cl::CL_AddressableVoid: return LV_IncompleteVoidType; + case Cl::CL_DuplicateVectorComponents: return LV_DuplicateVectorComponents; + case Cl::CL_MemberFunction: return LV_MemberFunction; + case Cl::CL_SubObjCPropertySetting: return LV_SubObjCPropertySetting; + case Cl::CL_ClassTemporary: return LV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return LV_InvalidMessageExpression; + case Cl::CL_PRValue: return LV_InvalidExpression; + } + llvm_unreachable("Unhandled kind"); +} + +Expr::isModifiableLvalueResult +Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { + SourceLocation dummy; + Classification VC = ClassifyModifiable(Ctx, Loc ? *Loc : dummy); + switch (VC.getKind()) { + case Cl::CL_LValue: break; + case Cl::CL_XValue: return MLV_InvalidExpression; + case Cl::CL_Function: return MLV_NotObjectType; + case Cl::CL_Void: return MLV_InvalidExpression; + case Cl::CL_AddressableVoid: return MLV_IncompleteVoidType; + case Cl::CL_DuplicateVectorComponents: return MLV_DuplicateVectorComponents; + case Cl::CL_MemberFunction: return MLV_MemberFunction; + case Cl::CL_SubObjCPropertySetting: return MLV_SubObjCPropertySetting; + case Cl::CL_ClassTemporary: return MLV_ClassTemporary; + case Cl::CL_ObjCMessageRValue: return MLV_InvalidMessageExpression; + case Cl::CL_PRValue: + return VC.getModifiable() == Cl::CM_LValueCast ? + MLV_LValueCast : MLV_InvalidExpression; + } + assert(VC.getKind() == Cl::CL_LValue && "Unhandled kind"); + switch (VC.getModifiable()) { + case Cl::CM_Untested: llvm_unreachable("Did not test modifiability"); + case Cl::CM_Modifiable: return MLV_Valid; + case Cl::CM_RValue: llvm_unreachable("CM_RValue and CL_LValue don't match"); + case Cl::CM_Function: return MLV_NotObjectType; + case Cl::CM_LValueCast: + llvm_unreachable("CM_LValueCast and CL_LValue don't match"); + case Cl::CM_NotBlockQualified: return MLV_NotBlockQualified; + case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty; + case Cl::CM_ConstQualified: return MLV_ConstQualified; + case Cl::CM_ArrayType: return MLV_ArrayType; + case Cl::CM_IncompleteType: return MLV_IncompleteType; + } + llvm_unreachable("Unhandled modifiable type"); +} diff --git a/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp new file mode 100644 index 000000000000..06c5645afb3f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ExprConstant.cpp @@ -0,0 +1,3091 @@ +//===--- 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/CharUnits.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeLoc.h" +#include "clang/AST/ASTDiagnostic.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/Builtins.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallString.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. +namespace { + struct EvalInfo { + const ASTContext &Ctx; + + /// EvalResult - Contains information about the evaluation. + Expr::EvalResult &EvalResult; + + typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy; + MapTy OpaqueValues; + const APValue *getOpaqueValue(const OpaqueValueExpr *e) const { + MapTy::const_iterator i = OpaqueValues.find(e); + if (i == OpaqueValues.end()) return 0; + return &i->second; + } + + EvalInfo(const ASTContext &ctx, Expr::EvalResult &evalresult) + : Ctx(ctx), EvalResult(evalresult) {} + }; + + struct ComplexValue { + private: + bool IsInt; + + public: + APSInt IntReal, IntImag; + APFloat FloatReal, FloatImag; + + ComplexValue() : FloatReal(APFloat::Bogus), FloatImag(APFloat::Bogus) {} + + void makeComplexFloat() { IsInt = false; } + bool isComplexFloat() const { return !IsInt; } + APFloat &getComplexFloatReal() { return FloatReal; } + APFloat &getComplexFloatImag() { return FloatImag; } + + void makeComplexInt() { IsInt = true; } + bool isComplexInt() const { return IsInt; } + APSInt &getComplexIntReal() { return IntReal; } + APSInt &getComplexIntImag() { return IntImag; } + + void moveInto(APValue &v) const { + if (isComplexFloat()) + v = APValue(FloatReal, FloatImag); + else + v = APValue(IntReal, IntImag); + } + void setFrom(const APValue &v) { + assert(v.isComplexFloat() || v.isComplexInt()); + if (v.isComplexFloat()) { + makeComplexFloat(); + FloatReal = v.getComplexFloatReal(); + FloatImag = v.getComplexFloatImag(); + } else { + makeComplexInt(); + IntReal = v.getComplexIntReal(); + IntImag = v.getComplexIntImag(); + } + } + }; + + struct LValue { + const Expr *Base; + CharUnits Offset; + + const Expr *getLValueBase() { return Base; } + CharUnits getLValueOffset() { return Offset; } + + void moveInto(APValue &v) const { + v = APValue(Base, Offset); + } + void setFrom(const APValue &v) { + assert(v.isLValue()); + Base = v.getLValueBase(); + Offset = v.getLValueOffset(); + } + }; +} + +static bool Evaluate(EvalInfo &info, const Expr *E); +static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info); +static bool EvaluatePointer(const Expr *E, LValue &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, ComplexValue &Res, EvalInfo &Info); + +//===----------------------------------------------------------------------===// +// Misc utilities +//===----------------------------------------------------------------------===// + +static bool IsGlobalLValue(const Expr* E) { + if (!E) return true; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (isa<FunctionDecl>(DRE->getDecl())) + return true; + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + return VD->hasGlobalStorage(); + return false; + } + + if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E)) + return CLE->isFileScope(); + + return true; +} + +static bool EvalPointerValueAsBool(LValue& Value, bool& Result) { + const Expr* Base = Value.Base; + + // A null base expression indicates a null pointer. These are always + // evaluatable, and they are false unless the offset is zero. + if (!Base) { + Result = !Value.Offset.isZero(); + return true; + } + + // Require the base expression to be a global l-value. + if (!IsGlobalLValue(Base)) return false; + + // We have a non-null base expression. These are generally known to + // be true, but if it'a decl-ref to a weak symbol it can be null at + // runtime. + Result = true; + + const DeclRefExpr* DeclRef = dyn_cast<DeclRefExpr>(Base); + if (!DeclRef) + return true; + + // If it's a weak symbol, it isn't constant-evaluable. + const ValueDecl* Decl = DeclRef->getDecl(); + if (Decl->hasAttr<WeakAttr>() || + Decl->hasAttr<WeakRefAttr>() || + Decl->isWeakImported()) + return false; + + return true; +} + +static bool HandleConversionToBool(const Expr* E, bool& Result, + EvalInfo &Info) { + if (E->getType()->isIntegralOrEnumerationType()) { + 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()) { + LValue PointerResult; + if (!EvaluatePointer(E, PointerResult, Info)) + return false; + return EvalPointerValueAsBool(PointerResult, Result); + } else if (E->getType()->isAnyComplexType()) { + ComplexValue 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, const ASTContext &Ctx) { + unsigned DestWidth = Ctx.getIntWidth(DestType); + // Determine whether we are converting to unsigned or signed. + bool DestSigned = DestType->isSignedIntegerOrEnumerationType(); + + // 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, const 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, const 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 = Result.extOrTrunc(DestWidth); + Result.setIsUnsigned(DestType->isUnsignedIntegerOrEnumerationType()); + return Result; +} + +static APFloat HandleIntToFloatCast(QualType DestType, QualType SrcType, + APSInt &Value, const ASTContext &Ctx) { + + APFloat Result(Ctx.getFloatTypeSemantics(DestType), 1); + Result.convertFromAPInt(Value, Value.isSigned(), + APFloat::rmNearestTiesToEven); + return Result; +} + +namespace { +class HasSideEffect + : public ConstStmtVisitor<HasSideEffect, bool> { + EvalInfo &Info; +public: + + HasSideEffect(EvalInfo &info) : Info(info) {} + + // Unhandled nodes conservatively default to having side effects. + bool VisitStmt(const Stmt *S) { + return true; + } + + bool VisitParenExpr(const ParenExpr *E) { return Visit(E->getSubExpr()); } + bool VisitGenericSelectionExpr(const GenericSelectionExpr *E) { + return Visit(E->getResultExpr()); + } + bool VisitDeclRefExpr(const DeclRefExpr *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return false; + } + // We don't want to evaluate BlockExprs multiple times, as they generate + // a ton of code. + bool VisitBlockExpr(const BlockExpr *E) { return true; } + bool VisitPredefinedExpr(const PredefinedExpr *E) { return false; } + bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) + { return Visit(E->getInitializer()); } + bool VisitMemberExpr(const MemberExpr *E) { return Visit(E->getBase()); } + bool VisitIntegerLiteral(const IntegerLiteral *E) { return false; } + bool VisitFloatingLiteral(const FloatingLiteral *E) { return false; } + bool VisitStringLiteral(const StringLiteral *E) { return false; } + bool VisitCharacterLiteral(const CharacterLiteral *E) { return false; } + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) + { return false; } + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitChooseExpr(const ChooseExpr *E) + { return Visit(E->getChosenSubExpr(Info.Ctx)); } + bool VisitCastExpr(const CastExpr *E) { return Visit(E->getSubExpr()); } + bool VisitBinAssign(const BinaryOperator *E) { return true; } + bool VisitCompoundAssignOperator(const BinaryOperator *E) { return true; } + bool VisitBinaryOperator(const BinaryOperator *E) + { return Visit(E->getLHS()) || Visit(E->getRHS()); } + bool VisitUnaryPreInc(const UnaryOperator *E) { return true; } + bool VisitUnaryPostInc(const UnaryOperator *E) { return true; } + bool VisitUnaryPreDec(const UnaryOperator *E) { return true; } + bool VisitUnaryPostDec(const UnaryOperator *E) { return true; } + bool VisitUnaryDeref(const UnaryOperator *E) { + if (Info.Ctx.getCanonicalType(E->getType()).isVolatileQualified()) + return true; + return Visit(E->getSubExpr()); + } + bool VisitUnaryOperator(const UnaryOperator *E) { return Visit(E->getSubExpr()); } + + // Has side effects if any element does. + bool VisitInitListExpr(const InitListExpr *E) { + for (unsigned i = 0, e = E->getNumInits(); i != e; ++i) + if (Visit(E->getInit(i))) return true; + if (const Expr *filler = E->getArrayFiller()) + return Visit(filler); + return false; + } + + bool VisitSizeOfPackExpr(const SizeOfPackExpr *) { return false; } +}; + +class OpaqueValueEvaluation { + EvalInfo &info; + OpaqueValueExpr *opaqueValue; + +public: + OpaqueValueEvaluation(EvalInfo &info, OpaqueValueExpr *opaqueValue, + Expr *value) + : info(info), opaqueValue(opaqueValue) { + + // If evaluation fails, fail immediately. + if (!Evaluate(info, value)) { + this->opaqueValue = 0; + return; + } + info.OpaqueValues[opaqueValue] = info.EvalResult.Val; + } + + bool hasError() const { return opaqueValue == 0; } + + ~OpaqueValueEvaluation() { + if (opaqueValue) info.OpaqueValues.erase(opaqueValue); + } +}; + +} // end anonymous namespace + +//===----------------------------------------------------------------------===// +// Generic Evaluation +//===----------------------------------------------------------------------===// +namespace { + +template <class Derived, typename RetTy=void> +class ExprEvaluatorBase + : public ConstStmtVisitor<Derived, RetTy> { +private: + RetTy DerivedSuccess(const APValue &V, const Expr *E) { + return static_cast<Derived*>(this)->Success(V, E); + } + RetTy DerivedError(const Expr *E) { + return static_cast<Derived*>(this)->Error(E); + } + +protected: + EvalInfo &Info; + typedef ConstStmtVisitor<Derived, RetTy> StmtVisitorTy; + typedef ExprEvaluatorBase ExprEvaluatorBaseTy; + +public: + ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {} + + RetTy VisitStmt(const Stmt *) { + assert(0 && "Expression evaluator should not be called on stmts"); + return DerivedError(0); + } + RetTy VisitExpr(const Expr *E) { + return DerivedError(E); + } + + RetTy VisitParenExpr(const ParenExpr *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitUnaryExtension(const UnaryOperator *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitUnaryPlus(const UnaryOperator *E) + { return StmtVisitorTy::Visit(E->getSubExpr()); } + RetTy VisitChooseExpr(const ChooseExpr *E) + { return StmtVisitorTy::Visit(E->getChosenSubExpr(Info.Ctx)); } + RetTy VisitGenericSelectionExpr(const GenericSelectionExpr *E) + { return StmtVisitorTy::Visit(E->getResultExpr()); } + + RetTy VisitBinaryConditionalOperator(const BinaryConditionalOperator *E) { + OpaqueValueEvaluation opaque(Info, E->getOpaqueValue(), E->getCommon()); + if (opaque.hasError()) + return DerivedError(E); + + bool cond; + if (!HandleConversionToBool(E->getCond(), cond, Info)) + return DerivedError(E); + + return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr()); + } + + RetTy VisitConditionalOperator(const ConditionalOperator *E) { + bool BoolResult; + if (!HandleConversionToBool(E->getCond(), BoolResult, Info)) + return DerivedError(E); + + Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr(); + return StmtVisitorTy::Visit(EvalExpr); + } + + RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) { + const APValue *value = Info.getOpaqueValue(E); + if (!value) + return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr()) + : DerivedError(E)); + return DerivedSuccess(*value, E); + } +}; + +} + +//===----------------------------------------------------------------------===// +// LValue Evaluation +//===----------------------------------------------------------------------===// +namespace { +class LValueExprEvaluator + : public ExprEvaluatorBase<LValueExprEvaluator, bool> { + LValue &Result; + + bool Success(const Expr *E) { + Result.Base = E; + Result.Offset = CharUnits::Zero(); + return true; + } +public: + + LValueExprEvaluator(EvalInfo &info, LValue &Result) : + ExprEvaluatorBaseTy(info), Result(Result) {} + + bool Success(const APValue &V, const Expr *E) { + Result.setFrom(V); + return true; + } + bool Error(const Expr *E) { + return false; + } + + bool VisitDeclRefExpr(const DeclRefExpr *E); + bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); } + bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E); + bool VisitMemberExpr(const MemberExpr *E); + bool VisitStringLiteral(const StringLiteral *E) { return Success(E); } + bool VisitObjCEncodeExpr(const ObjCEncodeExpr *E) { return Success(E); } + bool VisitArraySubscriptExpr(const ArraySubscriptExpr *E); + bool VisitUnaryDeref(const UnaryOperator *E); + + bool VisitCastExpr(const CastExpr *E) { + switch (E->getCastKind()) { + default: + return false; + + case CK_NoOp: + return Visit(E->getSubExpr()); + } + } + // FIXME: Missing: __real__, __imag__ + +}; +} // end anonymous namespace + +static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) { + return LValueExprEvaluator(Info, Result).Visit(E); +} + +bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { + if (isa<FunctionDecl>(E->getDecl())) { + return Success(E); + } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) { + if (!VD->getType()->isReferenceType()) + return Success(E); + // Reference parameters can refer to anything even if they have an + // "initializer" in the form of a default argument. + if (!isa<ParmVarDecl>(VD)) + // FIXME: Check whether VD might be overridden! + if (const Expr *Init = VD->getAnyInitializer()) + return Visit(Init); + } + + return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); +} + +bool +LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return Success(E); +} + +bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) { + QualType Ty; + if (E->isArrow()) { + if (!EvaluatePointer(E->getBase(), Result, Info)) + return false; + Ty = E->getBase()->getType()->getAs<PointerType>()->getPointeeType(); + } else { + if (!Visit(E->getBase())) + return false; + Ty = E->getBase()->getType(); + } + + const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); + if (!FD) // FIXME: deal with other kinds of member expressions + return false; + + if (FD->getType()->isReferenceType()) + return false; + + // FIXME: This is linear time. + unsigned i = 0; + for (RecordDecl::field_iterator Field = RD->field_begin(), + FieldEnd = RD->field_end(); + Field != FieldEnd; (void)++Field, ++i) { + if (*Field == FD) + break; + } + + Result.Offset += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); + return true; +} + +bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { + if (!EvaluatePointer(E->getBase(), Result, Info)) + return false; + + APSInt Index; + if (!EvaluateInteger(E->getIdx(), Index, Info)) + return false; + + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(E->getType()); + Result.Offset += Index.getSExtValue() * ElementSize; + return true; +} + +bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) { + return EvaluatePointer(E->getSubExpr(), Result, Info); +} + +//===----------------------------------------------------------------------===// +// Pointer Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class PointerExprEvaluator + : public ExprEvaluatorBase<PointerExprEvaluator, bool> { + LValue &Result; + + bool Success(const Expr *E) { + Result.Base = E; + Result.Offset = CharUnits::Zero(); + return true; + } +public: + + PointerExprEvaluator(EvalInfo &info, LValue &Result) + : ExprEvaluatorBaseTy(info), Result(Result) {} + + bool Success(const APValue &V, const Expr *E) { + Result.setFrom(V); + return true; + } + bool Error(const Stmt *S) { + return false; + } + + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitCastExpr(const CastExpr* E); + bool VisitUnaryAddrOf(const UnaryOperator *E); + bool VisitObjCStringLiteral(const ObjCStringLiteral *E) + { return Success(E); } + bool VisitAddrLabelExpr(const AddrLabelExpr *E) + { return Success(E); } + bool VisitCallExpr(const CallExpr *E); + bool VisitBlockExpr(const BlockExpr *E) { + if (!E->getBlockDecl()->hasCaptures()) + return Success(E); + return false; + } + bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) + { return Success((Expr*)0); } + bool VisitCXXNullPtrLiteralExpr(const CXXNullPtrLiteralExpr *E) + { return Success((Expr*)0); } + + // FIXME: Missing: @protocol, @selector +}; +} // end anonymous namespace + +static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) { + assert(E->getType()->hasPointerRepresentation()); + return PointerExprEvaluator(Info, Result).Visit(E); +} + +bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() != BO_Add && + E->getOpcode() != BO_Sub) + return false; + + const Expr *PExp = E->getLHS(); + const Expr *IExp = E->getRHS(); + if (IExp->getType()->isPointerType()) + std::swap(PExp, IExp); + + if (!EvaluatePointer(PExp, Result, Info)) + return false; + + llvm::APSInt Offset; + if (!EvaluateInteger(IExp, Offset, Info)) + return false; + int64_t AdditionalOffset + = Offset.isSigned() ? Offset.getSExtValue() + : static_cast<int64_t>(Offset.getZExtValue()); + + // Compute the new offset in the appropriate width. + + QualType PointeeType = + PExp->getType()->getAs<PointerType>()->getPointeeType(); + CharUnits SizeOfPointee; + + // Explicitly handle GNU void* and function pointer arithmetic extensions. + if (PointeeType->isVoidType() || PointeeType->isFunctionType()) + SizeOfPointee = CharUnits::One(); + else + SizeOfPointee = Info.Ctx.getTypeSizeInChars(PointeeType); + + if (E->getOpcode() == BO_Add) + Result.Offset += AdditionalOffset * SizeOfPointee; + else + Result.Offset -= AdditionalOffset * SizeOfPointee; + + return true; +} + +bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) { + return EvaluateLValue(E->getSubExpr(), Result, Info); +} + + +bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { + const Expr* SubExpr = E->getSubExpr(); + + switch (E->getCastKind()) { + default: + break; + + case CK_NoOp: + case CK_BitCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + return Visit(SubExpr); + + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: { + LValue BaseLV; + if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info)) + return false; + + // Now figure out the necessary offset to add to the baseLV to get from + // the derived class to the base class. + CharUnits Offset = CharUnits::Zero(); + + QualType Ty = E->getSubExpr()->getType(); + const CXXRecordDecl *DerivedDecl = + Ty->getAs<PointerType>()->getPointeeType()->getAsCXXRecordDecl(); + + for (CastExpr::path_const_iterator PathI = E->path_begin(), + PathE = E->path_end(); PathI != PathE; ++PathI) { + const CXXBaseSpecifier *Base = *PathI; + + // FIXME: If the base is virtual, we'd need to determine the type of the + // most derived class and we don't support that right now. + if (Base->isVirtual()) + return false; + + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); + const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl); + + Offset += Layout.getBaseClassOffset(BaseDecl); + DerivedDecl = BaseDecl; + } + + Result.Base = BaseLV.getLValueBase(); + Result.Offset = BaseLV.getLValueOffset() + Offset; + return true; + } + + case CK_NullToPointer: { + Result.Base = 0; + Result.Offset = CharUnits::Zero(); + return true; + } + + case CK_IntegralToPointer: { + APValue Value; + if (!EvaluateIntegerOrLValue(SubExpr, Value, Info)) + break; + + if (Value.isInt()) { + Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType())); + Result.Base = 0; + Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue()); + return true; + } else { + // Cast is of an lvalue, no need to change value. + Result.Base = Value.getLValueBase(); + Result.Offset = Value.getLValueOffset(); + return true; + } + } + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + return EvaluateLValue(SubExpr, Result, Info); + } + + return false; +} + +bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { + if (E->isBuiltinCall(Info.Ctx) == + Builtin::BI__builtin___CFStringMakeConstantString || + E->isBuiltinCall(Info.Ctx) == + Builtin::BI__builtin___NSStringMakeConstantString) + return Success(E); + + return ExprEvaluatorBaseTy::VisitCallExpr(E); +} + +//===----------------------------------------------------------------------===// +// Vector Evaluation +//===----------------------------------------------------------------------===// + +namespace { + class VectorExprEvaluator + : public ExprEvaluatorBase<VectorExprEvaluator, APValue> { + APValue GetZeroVector(QualType VecType); + public: + + VectorExprEvaluator(EvalInfo &info) : ExprEvaluatorBaseTy(info) {} + + APValue Success(const APValue &V, const Expr *E) { return V; } + APValue Error(const Expr *E) { return APValue(); } + + 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 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(E); + return !Result.isUninit(); +} + +APValue VectorExprEvaluator::VisitCastExpr(const CastExpr* E) { + const VectorType *VTy = E->getType()->getAs<VectorType>(); + QualType EltTy = VTy->getElementType(); + unsigned NElts = VTy->getNumElements(); + unsigned EltWidth = Info.Ctx.getTypeSize(EltTy); + + const Expr* SE = E->getSubExpr(); + QualType SETy = SE->getType(); + + switch (E->getCastKind()) { + case CK_VectorSplat: { + APValue Result = APValue(); + if (SETy->isIntegerType()) { + APSInt IntResult; + if (!EvaluateInteger(SE, IntResult, Info)) + return APValue(); + Result = APValue(IntResult); + } else if (SETy->isRealFloatingType()) { + APFloat F(0.0); + if (!EvaluateFloat(SE, F, Info)) + return APValue(); + Result = APValue(F); + } else { + return APValue(); + } + + // Splat and create vector APValue. + llvm::SmallVector<APValue, 4> Elts(NElts, Result); + return APValue(&Elts[0], Elts.size()); + } + case CK_BitCast: { + if (SETy->isVectorType()) + return Visit(SE); + + if (!SETy->isIntegerType()) + return APValue(); + + APSInt Init; + if (!EvaluateInteger(SE, Init, Info)) + return APValue(); + + assert((EltTy->isIntegerType() || EltTy->isRealFloatingType()) && + "Vectors must be composed of ints or floats"); + + llvm::SmallVector<APValue, 4> Elts; + for (unsigned i = 0; i != NElts; ++i) { + APSInt Tmp = Init.extOrTrunc(EltWidth); + + if (EltTy->isIntegerType()) + Elts.push_back(APValue(Tmp)); + else + Elts.push_back(APValue(APFloat(Tmp))); + + Init >>= EltWidth; + } + return APValue(&Elts[0], Elts.size()); + } + case CK_LValueToRValue: + case CK_NoOp: + return Visit(SE); + default: + return APValue(); + } +} + +APValue +VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { + return this->Visit(E->getInitializer()); +} + +APValue +VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) { + const VectorType *VT = E->getType()->getAs<VectorType>(); + unsigned NumInits = E->getNumInits(); + unsigned NumElements = VT->getNumElements(); + + QualType EltTy = VT->getElementType(); + llvm::SmallVector<APValue, 4> Elements; + + // If a vector is initialized with a single element, that value + // becomes every element of the vector, not just the first. + // This is the behavior described in the IBM AltiVec documentation. + if (NumInits == 1) { + + // Handle the case where the vector is initialized by a another + // vector (OpenCL 6.1.6). + if (E->getInit(0)->getType()->isVectorType()) + return this->Visit(const_cast<Expr*>(E->getInit(0))); + + APValue InitValue; + if (EltTy->isIntegerType()) { + llvm::APSInt sInt(32); + if (!EvaluateInteger(E->getInit(0), sInt, Info)) + return APValue(); + InitValue = APValue(sInt); + } else { + llvm::APFloat f(0.0); + if (!EvaluateFloat(E->getInit(0), f, Info)) + return APValue(); + InitValue = APValue(f); + } + for (unsigned i = 0; i < NumElements; i++) { + Elements.push_back(InitValue); + } + } else { + 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->getAs<VectorType>(); + 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::VisitUnaryImag(const UnaryOperator *E) { + if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + return GetZeroVector(E->getType()); +} + +//===----------------------------------------------------------------------===// +// Integer Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class IntExprEvaluator + : public ExprEvaluatorBase<IntExprEvaluator, bool> { + APValue &Result; +public: + IntExprEvaluator(EvalInfo &info, APValue &result) + : ExprEvaluatorBaseTy(info), Result(result) {} + + bool Success(const llvm::APSInt &SI, const Expr *E) { + assert(E->getType()->isIntegralOrEnumerationType() && + "Invalid evaluation result."); + assert(SI.isSigned() == E->getType()->isSignedIntegerOrEnumerationType() && + "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()->isIntegralOrEnumerationType() && + "Invalid evaluation result."); + assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) && + "Invalid evaluation result."); + Result = APValue(APSInt(I)); + Result.getInt().setIsUnsigned( + E->getType()->isUnsignedIntegerOrEnumerationType()); + return true; + } + + bool Success(uint64_t Value, const Expr *E) { + assert(E->getType()->isIntegralOrEnumerationType() && + "Invalid evaluation result."); + Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType())); + return true; + } + + bool Success(CharUnits Size, const Expr *E) { + return Success(Size.getQuantity(), E); + } + + + 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; + } + + bool Success(const APValue &V, const Expr *E) { + return Success(V.getInt(), E); + } + bool Error(const Expr *E) { + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitIntegerLiteral(const IntegerLiteral *E) { + return Success(E->getValue(), E); + } + bool VisitCharacterLiteral(const CharacterLiteral *E) { + return Success(E->getValue(), E); + } + + bool CheckReferencedDecl(const Expr *E, const Decl *D); + bool VisitDeclRefExpr(const DeclRefExpr *E) { + if (CheckReferencedDecl(E, E->getDecl())) + return true; + + return ExprEvaluatorBaseTy::VisitDeclRefExpr(E); + } + bool VisitMemberExpr(const MemberExpr *E) { + if (CheckReferencedDecl(E, E->getMemberDecl())) { + // Conservatively assume a MemberExpr will have side-effects + Info.EvalResult.HasSideEffects = true; + return true; + } + + return ExprEvaluatorBaseTy::VisitMemberExpr(E); + } + + bool VisitCallExpr(const CallExpr *E); + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitOffsetOfExpr(const OffsetOfExpr *E); + bool VisitUnaryOperator(const UnaryOperator *E); + + bool VisitCastExpr(const CastExpr* E); + bool VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); + + bool VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitGNUNullExpr(const GNUNullExpr *E) { + return Success(0, E); + } + + bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { + return Success(0, E); + } + + bool VisitImplicitValueInitExpr(const ImplicitValueInitExpr *E) { + return Success(0, E); + } + + bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitBinaryTypeTraitExpr(const BinaryTypeTraitExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitArrayTypeTraitExpr(const ArrayTypeTraitExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E) { + return Success(E->getValue(), E); + } + + bool VisitUnaryReal(const UnaryOperator *E); + bool VisitUnaryImag(const UnaryOperator *E); + + bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E); + bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); + +private: + CharUnits GetAlignOfExpr(const Expr *E); + CharUnits GetAlignOfType(QualType T); + static QualType GetObjectType(const Expr *E); + bool TryEvaluateBuiltinObjectSize(const CallExpr *E); + // FIXME: Missing: array subscript of vector, member of vector +}; +} // end anonymous namespace + +static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) { + assert(E->getType()->isIntegralOrEnumerationType()); + return IntExprEvaluator(Info, Result).Visit(E); +} + +static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) { + assert(E->getType()->isIntegralOrEnumerationType()); + + APValue Val; + if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt()) + return false; + Result = Val.getInt(); + return true; +} + +bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) { + // Enums are integer constant exprs. + if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) + return Success(ECD->getInitVal(), 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 (Info.Ctx.getCanonicalType(E->getType()).getCVRQualifiers() + == Qualifiers::Const) { + + if (isa<ParmVarDecl>(D)) + return false; + + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (const Expr *Init = VD->getAnyInitializer()) { + if (APValue *V = VD->getEvaluatedValue()) { + if (V->isInt()) + return Success(V->getInt(), E); + return false; + } + + if (VD->isEvaluatingValue()) + return false; + + VD->setEvaluatingValue(); + + Expr::EvalResult EResult; + if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects && + EResult.Val.isInt()) { + // Cache the evaluated value in the variable declaration. + Result = EResult.Val; + VD->setEvaluatedValue(Result); + return true; + } + + VD->setEvaluatedValue(APValue()); + } + } + } + + // Otherwise, random variable references are not constants. + return false; +} + +/// 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->isStructureOrClassType()) + 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; +} + +/// Retrieves the "underlying object type" of the given expression, +/// as used by __builtin_object_size. +QualType IntExprEvaluator::GetObjectType(const Expr *E) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + return VD->getType(); + } else if (isa<CompoundLiteralExpr>(E)) { + return E->getType(); + } + + return QualType(); +} + +bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { + // TODO: Perhaps we should let LLVM lower this? + LValue Base; + if (!EvaluatePointer(E->getArg(0), Base, Info)) + return false; + + // If we can prove the base is null, lower to zero now. + const Expr *LVBase = Base.getLValueBase(); + if (!LVBase) return Success(0, E); + + QualType T = GetObjectType(LVBase); + if (T.isNull() || + T->isIncompleteType() || + T->isFunctionType() || + T->isVariablyModifiedType() || + T->isDependentType()) + return false; + + CharUnits Size = Info.Ctx.getTypeSizeInChars(T); + CharUnits Offset = Base.getLValueOffset(); + + if (!Offset.isNegative() && Offset <= Size) + Size -= Offset; + else + Size = CharUnits::Zero(); + return Success(Size, E); +} + +bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { + switch (E->isBuiltinCall(Info.Ctx)) { + default: + return ExprEvaluatorBaseTy::VisitCallExpr(E); + + case Builtin::BI__builtin_object_size: { + if (TryEvaluateBuiltinObjectSize(E)) + return true; + + // If evaluating the argument has side-effects we can't determine + // the size of the object and lower it to unknown now. + if (E->getArg(0)->HasSideEffects(Info.Ctx)) { + if (E->getArg(1)->EvaluateAsInt(Info.Ctx).getZExtValue() <= 1) + return Success(-1ULL, E); + return Success(0, E); + } + + 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); + + case Builtin::BI__builtin_eh_return_data_regno: { + int Operand = E->getArg(0)->EvaluateAsInt(Info.Ctx).getZExtValue(); + Operand = Info.Ctx.Target.getEHDataRegisterNumber(Operand); + return Success(Operand, E); + } + + case Builtin::BI__builtin_expect: + return Visit(E->getArg(0)); + + case Builtin::BIstrlen: + case Builtin::BI__builtin_strlen: + // As an extension, we support strlen() and __builtin_strlen() as constant + // expressions when the argument is a string literal. + if (const StringLiteral *S + = dyn_cast<StringLiteral>(E->getArg(0)->IgnoreParenImpCasts())) { + // The string literal may have embedded null characters. Find the first + // one and truncate there. + llvm::StringRef Str = S->getString(); + llvm::StringRef::size_type Pos = Str.find(0); + if (Pos != llvm::StringRef::npos) + Str = Str.substr(0, Pos); + + return Success(Str.size(), E); + } + + return Error(E->getLocStart(), diag::note_invalid_subexpr_in_ice, E); + } +} + +bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BO_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() == BO_LOr)) + return Success(lhsResult, E); + + if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) { + if (E->getOpcode() == BO_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() == BO_LOr) || + !rhsResult == (E->getOpcode() == BO_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"); + ComplexValue 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() == BO_EQ) + return Success((CR_r == APFloat::cmpEqual && + CR_i == APFloat::cmpEqual), E); + else { + assert(E->getOpcode() == BO_NE && + "Invalid complex comparison."); + return Success(((CR_r == APFloat::cmpGreaterThan || + CR_r == APFloat::cmpLessThan || + CR_r == APFloat::cmpUnordered) || + (CR_i == APFloat::cmpGreaterThan || + CR_i == APFloat::cmpLessThan || + CR_i == APFloat::cmpUnordered)), E); + } + } else { + if (E->getOpcode() == BO_EQ) + return Success((LHS.getComplexIntReal() == RHS.getComplexIntReal() && + LHS.getComplexIntImag() == RHS.getComplexIntImag()), E); + else { + assert(E->getOpcode() == BO_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 BO_LT: + return Success(CR == APFloat::cmpLessThan, E); + case BO_GT: + return Success(CR == APFloat::cmpGreaterThan, E); + case BO_LE: + return Success(CR == APFloat::cmpLessThan || CR == APFloat::cmpEqual, E); + case BO_GE: + return Success(CR == APFloat::cmpGreaterThan || CR == APFloat::cmpEqual, + E); + case BO_EQ: + return Success(CR == APFloat::cmpEqual, E); + case BO_NE: + return Success(CR == APFloat::cmpGreaterThan + || CR == APFloat::cmpLessThan + || CR == APFloat::cmpUnordered, E); + } + } + + if (LHSTy->isPointerType() && RHSTy->isPointerType()) { + if (E->getOpcode() == BO_Sub || E->isEqualityOp()) { + LValue LHSValue; + if (!EvaluatePointer(E->getLHS(), LHSValue, Info)) + return false; + + LValue RHSValue; + if (!EvaluatePointer(E->getRHS(), RHSValue, Info)) + return false; + + // Reject any bases from the normal codepath; we special-case comparisons + // to null. + if (LHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (RHSValue.getLValueBase() || !RHSValue.getLValueOffset().isZero()) + return false; + bool bres; + if (!EvalPointerValueAsBool(LHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BO_EQ), E); + } else if (RHSValue.getLValueBase()) { + if (!E->isEqualityOp()) + return false; + if (LHSValue.getLValueBase() || !LHSValue.getLValueOffset().isZero()) + return false; + bool bres; + if (!EvalPointerValueAsBool(RHSValue, bres)) + return false; + return Success(bres ^ (E->getOpcode() == BO_EQ), E); + } + + if (E->getOpcode() == BO_Sub) { + QualType Type = E->getLHS()->getType(); + QualType ElementType = Type->getAs<PointerType>()->getPointeeType(); + + CharUnits ElementSize = CharUnits::One(); + if (!ElementType->isVoidType() && !ElementType->isFunctionType()) + ElementSize = Info.Ctx.getTypeSizeInChars(ElementType); + + CharUnits Diff = LHSValue.getLValueOffset() - + RHSValue.getLValueOffset(); + return Success(Diff / ElementSize, E); + } + bool Result; + if (E->getOpcode() == BO_EQ) { + Result = LHSValue.getLValueOffset() == RHSValue.getLValueOffset(); + } else { + Result = LHSValue.getLValueOffset() != RHSValue.getLValueOffset(); + } + return Success(Result, E); + } + } + if (!LHSTy->isIntegralOrEnumerationType() || + !RHSTy->isIntegralOrEnumerationType()) { + // 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()) { + CharUnits Offset = Result.getLValueOffset(); + CharUnits AdditionalOffset = CharUnits::fromQuantity( + RHSVal.getInt().getZExtValue()); + if (E->getOpcode() == BO_Add) + Offset += AdditionalOffset; + else + Offset -= AdditionalOffset; + Result = APValue(Result.getLValueBase(), Offset); + return true; + } + + // Handle cases like 4 + (unsigned long)&a + if (E->getOpcode() == BO_Add && + RHSVal.isLValue() && Result.isInt()) { + CharUnits Offset = RHSVal.getLValueOffset(); + Offset += CharUnits::fromQuantity(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 BO_Mul: return Success(Result.getInt() * RHS, E); + case BO_Add: return Success(Result.getInt() + RHS, E); + case BO_Sub: return Success(Result.getInt() - RHS, E); + case BO_And: return Success(Result.getInt() & RHS, E); + case BO_Xor: return Success(Result.getInt() ^ RHS, E); + case BO_Or: return Success(Result.getInt() | RHS, E); + case BO_Div: + if (RHS == 0) + return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); + return Success(Result.getInt() / RHS, E); + case BO_Rem: + if (RHS == 0) + return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E); + return Success(Result.getInt() % RHS, E); + case BO_Shl: { + // During constant-folding, a negative shift is an opposite shift. + if (RHS.isSigned() && RHS.isNegative()) { + RHS = -RHS; + goto shift_right; + } + + shift_left: + unsigned SA + = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); + return Success(Result.getInt() << SA, E); + } + case BO_Shr: { + // During constant-folding, a negative shift is an opposite shift. + if (RHS.isSigned() && RHS.isNegative()) { + RHS = -RHS; + goto shift_left; + } + + shift_right: + unsigned SA = + (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1); + return Success(Result.getInt() >> SA, E); + } + + case BO_LT: return Success(Result.getInt() < RHS, E); + case BO_GT: return Success(Result.getInt() > RHS, E); + case BO_LE: return Success(Result.getInt() <= RHS, E); + case BO_GE: return Success(Result.getInt() >= RHS, E); + case BO_EQ: return Success(Result.getInt() == RHS, E); + case BO_NE: return Success(Result.getInt() != RHS, E); + } +} + +CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + + // __alignof is defined to return the preferred alignment. + return Info.Ctx.toCharUnitsFromBits( + Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); +} + +CharUnits 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.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/true); + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return Info.Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/true); + + return GetAlignOfType(E->getType()); +} + + +/// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with +/// a result as the expression's type. +bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { + switch(E->getKind()) { + case UETT_AlignOf: { + if (E->isArgumentType()) + return Success(GetAlignOfType(E->getArgumentType()), E); + else + return Success(GetAlignOfExpr(E->getArgumentExpr()), E); + } + + case UETT_VecStep: { + QualType Ty = E->getTypeOfArgument(); + + if (Ty->isVectorType()) { + unsigned n = Ty->getAs<VectorType>()->getNumElements(); + + // The vec_step built-in functions that take a 3-component + // vector return 4. (OpenCL 1.1 spec 6.11.12) + if (n == 3) + n = 4; + + return Success(n, E); + } else + return Success(1, E); + } + + case UETT_SizeOf: { + QualType SrcTy = E->getTypeOfArgument(); + // C++ [expr.sizeof]p2: "When applied to a reference or a reference type, + // the result is the size of the referenced type." + // C++ [expr.alignof]p3: "When alignof is applied to a reference type, the + // result shall be the alignment of the referenced type." + if (const ReferenceType *Ref = SrcTy->getAs<ReferenceType>()) + SrcTy = Ref->getPointeeType(); + + // 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. + return Success(Info.Ctx.getTypeSizeInChars(SrcTy), E); + } + } + + llvm_unreachable("unknown expr/type trait"); + return false; +} + +bool IntExprEvaluator::VisitOffsetOfExpr(const OffsetOfExpr *OOE) { + CharUnits Result; + unsigned n = OOE->getNumComponents(); + if (n == 0) + return false; + QualType CurrentType = OOE->getTypeSourceInfo()->getType(); + for (unsigned i = 0; i != n; ++i) { + OffsetOfExpr::OffsetOfNode ON = OOE->getComponent(i); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: { + const Expr *Idx = OOE->getIndexExpr(ON.getArrayExprIndex()); + APSInt IdxResult; + if (!EvaluateInteger(Idx, IdxResult, Info)) + return false; + const ArrayType *AT = Info.Ctx.getAsArrayType(CurrentType); + if (!AT) + return false; + CurrentType = AT->getElementType(); + CharUnits ElementSize = Info.Ctx.getTypeSizeInChars(CurrentType); + Result += IdxResult.getSExtValue() * ElementSize; + break; + } + + case OffsetOfExpr::OffsetOfNode::Field: { + FieldDecl *MemberDecl = ON.getField(); + const RecordType *RT = CurrentType->getAs<RecordType>(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + unsigned i = MemberDecl->getFieldIndex(); + assert(i < RL.getFieldCount() && "offsetof field in wrong type"); + Result += Info.Ctx.toCharUnitsFromBits(RL.getFieldOffset(i)); + CurrentType = MemberDecl->getType().getNonReferenceType(); + break; + } + + case OffsetOfExpr::OffsetOfNode::Identifier: + llvm_unreachable("dependent __builtin_offsetof"); + return false; + + case OffsetOfExpr::OffsetOfNode::Base: { + CXXBaseSpecifier *BaseSpec = ON.getBase(); + if (BaseSpec->isVirtual()) + return false; + + // Find the layout of the class whose base we are looking into. + const RecordType *RT = CurrentType->getAs<RecordType>(); + if (!RT) + return false; + RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &RL = Info.Ctx.getASTRecordLayout(RD); + + // Find the base class itself. + CurrentType = BaseSpec->getType(); + const RecordType *BaseRT = CurrentType->getAs<RecordType>(); + if (!BaseRT) + return false; + + // Add the offset to the base. + Result += RL.getBaseClassOffset(cast<CXXRecordDecl>(BaseRT->getDecl())); + break; + } + } + } + return Success(Result, OOE); +} + +bool IntExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + if (E->getOpcode() == UO_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()->isIntegralOrEnumerationType()) + 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 UO_Extension: + // FIXME: Should extension allow i-c-e extension expressions in its scope? + // If so, we could clear the diagnostic ID. + return true; + case UO_Plus: + // The result is always just the subexpr. + return true; + case UO_Minus: + if (!Result.isInt()) return false; + return Success(-Result.getInt(), E); + case UO_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(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); + QualType DestType = E->getType(); + QualType SrcType = SubExpr->getType(); + + switch (E->getCastKind()) { + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralToFloating: + case CK_FloatingCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingRealToComplex: + case CK_FloatingComplexToReal: + case CK_FloatingComplexCast: + case CK_FloatingComplexToIntegralComplex: + case CK_IntegralRealToComplex: + case CK_IntegralComplexCast: + case CK_IntegralComplexToFloatingComplex: + llvm_unreachable("invalid cast kind for integral value"); + + case CK_BitCast: + case CK_Dependent: + case CK_GetObjCProperty: + case CK_LValueBitCast: + case CK_UserDefinedConversion: + return false; + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(E->getSubExpr()); + + case CK_MemberPointerToBoolean: + case CK_PointerToBoolean: + case CK_IntegralToBoolean: + case CK_FloatingToBoolean: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToBoolean: { + bool BoolResult; + if (!HandleConversionToBool(SubExpr, BoolResult, Info)) + return false; + return Success(BoolResult, E); + } + + case CK_IntegralCast: { + 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); + } + + case CK_PointerToIntegral: { + LValue 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; + + LV.moveInto(Result); + return true; + } + + APSInt AsInt = Info.Ctx.MakeIntValue(LV.getLValueOffset().getQuantity(), + SrcType); + return Success(HandleIntToIntCast(DestType, SrcType, AsInt, Info.Ctx), E); + } + + case CK_IntegralComplexToReal: { + ComplexValue C; + if (!EvaluateComplex(SubExpr, C, Info)) + return false; + return Success(C.getComplexIntReal(), E); + } + + case CK_FloatingToIntegral: { + APFloat F(0.0); + if (!EvaluateFloat(SubExpr, F, Info)) + return false; + + return Success(HandleFloatToIntCast(DestType, SrcType, F, Info.Ctx), E); + } + } + + llvm_unreachable("unknown cast resulting in integral value"); + return false; +} + +bool IntExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { + if (E->getSubExpr()->getType()->isAnyComplexType()) { + ComplexValue 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()) { + ComplexValue 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); +} + +bool IntExprEvaluator::VisitSizeOfPackExpr(const SizeOfPackExpr *E) { + return Success(E->getPackLength(), E); +} + +bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) { + return Success(E->getValue(), E); +} + +//===----------------------------------------------------------------------===// +// Float Evaluation +//===----------------------------------------------------------------------===// + +namespace { +class FloatExprEvaluator + : public ExprEvaluatorBase<FloatExprEvaluator, bool> { + APFloat &Result; +public: + FloatExprEvaluator(EvalInfo &info, APFloat &result) + : ExprEvaluatorBaseTy(info), Result(result) {} + + bool Success(const APValue &V, const Expr *e) { + Result = V.getFloat(); + return true; + } + bool Error(const Stmt *S) { + return false; + } + + bool VisitCallExpr(const CallExpr *E); + + bool VisitUnaryOperator(const UnaryOperator *E); + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitFloatingLiteral(const FloatingLiteral *E); + bool VisitCastExpr(const CastExpr *E); + bool VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E); + + bool VisitUnaryReal(const UnaryOperator *E); + bool VisitUnaryImag(const UnaryOperator *E); + + bool VisitDeclRefExpr(const DeclRefExpr *E); + + // FIXME: Missing: array subscript of vector, member of vector, + // ImplicitValueInitExpr +}; +} // end anonymous namespace + +static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) { + assert(E->getType()->isRealFloatingType()); + return FloatExprEvaluator(Info, Result).Visit(E); +} + +static bool TryEvaluateBuiltinNaN(const ASTContext &Context, + QualType ResultTy, + const Expr *Arg, + bool SNaN, + llvm::APFloat &Result) { + const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts()); + if (!S) return false; + + const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy); + + llvm::APInt fill; + + // Treat empty strings as if they were zero. + if (S->getString().empty()) + fill = llvm::APInt(32, 0); + else if (S->getString().getAsInteger(0, fill)) + return false; + + if (SNaN) + Result = llvm::APFloat::getSNaN(Sem, false, &fill); + else + Result = llvm::APFloat::getQNaN(Sem, false, &fill); + return true; +} + +bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { + switch (E->isBuiltinCall(Info.Ctx)) { + default: + return ExprEvaluatorBaseTy::VisitCallExpr(E); + + 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_nans: + case Builtin::BI__builtin_nansf: + case Builtin::BI__builtin_nansl: + return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), + true, Result); + + 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. + return TryEvaluateBuiltinNaN(Info.Ctx, E->getType(), E->getArg(0), + false, Result); + + 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::VisitDeclRefExpr(const DeclRefExpr *E) { + if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E)) + return true; + + const Decl *D = E->getDecl(); + if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D)) return false; + const VarDecl *VD = cast<VarDecl>(D); + + // Require the qualifiers to be const and not volatile. + CanQualType T = Info.Ctx.getCanonicalType(E->getType()); + if (!T.isConstQualified() || T.isVolatileQualified()) + return false; + + const Expr *Init = VD->getAnyInitializer(); + if (!Init) return false; + + if (APValue *V = VD->getEvaluatedValue()) { + if (V->isFloat()) { + Result = V->getFloat(); + return true; + } + return false; + } + + if (VD->isEvaluatingValue()) + return false; + + VD->setEvaluatingValue(); + + Expr::EvalResult InitResult; + if (Init->Evaluate(InitResult, Info.Ctx) && !InitResult.HasSideEffects && + InitResult.Val.isFloat()) { + // Cache the evaluated value in the variable declaration. + Result = InitResult.Val.getFloat(); + VD->setEvaluatedValue(InitResult.Val); + return true; + } + + VD->setEvaluatedValue(APValue()); + return false; +} + +bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) { + if (E->getSubExpr()->getType()->isAnyComplexType()) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatReal; + return true; + } + + return Visit(E->getSubExpr()); +} + +bool FloatExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { + if (E->getSubExpr()->getType()->isAnyComplexType()) { + ComplexValue CV; + if (!EvaluateComplex(E->getSubExpr(), CV, Info)) + return false; + Result = CV.FloatImag; + return true; + } + + if (!E->getSubExpr()->isEvaluatable(Info.Ctx)) + Info.EvalResult.HasSideEffects = true; + const llvm::fltSemantics &Sem = Info.Ctx.getFloatTypeSemantics(E->getType()); + Result = llvm::APFloat::getZero(Sem); + return true; +} + +bool FloatExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + if (E->getOpcode() == UO_Deref) + return false; + + if (!EvaluateFloat(E->getSubExpr(), Result, Info)) + return false; + + switch (E->getOpcode()) { + default: return false; + case UO_Plus: + return true; + case UO_Minus: + Result.changeSign(); + return true; + } +} + +bool FloatExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BO_Comma) { + if (!EvaluateFloat(E->getRHS(), Result, Info)) + 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; + } + + // We can't evaluate pointer-to-member operations. + if (E->isPtrMemOp()) + return false; + + // 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 BO_Mul: + Result.multiply(RHS, APFloat::rmNearestTiesToEven); + return true; + case BO_Add: + Result.add(RHS, APFloat::rmNearestTiesToEven); + return true; + case BO_Sub: + Result.subtract(RHS, APFloat::rmNearestTiesToEven); + return true; + case BO_Div: + Result.divide(RHS, APFloat::rmNearestTiesToEven); + return true; + } +} + +bool FloatExprEvaluator::VisitFloatingLiteral(const FloatingLiteral *E) { + Result = E->getValue(); + return true; +} + +bool FloatExprEvaluator::VisitCastExpr(const CastExpr *E) { + const Expr* SubExpr = E->getSubExpr(); + + switch (E->getCastKind()) { + default: + return false; + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(SubExpr); + + case CK_IntegralToFloating: { + APSInt IntResult; + if (!EvaluateInteger(SubExpr, IntResult, Info)) + return false; + Result = HandleIntToFloatCast(E->getType(), SubExpr->getType(), + IntResult, Info.Ctx); + return true; + } + + case CK_FloatingCast: { + if (!Visit(SubExpr)) + return false; + Result = HandleFloatToFloatCast(E->getType(), SubExpr->getType(), + Result, Info.Ctx); + return true; + } + + case CK_FloatingComplexToReal: { + ComplexValue V; + if (!EvaluateComplex(SubExpr, V, Info)) + return false; + Result = V.getComplexFloatReal(); + return true; + } + } + + return false; +} + +bool FloatExprEvaluator::VisitCXXScalarValueInitExpr(const CXXScalarValueInitExpr *E) { + Result = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(E->getType())); + return true; +} + +//===----------------------------------------------------------------------===// +// Complex Evaluation (for float and integer) +//===----------------------------------------------------------------------===// + +namespace { +class ComplexExprEvaluator + : public ExprEvaluatorBase<ComplexExprEvaluator, bool> { + ComplexValue &Result; + +public: + ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result) + : ExprEvaluatorBaseTy(info), Result(Result) {} + + bool Success(const APValue &V, const Expr *e) { + Result.setFrom(V); + return true; + } + bool Error(const Expr *E) { + return false; + } + + //===--------------------------------------------------------------------===// + // Visitor Methods + //===--------------------------------------------------------------------===// + + bool VisitImaginaryLiteral(const ImaginaryLiteral *E); + + bool VisitCastExpr(const CastExpr *E); + + bool VisitBinaryOperator(const BinaryOperator *E); + bool VisitUnaryOperator(const UnaryOperator *E); + // FIXME Missing: ImplicitValueInitExpr +}; +} // end anonymous namespace + +static bool EvaluateComplex(const Expr *E, ComplexValue &Result, + EvalInfo &Info) { + assert(E->getType()->isAnyComplexType()); + return ComplexExprEvaluator(Info, Result).Visit(E); +} + +bool ComplexExprEvaluator::VisitImaginaryLiteral(const ImaginaryLiteral *E) { + const Expr* SubExpr = E->getSubExpr(); + + if (SubExpr->getType()->isRealFloatingType()) { + Result.makeComplexFloat(); + APFloat &Imag = Result.FloatImag; + if (!EvaluateFloat(SubExpr, Imag, Info)) + return false; + + Result.FloatReal = APFloat(Imag.getSemantics()); + return true; + } else { + assert(SubExpr->getType()->isIntegerType() && + "Unexpected imaginary literal."); + + Result.makeComplexInt(); + APSInt &Imag = Result.IntImag; + if (!EvaluateInteger(SubExpr, Imag, Info)) + return false; + + Result.IntReal = APSInt(Imag.getBitWidth(), !Imag.isSigned()); + return true; + } +} + +bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { + + switch (E->getCastKind()) { + case CK_BitCast: + case CK_BaseToDerived: + case CK_DerivedToBase: + case CK_UncheckedDerivedToBase: + case CK_Dynamic: + case CK_ToUnion: + case CK_ArrayToPointerDecay: + case CK_FunctionToPointerDecay: + case CK_NullToPointer: + case CK_NullToMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_DerivedToBaseMemberPointer: + case CK_MemberPointerToBoolean: + case CK_ConstructorConversion: + case CK_IntegralToPointer: + case CK_PointerToIntegral: + case CK_PointerToBoolean: + case CK_ToVoid: + case CK_VectorSplat: + case CK_IntegralCast: + case CK_IntegralToBoolean: + case CK_IntegralToFloating: + case CK_FloatingToIntegral: + case CK_FloatingToBoolean: + case CK_FloatingCast: + case CK_AnyPointerToObjCPointerCast: + case CK_AnyPointerToBlockPointerCast: + case CK_ObjCObjectLValueCast: + case CK_FloatingComplexToReal: + case CK_FloatingComplexToBoolean: + case CK_IntegralComplexToReal: + case CK_IntegralComplexToBoolean: + llvm_unreachable("invalid cast kind for complex value"); + + case CK_LValueToRValue: + case CK_NoOp: + return Visit(E->getSubExpr()); + + case CK_Dependent: + case CK_GetObjCProperty: + case CK_LValueBitCast: + case CK_UserDefinedConversion: + return false; + + case CK_FloatingRealToComplex: { + APFloat &Real = Result.FloatReal; + if (!EvaluateFloat(E->getSubExpr(), Real, Info)) + return false; + + Result.makeComplexFloat(); + Result.FloatImag = APFloat(Real.getSemantics()); + return true; + } + + case CK_FloatingComplexCast: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + + Result.FloatReal + = HandleFloatToFloatCast(To, From, Result.FloatReal, Info.Ctx); + Result.FloatImag + = HandleFloatToFloatCast(To, From, Result.FloatImag, Info.Ctx); + return true; + } + + case CK_FloatingComplexToIntegralComplex: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + Result.makeComplexInt(); + Result.IntReal = HandleFloatToIntCast(To, From, Result.FloatReal, Info.Ctx); + Result.IntImag = HandleFloatToIntCast(To, From, Result.FloatImag, Info.Ctx); + return true; + } + + case CK_IntegralRealToComplex: { + APSInt &Real = Result.IntReal; + if (!EvaluateInteger(E->getSubExpr(), Real, Info)) + return false; + + Result.makeComplexInt(); + Result.IntImag = APSInt(Real.getBitWidth(), !Real.isSigned()); + return true; + } + + case CK_IntegralComplexCast: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + + Result.IntReal = HandleIntToIntCast(To, From, Result.IntReal, Info.Ctx); + Result.IntImag = HandleIntToIntCast(To, From, Result.IntImag, Info.Ctx); + return true; + } + + case CK_IntegralComplexToFloatingComplex: { + if (!Visit(E->getSubExpr())) + return false; + + QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType From + = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + Result.makeComplexFloat(); + Result.FloatReal = HandleIntToFloatCast(To, From, Result.IntReal, Info.Ctx); + Result.FloatImag = HandleIntToFloatCast(To, From, Result.IntImag, Info.Ctx); + return true; + } + } + + llvm_unreachable("unknown cast resulting in complex value"); + return false; +} + +bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { + if (E->getOpcode() == BO_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 (!Visit(E->getLHS())) + return false; + + ComplexValue RHS; + if (!EvaluateComplex(E->getRHS(), RHS, Info)) + return false; + + assert(Result.isComplexFloat() == RHS.isComplexFloat() && + "Invalid operands to binary operator."); + switch (E->getOpcode()) { + default: return false; + case BO_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 BO_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 BO_Mul: + if (Result.isComplexFloat()) { + ComplexValue 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 { + ComplexValue LHS = Result; + Result.getComplexIntReal() = + (LHS.getComplexIntReal() * RHS.getComplexIntReal() - + LHS.getComplexIntImag() * RHS.getComplexIntImag()); + Result.getComplexIntImag() = + (LHS.getComplexIntReal() * RHS.getComplexIntImag() + + LHS.getComplexIntImag() * RHS.getComplexIntReal()); + } + break; + case BO_Div: + if (Result.isComplexFloat()) { + ComplexValue LHS = Result; + APFloat &LHS_r = LHS.getComplexFloatReal(); + APFloat &LHS_i = LHS.getComplexFloatImag(); + APFloat &RHS_r = RHS.getComplexFloatReal(); + APFloat &RHS_i = RHS.getComplexFloatImag(); + APFloat &Res_r = Result.getComplexFloatReal(); + APFloat &Res_i = Result.getComplexFloatImag(); + + APFloat Den = RHS_r; + Den.multiply(RHS_r, APFloat::rmNearestTiesToEven); + APFloat Tmp = RHS_i; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Den.add(Tmp, APFloat::rmNearestTiesToEven); + + Res_r = LHS_r; + Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Tmp = LHS_i; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Res_r.add(Tmp, APFloat::rmNearestTiesToEven); + Res_r.divide(Den, APFloat::rmNearestTiesToEven); + + Res_i = LHS_i; + Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven); + Tmp = LHS_r; + Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); + Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven); + Res_i.divide(Den, APFloat::rmNearestTiesToEven); + } else { + if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) { + // FIXME: what about diagnostics? + return false; + } + ComplexValue LHS = Result; + APSInt Den = RHS.getComplexIntReal() * RHS.getComplexIntReal() + + RHS.getComplexIntImag() * RHS.getComplexIntImag(); + Result.getComplexIntReal() = + (LHS.getComplexIntReal() * RHS.getComplexIntReal() + + LHS.getComplexIntImag() * RHS.getComplexIntImag()) / Den; + Result.getComplexIntImag() = + (LHS.getComplexIntImag() * RHS.getComplexIntReal() - + LHS.getComplexIntReal() * RHS.getComplexIntImag()) / Den; + } + break; + } + + return true; +} + +bool ComplexExprEvaluator::VisitUnaryOperator(const UnaryOperator *E) { + // Get the operand value into 'Result'. + if (!Visit(E->getSubExpr())) + return false; + + switch (E->getOpcode()) { + default: + // FIXME: what about diagnostics? + return false; + case UO_Extension: + return true; + case UO_Plus: + // The result is always just the subexpr. + return true; + case UO_Minus: + if (Result.isComplexFloat()) { + Result.getComplexFloatReal().changeSign(); + Result.getComplexFloatImag().changeSign(); + } + else { + Result.getComplexIntReal() = -Result.getComplexIntReal(); + Result.getComplexIntImag() = -Result.getComplexIntImag(); + } + return true; + case UO_Not: + if (Result.isComplexFloat()) + Result.getComplexFloatImag().changeSign(); + else + Result.getComplexIntImag() = -Result.getComplexIntImag(); + return true; + } +} + +//===----------------------------------------------------------------------===// +// Top level Expr::Evaluate method. +//===----------------------------------------------------------------------===// + +static bool Evaluate(EvalInfo &Info, const Expr *E) { + if (E->getType()->isVectorType()) { + if (!EvaluateVector(E, Info.EvalResult.Val, Info)) + return false; + } else if (E->getType()->isIntegralOrEnumerationType()) { + if (!IntExprEvaluator(Info, Info.EvalResult.Val).Visit(E)) + return false; + if (Info.EvalResult.Val.isLValue() && + !IsGlobalLValue(Info.EvalResult.Val.getLValueBase())) + return false; + } else if (E->getType()->hasPointerRepresentation()) { + LValue LV; + if (!EvaluatePointer(E, LV, Info)) + return false; + if (!IsGlobalLValue(LV.Base)) + return false; + LV.moveInto(Info.EvalResult.Val); + } else if (E->getType()->isRealFloatingType()) { + llvm::APFloat F(0.0); + if (!EvaluateFloat(E, F, Info)) + return false; + + Info.EvalResult.Val = APValue(F); + } else if (E->getType()->isAnyComplexType()) { + ComplexValue C; + if (!EvaluateComplex(E, C, Info)) + return false; + C.moveInto(Info.EvalResult.Val); + } else + return false; + + return true; +} + +/// 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, const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + return ::Evaluate(Info, this); +} + +bool Expr::EvaluateAsBooleanCondition(bool &Result, + const ASTContext &Ctx) const { + EvalResult Scratch; + EvalInfo Info(Ctx, Scratch); + + return HandleConversionToBool(this, Result, Info); +} + +bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + + LValue LV; + if (EvaluateLValue(this, LV, Info) && + !Result.HasSideEffects && + IsGlobalLValue(LV.Base)) { + LV.moveInto(Result.Val); + return true; + } + return false; +} + +bool Expr::EvaluateAsAnyLValue(EvalResult &Result, + const ASTContext &Ctx) const { + EvalInfo Info(Ctx, Result); + + LValue LV; + if (EvaluateLValue(this, LV, Info)) { + LV.moveInto(Result.Val); + return true; + } + return false; +} + +/// isEvaluatable - Call Evaluate to see if this expression can be constant +/// folded, but discard the result. +bool Expr::isEvaluatable(const ASTContext &Ctx) const { + EvalResult Result; + return Evaluate(Result, Ctx) && !Result.HasSideEffects; +} + +bool Expr::HasSideEffects(const ASTContext &Ctx) const { + Expr::EvalResult Result; + EvalInfo Info(Ctx, Result); + return HasSideEffect(Info).Visit(this); +} + +APSInt Expr::EvaluateAsInt(const ASTContext &Ctx) const { + EvalResult EvalResult; + bool Result = Evaluate(EvalResult, Ctx); + (void)Result; + assert(Result && "Could not evaluate expression"); + assert(EvalResult.Val.isInt() && "Expression did not evaluate to integer"); + + return EvalResult.Val.getInt(); +} + + bool Expr::EvalResult::isGlobalLValue() const { + assert(Val.isLValue()); + return IsGlobalLValue(Val.getLValueBase()); + } + + +/// 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. + +namespace { + +struct ICEDiag { + unsigned Val; + SourceLocation Loc; + + public: + ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {} + ICEDiag() : Val(0) {} +}; + +} + +static 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()->isIntegralOrEnumerationType()) { + return ICEDiag(2, E->getLocStart()); + } + + switch (E->getStmtClass()) { +#define ABSTRACT_STMT(Node) +#define STMT(Node, Base) case Expr::Node##Class: +#define EXPR(Node, Base) +#include "clang/AST/StmtNodes.inc" + case Expr::PredefinedExprClass: + case Expr::FloatingLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::StringLiteralClass: + case Expr::ArraySubscriptExprClass: + case Expr::MemberExprClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::VAArgExprClass: + case Expr::AddrLabelExprClass: + case Expr::StmtExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CUDAKernelCallExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXTypeidExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXThrowExprClass: + case Expr::CXXNewExprClass: + case Expr::CXXDeleteExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::DependentScopeDeclRefExprClass: + case Expr::CXXConstructExprClass: + case Expr::CXXBindTemporaryExprClass: + case Expr::ExprWithCleanupsClass: + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::BlockExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::NoStmtClass: + case Expr::OpaqueValueExprClass: + case Expr::PackExpansionExprClass: + case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: + return ICEDiag(2, E->getLocStart()); + + case Expr::SizeOfPackExprClass: + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + return NoDiag(); + + case Expr::ParenExprClass: + return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); + case Expr::GenericSelectionExprClass: + return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx); + case Expr::IntegerLiteralClass: + case Expr::CharacterLiteralClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: + case Expr::CXXNoexceptExprClass: + 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: + if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) + return NoDiag(); + if (Ctx.getLangOptions().CPlusPlus && + E->getType().getCVRQualifiers() == Qualifiers::Const) { + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); + + // Parameter variables are never constants. Without this check, + // getAnyInitializer() can find a default argument, which leads + // to chaos. + if (isa<ParmVarDecl>(D)) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // 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>(D)) { + Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); + if (Quals.hasVolatile() || !Quals.hasConst()) + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + + // Look for a declaration of this variable that has an initializer. + const VarDecl *ID = 0; + const Expr *Init = Dcl->getAnyInitializer(ID); + if (Init) { + if (ID->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (ID->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + + // It's an ICE whether or not the definition we found is + // out-of-line. See DR 721 and the discussion in Clang PR + // 6206 for details. + + if (Dcl->isCheckingICE()) { + return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation()); + } + + Dcl->setCheckingICE(); + ICEDiag Result = CheckICE(Init, Ctx); + // Cache the result of the ICE test. + Dcl->setInitKnownICE(Result.Val == 0); + return Result; + } + } + } + return ICEDiag(2, E->getLocStart()); + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast<UnaryOperator>(E); + switch (Exp->getOpcode()) { + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: + case UO_AddrOf: + case UO_Deref: + return ICEDiag(2, E->getLocStart()); + case UO_Extension: + case UO_LNot: + case UO_Plus: + case UO_Minus: + case UO_Not: + case UO_Real: + case UO_Imag: + return CheckICE(Exp->getSubExpr(), Ctx); + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { + // 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::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E); + if ((Exp->getKind() == UETT_SizeOf) && + Exp->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(2, E->getLocStart()); + return NoDiag(); + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast<BinaryOperator>(E); + switch (Exp->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + case BO_Assign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_AddAssign: + case BO_SubAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + return ICEDiag(2, E->getLocStart()); + + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_Comma: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); + if (Exp->getOpcode() == BO_Div || + Exp->getOpcode() == BO_Rem) { + // Evaluate gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Val == 0 && RHSResult.Val == 0) { + 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() == BO_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 BO_LAnd: + case BO_LOr: { + ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); + + // C++0x [expr.const]p2: + // [...] subexpressions of logical AND (5.14), logical OR + // (5.15), and condi- tional (5.16) operations that are not + // evaluated are not considered. + if (Ctx.getLangOptions().CPlusPlus0x && LHSResult.Val == 0) { + if (Exp->getOpcode() == BO_LAnd && + Exp->getLHS()->EvaluateAsInt(Ctx) == 0) + return LHSResult; + + if (Exp->getOpcode() == BO_LOr && + Exp->getLHS()->EvaluateAsInt(Ctx) != 0) + return LHSResult; + } + + 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() == BO_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: + case Expr::CXXStaticCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: { + const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); + if (SubExpr->getType()->isIntegralOrEnumerationType()) + return CheckICE(SubExpr, Ctx); + if (isa<FloatingLiteral>(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } + case Expr::BinaryConditionalOperatorClass: { + const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E); + ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx); + if (CommonResult.Val == 2) return CommonResult; + ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + if (FalseResult.Val == 2) return FalseResult; + if (CommonResult.Val == 1) return CommonResult; + if (FalseResult.Val == 1 && + Exp->getCommon()->EvaluateAsInt(Ctx) == 0) return NoDiag(); + return FalseResult; + } + 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); + if (CondResult.Val == 2) + return CondResult; + + // C++0x [expr.const]p2: + // subexpressions of [...] conditional (5.16) operations that + // are not evaluated are not considered + bool TrueBranch = Ctx.getLangOptions().CPlusPlus0x + ? Exp->getCond()->EvaluateAsInt(Ctx) != 0 + : false; + ICEDiag TrueResult = NoDiag(); + if (!Ctx.getLangOptions().CPlusPlus0x || TrueBranch) + TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); + ICEDiag FalseResult = NoDiag(); + if (!Ctx.getLangOptions().CPlusPlus0x || !TrueBranch) + FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); + + 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); + } + } + + // Silence a GCC warning + return ICEDiag(2, E->getLocStart()); +} + +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)) + llvm_unreachable("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; +} diff --git a/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp new file mode 100644 index 000000000000..f428318a21e3 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ExternalASTSource.cpp @@ -0,0 +1,61 @@ +//===- ExternalASTSource.cpp - Abstract External AST Interface --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the default implementation of the ExternalASTSource +// interface, which enables construction of AST nodes from some external +// source. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ExternalASTSource.h" +#include "clang/AST/DeclarationName.h" + +using namespace clang; + +ExternalASTSource::~ExternalASTSource() { } + +void ExternalASTSource::PrintStats() { } + +Decl *ExternalASTSource::GetExternalDecl(uint32_t ID) { + return 0; +} + +Selector ExternalASTSource::GetExternalSelector(uint32_t ID) { + return Selector(); +} + +uint32_t ExternalASTSource::GetNumExternalSelectors() { + return 0; +} + +Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) { + return 0; +} + +CXXBaseSpecifier * +ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { + return 0; +} + +DeclContextLookupResult +ExternalASTSource::FindExternalVisibleDeclsByName(const DeclContext *DC, + DeclarationName Name) { + return DeclContext::lookup_result(); +} + +void ExternalASTSource::MaterializeVisibleDecls(const DeclContext *DC) { } + +bool +ExternalASTSource::FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + llvm::SmallVectorImpl<Decl*> &Result) { + return true; +} + +void ExternalASTSource::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { } diff --git a/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp b/contrib/llvm/tools/clang/lib/AST/InheritViz.cpp new file mode 100644 index 000000000000..c47a9dadbadd --- /dev/null +++ b/contrib/llvm/tools/clang/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->getAs<RecordType>()->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(), 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/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp new file mode 100644 index 000000000000..30aece3ee73b --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumCXXABI.cpp @@ -0,0 +1,73 @@ +//===------- ItaniumCXXABI.cpp - AST support for the Itanium C++ ABI ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ AST support targeting the Itanium C++ ABI, which is +// documented at: +// http://www.codesourcery.com/public/cxx-abi/abi.html +// http://www.codesourcery.com/public/cxx-abi/abi-eh.html +// +// It also supports the closely-related ARM C++ ABI, documented at: +// http://infocenter.arm.com/help/topic/com.arm.doc.ihi0041c/IHI0041C_cppabi.pdf +// +//===----------------------------------------------------------------------===// + +#include "CXXABI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang; + +namespace { +class ItaniumCXXABI : public CXXABI { +protected: + ASTContext &Context; +public: + ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { } + + unsigned getMemberPointerSize(const MemberPointerType *MPT) const { + QualType Pointee = MPT->getPointeeType(); + if (Pointee->isFunctionType()) return 2; + return 1; + } + + CallingConv getDefaultMethodCallConv() const { + return CC_C; + } + + // We cheat and just check that the class has a vtable pointer, and that it's + // only big enough to have a vtable pointer and nothing more (or less). + bool isNearlyEmpty(const CXXRecordDecl *RD) const { + + // Check that the class has a vtable pointer. + if (!RD->isDynamicClass()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Layout.getNonVirtualSize() == PointerSize; + } +}; + +class ARMCXXABI : public ItaniumCXXABI { +public: + ARMCXXABI(ASTContext &Ctx) : ItaniumCXXABI(Ctx) { } +}; +} + +CXXABI *clang::CreateItaniumCXXABI(ASTContext &Ctx) { + return new ItaniumCXXABI(Ctx); +} + +CXXABI *clang::CreateARMCXXABI(ASTContext &Ctx) { + return new ARMCXXABI(Ctx); +} diff --git a/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp new file mode 100644 index 000000000000..e81ec7e54b62 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ItaniumMangle.cpp @@ -0,0 +1,3158 @@ +//===--- ItaniumMangle.cpp - Itanium C++ Name Mangling ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements C++ name mangling according to the Itanium C++ ABI, +// which is used in GCC 3.2 and newer (and many compilers that are +// ABI-compatible with GCC): +// +// http://www.codesourcery.com/public/cxx-abi/abi.html +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + +using namespace clang; + +namespace { + +static const CXXRecordDecl *GetLocalClassDecl(const NamedDecl *ND) { + const DeclContext *DC = dyn_cast<DeclContext>(ND); + if (!DC) + DC = ND->getDeclContext(); + while (!DC->isNamespace() && !DC->isTranslationUnit()) { + if (isa<FunctionDecl>(DC->getParent())) + return dyn_cast<CXXRecordDecl>(DC); + DC = DC->getParent(); + } + return 0; +} + +static const FunctionDecl *getStructor(const FunctionDecl *fn) { + if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) + return ftd->getTemplatedDecl(); + + return fn; +} + +static const NamedDecl *getStructor(const NamedDecl *decl) { + const FunctionDecl *fn = dyn_cast_or_null<FunctionDecl>(decl); + return (fn ? getStructor(fn) : decl); +} + +static const unsigned UnknownArity = ~0U; + +class ItaniumMangleContext : public MangleContext { + llvm::DenseMap<const TagDecl *, uint64_t> AnonStructIds; + unsigned Discriminator; + llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; + +public: + explicit ItaniumMangleContext(ASTContext &Context, + Diagnostic &Diags) + : MangleContext(Context, Diags) { } + + uint64_t getAnonymousStructId(const TagDecl *TD) { + std::pair<llvm::DenseMap<const TagDecl *, + uint64_t>::iterator, bool> Result = + AnonStructIds.insert(std::make_pair(TD, AnonStructIds.size())); + return Result.first->second; + } + + void startNewFunction() { + MangleContext::startNewFunction(); + mangleInitDiscriminator(); + } + + /// @name Mangler Entry Points + /// @{ + + bool shouldMangleDeclName(const NamedDecl *D); + void mangleName(const NamedDecl *D, llvm::raw_ostream &); + void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &); + void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &); + void mangleReferenceTemporary(const VarDecl *D, + llvm::raw_ostream &); + void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &); + void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &); + void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &); + void mangleCXXRTTI(QualType T, llvm::raw_ostream &); + void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::raw_ostream &); + void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::raw_ostream &); + + void mangleItaniumGuardVariable(const VarDecl *D, llvm::raw_ostream &); + + void mangleInitDiscriminator() { + Discriminator = 0; + } + + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + unsigned &discriminator = Uniquifier[ND]; + if (!discriminator) + discriminator = ++Discriminator; + if (discriminator == 1) + return false; + disc = discriminator-2; + return true; + } + /// @} +}; + +/// CXXNameMangler - Manage the mangling of a single name. +class CXXNameMangler { + ItaniumMangleContext &Context; + llvm::raw_ostream &Out; + + /// The "structor" is the top-level declaration being mangled, if + /// that's not a template specialization; otherwise it's the pattern + /// for that specialization. + const NamedDecl *Structor; + unsigned StructorType; + + /// SeqID - The next subsitution sequence number. + unsigned SeqID; + + class FunctionTypeDepthState { + unsigned Bits; + + enum { InResultTypeMask = 1 }; + + public: + FunctionTypeDepthState() : Bits(0) {} + + /// The number of function types we're inside. + unsigned getDepth() const { + return Bits >> 1; + } + + /// True if we're in the return type of the innermost function type. + bool isInResultType() const { + return Bits & InResultTypeMask; + } + + FunctionTypeDepthState push() { + FunctionTypeDepthState tmp = *this; + Bits = (Bits & ~InResultTypeMask) + 2; + return tmp; + } + + void enterResultType() { + Bits |= InResultTypeMask; + } + + void leaveResultType() { + Bits &= ~InResultTypeMask; + } + + void pop(FunctionTypeDepthState saved) { + assert(getDepth() == saved.getDepth() + 1); + Bits = saved.Bits; + } + + } FunctionTypeDepth; + + llvm::DenseMap<uintptr_t, unsigned> Substitutions; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const NamedDecl *D = 0) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(0), + SeqID(0) { + // These can't be mangled without a ctor type or dtor type. + assert(!D || (!isa<CXXDestructorDecl>(D) && + !isa<CXXConstructorDecl>(D))); + } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + CXXNameMangler(ItaniumMangleContext &C, llvm::raw_ostream &Out_, + const CXXDestructorDecl *D, CXXDtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + SeqID(0) { } + +#if MANGLE_CHECKER + ~CXXNameMangler() { + if (Out.str()[0] == '\01') + return; + + int status = 0; + char *result = abi::__cxa_demangle(Out.str().str().c_str(), 0, 0, &status); + assert(status == 0 && "Could not demangle mangled name!"); + free(result); + } +#endif + llvm::raw_ostream &getStream() { return Out; } + + void mangle(const NamedDecl *D, llvm::StringRef Prefix = "_Z"); + void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); + void mangleNumber(const llvm::APSInt &I); + void mangleNumber(int64_t Number); + void mangleFloat(const llvm::APFloat &F); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleName(const NamedDecl *ND); + void mangleType(QualType T); + void mangleNameOrStandardSubstitution(const NamedDecl *ND); + +private: + bool mangleSubstitution(const NamedDecl *ND); + bool mangleSubstitution(QualType T); + bool mangleSubstitution(TemplateName Template); + bool mangleSubstitution(uintptr_t Ptr); + + bool mangleStandardSubstitution(const NamedDecl *ND); + + void addSubstitution(const NamedDecl *ND) { + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + + addSubstitution(reinterpret_cast<uintptr_t>(ND)); + } + void addSubstitution(QualType T); + void addSubstitution(TemplateName Template); + void addSubstitution(uintptr_t Ptr); + + void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive = false); + void mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned KnownArity = UnknownArity); + + static bool isUnresolvedType(const Type *type); + void mangleUnresolvedType(const Type *type); + + void mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName(), UnknownArity); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, + unsigned KnownArity); + void mangleUnscopedName(const NamedDecl *ND); + void mangleUnscopedTemplateName(const TemplateDecl *ND); + void mangleUnscopedTemplateName(TemplateName); + void mangleSourceName(const IdentifierInfo *II); + void mangleLocalName(const NamedDecl *ND); + void mangleNestedName(const NamedDecl *ND, const DeclContext *DC, + bool NoFunction=false); + void mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void manglePrefix(NestedNameSpecifier *qualifier); + void manglePrefix(const DeclContext *DC, bool NoFunction=false); + void manglePrefix(QualType type); + void mangleTemplatePrefix(const TemplateDecl *ND); + void mangleTemplatePrefix(TemplateName Template); + void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); + void mangleQualifiers(Qualifiers Quals); + void mangleRefQualifier(RefQualifierKind RefQualifier); + + void mangleObjCMethodName(const ObjCMethodDecl *MD); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleType(TemplateName); + void mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType); + void mangleNeonVectorType(const VectorType *T); + + void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); + void mangleMemberExpr(const Expr *base, bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity); + void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); + void mangleCXXCtorType(CXXCtorType T); + void mangleCXXDtorType(CXXDtorType T); + + void mangleTemplateArgs(const ExplicitTemplateArgumentList &TemplateArgs); + void mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs); + void mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL); + void mangleTemplateArg(const NamedDecl *P, const TemplateArgument &A); + void mangleUnresolvedTemplateArgs(const TemplateArgument *args, + unsigned numArgs); + + void mangleTemplateParameter(unsigned Index); + + void mangleFunctionParam(const ParmVarDecl *parm); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = D->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool ItaniumMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOptions().CPlusPlus) + return false; + + // Variables at global scope with non-internal linkage are not mangled + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + // Check for extern variable declared locally. + if (DC->isFunctionOrMethod() && D->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + if (DC->isTranslationUnit() && D->getLinkage() != InternalLinkage) + return false; + } + + // Class members are always mangled. + if (D->getDeclContext()->isRecord()) + return true; + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void CXXNameMangler::mangle(const NamedDecl *D, llvm::StringRef Prefix) { + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + + // Adding the prefix can cause problems when one file has a "foo" and + // another has a "\01foo". That is known to happen on ELF with the + // tricks normally used for producing aliases (PR9177). Fortunately the + // llvm mangler on ELF is a nop, so we can just avoid adding the \01 + // marker. We also avoid adding the marker if this is an alias for an + // LLVM intrinsic. + llvm::StringRef UserLabelPrefix = + getASTContext().Target.getUserLabelPrefix(); + if (!UserLabelPrefix.empty() && !ALA->getLabel().startswith("llvm.")) + Out << '\01'; // LLVM IR Marker for __asm("foo") + + Out << ALA->getLabel(); + return; + } + + // <mangled-name> ::= _Z <encoding> + // ::= <data name> + // ::= <special-name> + Out << Prefix; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleName(VD); + else + mangleName(cast<FieldDecl>(D)); +} + +void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <encoding> ::= <function name> <bare-function-type> + mangleName(FD); + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // Whether the mangling of a function type includes the return type depends on + // the context and the nature of the function. The rules for deciding whether + // the return type is included are: + // + // 1. Template functions (names or types) have return types encoded, with + // the exceptions listed below. + // 2. Function types not appearing as part of a function name mangling, + // e.g. parameters, pointer types, etc., have return type encoded, with the + // exceptions listed below. + // 3. Non-template function names do not have return types encoded. + // + // The exceptions mentioned in (1) and (2) above, for which the return type is + // never included, are + // 1. Constructors. + // 2. Destructors. + // 3. Conversion operator functions, e.g. operator int. + bool MangleReturnType = false; + if (FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate()) { + if (!(isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) || + isa<CXXConversionDecl>(FD))) + MangleReturnType = true; + + // Mangle the type of the primary template. + FD = PrimaryTemplate->getTemplatedDecl(); + } + + // Do the canonicalization out here because parameter types can + // undergo additional canonicalization (e.g. array decay). + const FunctionType *FT + = cast<FunctionType>(Context.getASTContext() + .getCanonicalType(FD->getType())); + + mangleBareFunctionType(FT, MangleReturnType); +} + +static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { + while (isa<LinkageSpecDecl>(DC)) { + DC = DC->getParent(); + } + + return DC; +} + +/// isStd - Return whether a given namespace is the 'std' namespace. +static bool isStd(const NamespaceDecl *NS) { + if (!IgnoreLinkageSpecDecls(NS->getParent())->isTranslationUnit()) + return false; + + const IdentifierInfo *II = NS->getOriginalNamespace()->getIdentifier(); + return II && II->isStr("std"); +} + +// isStdNamespace - Return whether a given decl context is a toplevel 'std' +// namespace. +static bool isStdNamespace(const DeclContext *DC) { + if (!DC->isNamespace()) + return false; + + return isStd(cast<NamespaceDecl>(DC)); +} + +static const TemplateDecl * +isTemplate(const NamedDecl *ND, const TemplateArgumentList *&TemplateArgs) { + // Check if we have a function template. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)){ + if (const TemplateDecl *TD = FD->getPrimaryTemplate()) { + TemplateArgs = FD->getTemplateSpecializationArgs(); + return TD; + } + } + + // Check if we have a class template. + if (const ClassTemplateSpecializationDecl *Spec = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + TemplateArgs = &Spec->getTemplateArgs(); + return Spec->getSpecializedTemplate(); + } + + return 0; +} + +void CXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <nested-name> + // ::= <unscoped-name> + // ::= <unscoped-template-name> <template-args> + // ::= <local-name> + // + const DeclContext *DC = ND->getDeclContext(); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + else if (GetLocalClassDecl(ND)) { + mangleLocalName(ND); + return; + } + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleUnscopedTemplateName(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + return; + } + + mangleUnscopedName(ND); + return; + } + + if (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)) { + mangleLocalName(ND); + return; + } + + mangleNestedName(ND, DC); +} +void CXXNameMangler::mangleName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + const DeclContext *DC = IgnoreLinkageSpecDecls(TD->getDeclContext()); + + if (DC->isTranslationUnit() || isStdNamespace(DC)) { + mangleUnscopedTemplateName(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + } else { + mangleNestedName(TD, TemplateArgs, NumTemplateArgs); + } +} + +void CXXNameMangler::mangleUnscopedName(const NamedDecl *ND) { + // <unscoped-name> ::= <unqualified-name> + // ::= St <unqualified-name> # ::std:: + if (isStdNamespace(ND->getDeclContext())) + Out << "St"; + + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + mangleUnscopedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +void CXXNameMangler::mangleUnscopedTemplateName(TemplateName Template) { + // <unscoped-template-name> ::= <unscoped-name> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleUnscopedTemplateName(TD); + + if (mangleSubstitution(Template)) + return; + + // FIXME: How to cope with operators here? + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Not a dependent template name?"); + if (!Dependent->isIdentifier()) { + // FIXME: We can't possibly know the arity of the operator here! + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle dependent operator name"); + Diags.Report(DiagID); + return; + } + + mangleSourceName(Dependent->getIdentifier()); + addSubstitution(Template); +} + +void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { + // ABI: + // Floating-point literals are encoded using a fixed-length + // lowercase hexadecimal string corresponding to the internal + // representation (IEEE on Itanium), high-order bytes first, + // without leading zeroes. For example: "Lf bf800000 E" is -1.0f + // on Itanium. + // APInt::toString uses uppercase hexadecimal, and it's not really + // worth embellishing that interface for this use case, so we just + // do a second pass to lowercase things. + typedef llvm::SmallString<20> buffer_t; + buffer_t buffer; + f.bitcastToAPInt().toString(buffer, 16, false); + + for (buffer_t::iterator i = buffer.begin(), e = buffer.end(); i != e; ++i) + if (isupper(*i)) *i = tolower(*i); + + Out.write(buffer.data(), buffer.size()); +} + +void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + if (Value.isSigned() && Value.isNegative()) { + Out << 'n'; + Value.abs().print(Out, true); + } else + Value.print(Out, Value.isSigned()); +} + +void CXXNameMangler::mangleNumber(int64_t Number) { + // <number> ::= [n] <non-negative decimal integer> + if (Number < 0) { + Out << 'n'; + Number = -Number; + } + + Out << Number; +} + +void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { + // <call-offset> ::= h <nv-offset> _ + // ::= v <v-offset> _ + // <nv-offset> ::= <offset number> # non-virtual base override + // <v-offset> ::= <offset number> _ <virtual offset number> + // # virtual base override, with vcall offset + if (!Virtual) { + Out << 'h'; + mangleNumber(NonVirtual); + Out << '_'; + return; + } + + Out << 'v'; + mangleNumber(NonVirtual); + Out << '_'; + mangleNumber(Virtual); + Out << '_'; +} + +void CXXNameMangler::manglePrefix(QualType type) { + if (const TemplateSpecializationType *TST = + type->getAs<TemplateSpecializationType>()) { + if (!mangleSubstitution(QualType(TST, 0))) { + mangleTemplatePrefix(TST->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), + TST->getNumArgs()); + addSubstitution(QualType(TST, 0)); + } + } else if (const DependentTemplateSpecializationType *DTST + = type->getAs<DependentTemplateSpecializationType>()) { + TemplateName Template + = getASTContext().getDependentTemplateName(DTST->getQualifier(), + DTST->getIdentifier()); + mangleTemplatePrefix(Template); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); + } else { + // We use the QualType mangle type variant here because it handles + // substitutions. + mangleType(type); + } +} + +/// Returns true if the given type, appearing within an +/// unresolved-name, should be mangled as an unresolved-type. +bool CXXNameMangler::isUnresolvedType(const Type *type) { + // <unresolved-type> ::= <template-param> + // ::= <decltype> + // ::= <template-template-param> <template-args> + // (this last is not official yet) + + if (isa<TemplateTypeParmType>(type)) return true; + if (isa<DecltypeType>(type)) return true; + // typeof? + if (const TemplateSpecializationType *tst = + dyn_cast<TemplateSpecializationType>(type)) { + TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl(); + if (temp && isa<TemplateTemplateParmDecl>(temp)) + return true; + } + return false; +} + +void CXXNameMangler::mangleUnresolvedType(const Type *type) { + // This seems to be do everything we want. + mangleType(QualType(type, 0)); +} + +/// Mangle everything prior to the base-unresolved-name in an unresolved-name. +/// +/// \param firstQualifierLookup - the entity found by unqualified lookup +/// for the first name in the qualifier, if this is for a member expression +/// \param recursive - true if this is being called recursively, +/// i.e. if there is more prefix "to the right". +void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + bool recursive) { + + // x, ::x + // <unresolved-name> ::= [gs] <base-unresolved-name> + + // T::x / decltype(p)::x + // <unresolved-name> ::= sr <unresolved-type> <base-unresolved-name> + + // T::N::x /decltype(p)::N::x + // <unresolved-name> ::= srN <unresolved-type> <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + // A::x, N::y, A<T>::z; "gs" means leading "::" + // <unresolved-name> ::= [gs] sr <unresolved-qualifier-level>+ E + // <base-unresolved-name> + + switch (qualifier->getKind()) { + case NestedNameSpecifier::Global: + Out << "gs"; + + // We want an 'sr' unless this is the entire NNS. + if (recursive) + Out << "sr"; + + // We never want an 'E' here. + return; + + case NestedNameSpecifier::Namespace: + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespace()->getIdentifier()); + break; + case NestedNameSpecifier::NamespaceAlias: + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + else + Out << "sr"; + mangleSourceName(qualifier->getAsNamespaceAlias()->getIdentifier()); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + const Type *type = qualifier->getAsType(); + + // We only want to use an unresolved-type encoding if this is one of: + // - a decltype + // - a template type parameter + // - a template template parameter with arguments + // In all of these cases, we should have no prefix. + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else { + // Otherwise, all the cases want this. + Out << "sr"; + + if (isUnresolvedType(type)) { + // We only get here recursively if we're followed by identifiers. + if (recursive) Out << 'N'; + mangleUnresolvedType(type); + + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return; + } + } + + assert(!isUnresolvedType(type)); + + // Only certain other types are valid as prefixes; enumerate them. + // FIXME: can we get ElaboratedTypes here? + // FIXME: SubstTemplateTypeParmType? + if (const TagType *t = dyn_cast<TagType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const TypedefType *t = dyn_cast<TypedefType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const UnresolvedUsingType *t + = dyn_cast<UnresolvedUsingType>(type)) { + mangleSourceName(t->getDecl()->getIdentifier()); + } else if (const DependentNameType *t + = dyn_cast<DependentNameType>(type)) { + mangleSourceName(t->getIdentifier()); + } else if (const TemplateSpecializationType *tst + = dyn_cast<TemplateSpecializationType>(type)) { + TemplateDecl *temp = tst->getTemplateName().getAsTemplateDecl(); + assert(temp && "no template for template specialization type"); + mangleSourceName(temp->getIdentifier()); + mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + } else if (const DependentTemplateSpecializationType *tst + = dyn_cast<DependentTemplateSpecializationType>(type)) { + mangleSourceName(tst->getIdentifier()); + mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + } else { + llvm_unreachable("unexpected type in nested name specifier!"); + } + break; + } + + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes. + if (qualifier->getPrefix()) { + mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + /*recursive*/ true); + } else if (firstQualifierLookup) { + + // Try to make a proper qualifier out of the lookup result, and + // then just recurse on that. + NestedNameSpecifier *newQualifier; + if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) { + QualType type = getASTContext().getTypeDeclType(typeDecl); + + // Pretend we had a different nested name specifier. + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + /*template*/ false, + type.getTypePtr()); + } else if (NamespaceDecl *nspace = + dyn_cast<NamespaceDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + nspace); + } else if (NamespaceAliasDecl *alias = + dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) { + newQualifier = NestedNameSpecifier::Create(getASTContext(), + /*prefix*/ 0, + alias); + } else { + // No sensible mangling to do here. + newQualifier = 0; + } + + if (newQualifier) + return mangleUnresolvedPrefix(newQualifier, /*lookup*/ 0, recursive); + + } else { + Out << "sr"; + } + + mangleSourceName(qualifier->getAsIdentifier()); + break; + } + + // If this was the innermost part of the NNS, and we fell out to + // here, append an 'E'. + if (!recursive) + Out << 'E'; +} + +/// Mangle an unresolved-name, which is generally used for names which +/// weren't resolved to specific entities. +void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName name, + unsigned knownArity) { + if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup); + mangleUnqualifiedName(0, name, knownArity); +} + +static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { + assert(RD->isAnonymousStructOrUnion() && + "Expected anonymous struct or union!"); + + for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I) { + const FieldDecl *FD = *I; + + if (FD->getIdentifier()) + return FD; + + if (const RecordType *RT = FD->getType()->getAs<RecordType>()) { + if (const FieldDecl *NamedDataMember = + FindFirstNamedDataMember(RT->getDecl())) + return NamedDataMember; + } + } + + // We didn't find a named data member. + return 0; +} + +void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name, + unsigned KnownArity) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + // We must avoid conflicts between internally- and externally- + // linked variable and function declaration names in the same TU: + // void test() { extern void foo(); } + // static void foo(); + // This naming convention is the same as that followed by GCC, + // though it shouldn't actually matter. + if (ND && ND->getLinkage() == InternalLinkage && + ND->getDeclContext()->isFileContext()) + Out << 'L'; + + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + // This is how gcc mangles these names. + Out << "12_GLOBAL__N_1"; + break; + } + } + + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + // We must have an anonymous union or struct declaration. + const RecordDecl *RD = + cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); + + // Itanium C++ ABI 5.1.2: + // + // For the purposes of mangling, the name of an anonymous union is + // considered to be the name of the first named data member found by a + // pre-order, depth-first, declaration-order walk of the data members of + // the anonymous union. If there is no such data member (i.e., if all of + // the data members in the union are unnamed), then there is no way for + // a program to refer to the anonymous union, and there is therefore no + // need to mangle its name. + const FieldDecl *FD = FindFirstNamedDataMember(RD); + + // It's actually possible for various reasons for us to get here + // with an empty anonymous struct / union. Fortunately, it + // doesn't really matter what name we generate. + if (!FD) break; + assert(FD->getIdentifier() && "Data member name isn't an identifier!"); + + mangleSourceName(FD->getIdentifier()); + break; + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // Get a unique id for the anonymous struct. + uint64_t AnonStructId = Context.getAnonymousStructId(TD); + + // Mangle it as a source name in the form + // [n] $_<id> + // where n is the length of the string. + llvm::SmallString<8> Str; + Str += "$_"; + Str += llvm::utostr(AnonStructId); + + Out << Str.size(); + Out << Str.str(); + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + if (ND == Structor) + // If the named decl is the C++ constructor we're mangling, use the type + // we were given. + mangleCXXCtorType(static_cast<CXXCtorType>(StructorType)); + else + // Otherwise, use the complete constructor name. This is relevant if a + // class with a constructor is declared within a constructor. + mangleCXXCtorType(Ctor_Complete); + break; + + case DeclarationName::CXXDestructorName: + if (ND == Structor) + // If the named decl is the C++ destructor we're mangling, use the type we + // were given. + mangleCXXDtorType(static_cast<CXXDtorType>(StructorType)); + else + // Otherwise, use the complete destructor name. This is relevant if a + // class with a destructor is declared within a destructor. + mangleCXXDtorType(Dtor_Complete); + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= cv <type> # (cast) + Out << "cv"; + mangleType(Context.getASTContext().getCanonicalType(Name.getCXXNameType())); + break; + + case DeclarationName::CXXOperatorName: { + unsigned Arity; + if (ND) { + Arity = cast<FunctionDecl>(ND)->getNumParams(); + + // If we have a C++ member function, we need to include the 'this' pointer. + // FIXME: This does not make sense for operators that are static, but their + // names stay the same regardless of the arity (operator new for instance). + if (isa<CXXMethodDecl>(ND)) + Arity++; + } else + Arity = KnownArity; + + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); + break; + } + + case DeclarationName::CXXLiteralOperatorName: + // FIXME: This mangling is not yet official. + Out << "li"; + mangleSourceName(Name.getCXXLiteralIdentifier()); + break; + + case DeclarationName::CXXUsingDirective: + assert(false && "Can't mangle a using directive name!"); + break; + } +} + +void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source-name> ::= <positive length number> <identifier> + // <number> ::= [n] <non-negative decimal integer> + // <identifier> ::= <unqualified source code identifier> + Out << II->getLength() << II->getName(); +} + +void CXXNameMangler::mangleNestedName(const NamedDecl *ND, + const DeclContext *DC, + bool NoFunction) { + // <nested-name> + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <prefix> <unqualified-name> E + // ::= N [<CV-qualifiers>] [<ref-qualifier>] <template-prefix> + // <template-args> E + + Out << 'N'; + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(ND)) { + mangleQualifiers(Qualifiers::fromCVRMask(Method->getTypeQualifiers())); + mangleRefQualifier(Method->getRefQualifier()); + } + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + } + else { + manglePrefix(DC, NoFunction); + mangleUnqualifiedName(ND); + } + + Out << 'E'; +} +void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <nested-name> ::= N [<CV-qualifiers>] <template-prefix> <template-args> E + + Out << 'N'; + + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + + Out << 'E'; +} + +void CXXNameMangler::mangleLocalName(const NamedDecl *ND) { + // <local-name> := Z <function encoding> E <entity name> [<discriminator>] + // := Z <function encoding> E s [<discriminator>] + // <discriminator> := _ <non-negative number> + const DeclContext *DC = ND->getDeclContext(); + if (isa<ObjCMethodDecl>(DC) && isa<FunctionDecl>(ND)) { + // Don't add objc method name mangling to locally declared function + mangleUnqualifiedName(ND); + return; + } + + Out << 'Z'; + + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(MD); + } else if (const CXXRecordDecl *RD = GetLocalClassDecl(ND)) { + mangleFunctionEncoding(cast<FunctionDecl>(RD->getDeclContext())); + Out << 'E'; + + // Mangle the name relative to the closest enclosing function. + if (ND == RD) // equality ok because RD derived from ND above + mangleUnqualifiedName(ND); + else + mangleNestedName(ND, DC, true /*NoFunction*/); + + unsigned disc; + if (Context.getNextDiscriminator(RD, disc)) { + if (disc < 10) + Out << '_' << disc; + else + Out << "__" << disc << '_'; + } + + return; + } + else + mangleFunctionEncoding(cast<FunctionDecl>(DC)); + + Out << 'E'; + mangleUnqualifiedName(ND); +} + +void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { + switch (qualifier->getKind()) { + case NestedNameSpecifier::Global: + // nothing + return; + + case NestedNameSpecifier::Namespace: + mangleName(qualifier->getAsNamespace()); + return; + + case NestedNameSpecifier::NamespaceAlias: + mangleName(qualifier->getAsNamespaceAlias()->getNamespace()); + return; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: + manglePrefix(QualType(qualifier->getAsType(), 0)); + return; + + case NestedNameSpecifier::Identifier: + // Member expressions can have these without prefixes, but that + // should end up in mangleUnresolvedPrefix instead. + assert(qualifier->getPrefix()); + manglePrefix(qualifier->getPrefix()); + + mangleSourceName(qualifier->getAsIdentifier()); + return; + } + + llvm_unreachable("unexpected nested name specifier"); +} + +void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { + // <prefix> ::= <prefix> <unqualified-name> + // ::= <template-prefix> <template-args> + // ::= <template-param> + // ::= # empty + // ::= <substitution> + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *Block = dyn_cast<BlockDecl>(DC)) { + manglePrefix(DC->getParent(), NoFunction); + llvm::SmallString<64> Name; + llvm::raw_svector_ostream NameStream(Name); + Context.mangleBlock(Block, NameStream); + NameStream.flush(); + Out << Name.size() << Name; + return; + } + + if (mangleSubstitution(cast<NamedDecl>(DC))) + return; + + // Check if we have a template. + const TemplateArgumentList *TemplateArgs = 0; + if (const TemplateDecl *TD = isTemplate(cast<NamedDecl>(DC), TemplateArgs)) { + mangleTemplatePrefix(TD); + TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); + mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + } + else if(NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else { + manglePrefix(DC->getParent(), NoFunction); + mangleUnqualifiedName(cast<NamedDecl>(DC)); + } + + addSubstitution(cast<NamedDecl>(DC)); +} + +void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplatePrefix(TD); + + if (QualifiedTemplateName *Qualified = Template.getAsQualifiedTemplateName()) + manglePrefix(Qualified->getQualifier()); + + if (OverloadedTemplateStorage *Overloaded + = Template.getAsOverloadedTemplate()) { + mangleUnqualifiedName(0, (*Overloaded->begin())->getDeclName(), + UnknownArity); + return; + } + + DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); + assert(Dependent && "Unknown template name kind?"); + manglePrefix(Dependent->getQualifier()); + mangleUnscopedTemplateName(Template); +} + +void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND) { + // <template-prefix> ::= <prefix> <template unqualified-name> + // ::= <template-param> + // ::= <substitution> + // <template-template-param> ::= <template-param> + // <substitution> + + if (mangleSubstitution(ND)) + return; + + // <template-template-param> ::= <template-param> + if (const TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(ND)) { + mangleTemplateParameter(TTP->getIndex()); + return; + } + + manglePrefix(ND->getDeclContext()); + mangleUnqualifiedName(ND->getTemplatedDecl()); + addSubstitution(ND); +} + +/// Mangles a template name under the production <type>. Required for +/// template template arguments. +/// <type> ::= <class-enum-type> +/// ::= <template-param> +/// ::= <substitution> +void CXXNameMangler::mangleType(TemplateName TN) { + if (mangleSubstitution(TN)) + return; + + TemplateDecl *TD = 0; + + switch (TN.getKind()) { + case TemplateName::QualifiedTemplate: + TD = TN.getAsQualifiedTemplateName()->getTemplateDecl(); + goto HaveDecl; + + case TemplateName::Template: + TD = TN.getAsTemplateDecl(); + goto HaveDecl; + + HaveDecl: + if (isa<TemplateTemplateParmDecl>(TD)) + mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex()); + else + mangleName(TD); + break; + + case TemplateName::OverloadedTemplate: + llvm_unreachable("can't mangle an overloaded template name as a <type>"); + break; + + case TemplateName::DependentTemplate: { + const DependentTemplateName *Dependent = TN.getAsDependentTemplateName(); + assert(Dependent->isIdentifier()); + + // <class-enum-type> ::= <name> + // <name> ::= <nested-name> + mangleUnresolvedPrefix(Dependent->getQualifier(), 0); + mangleSourceName(Dependent->getIdentifier()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + SubstTemplateTemplateParmPackStorage *SubstPack + = TN.getAsSubstTemplateTemplateParmPack(); + mangleTemplateParameter(SubstPack->getParameterPack()->getIndex()); + break; + } + } + + addSubstitution(TN); +} + +void +CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { + switch (OO) { + // <operator-name> ::= nw # new + case OO_New: Out << "nw"; break; + // ::= na # new[] + case OO_Array_New: Out << "na"; break; + // ::= dl # delete + case OO_Delete: Out << "dl"; break; + // ::= da # delete[] + case OO_Array_Delete: Out << "da"; break; + // ::= ps # + (unary) + // ::= pl # + (binary or unknown) + case OO_Plus: + Out << (Arity == 1? "ps" : "pl"); break; + // ::= ng # - (unary) + // ::= mi # - (binary or unknown) + case OO_Minus: + Out << (Arity == 1? "ng" : "mi"); break; + // ::= ad # & (unary) + // ::= an # & (binary or unknown) + case OO_Amp: + Out << (Arity == 1? "ad" : "an"); break; + // ::= de # * (unary) + // ::= ml # * (binary or unknown) + case OO_Star: + // Use binary when unknown. + Out << (Arity == 1? "de" : "ml"); break; + // ::= co # ~ + case OO_Tilde: Out << "co"; break; + // ::= dv # / + case OO_Slash: Out << "dv"; break; + // ::= rm # % + case OO_Percent: Out << "rm"; break; + // ::= or # | + case OO_Pipe: Out << "or"; break; + // ::= eo # ^ + case OO_Caret: Out << "eo"; break; + // ::= aS # = + case OO_Equal: Out << "aS"; break; + // ::= pL # += + case OO_PlusEqual: Out << "pL"; break; + // ::= mI # -= + case OO_MinusEqual: Out << "mI"; break; + // ::= mL # *= + case OO_StarEqual: Out << "mL"; break; + // ::= dV # /= + case OO_SlashEqual: Out << "dV"; break; + // ::= rM # %= + case OO_PercentEqual: Out << "rM"; break; + // ::= aN # &= + case OO_AmpEqual: Out << "aN"; break; + // ::= oR # |= + case OO_PipeEqual: Out << "oR"; break; + // ::= eO # ^= + case OO_CaretEqual: Out << "eO"; break; + // ::= ls # << + case OO_LessLess: Out << "ls"; break; + // ::= rs # >> + case OO_GreaterGreater: Out << "rs"; break; + // ::= lS # <<= + case OO_LessLessEqual: Out << "lS"; break; + // ::= rS # >>= + case OO_GreaterGreaterEqual: Out << "rS"; break; + // ::= eq # == + case OO_EqualEqual: Out << "eq"; break; + // ::= ne # != + case OO_ExclaimEqual: Out << "ne"; break; + // ::= lt # < + case OO_Less: Out << "lt"; break; + // ::= gt # > + case OO_Greater: Out << "gt"; break; + // ::= le # <= + case OO_LessEqual: Out << "le"; break; + // ::= ge # >= + case OO_GreaterEqual: Out << "ge"; break; + // ::= nt # ! + case OO_Exclaim: Out << "nt"; break; + // ::= aa # && + case OO_AmpAmp: Out << "aa"; break; + // ::= oo # || + case OO_PipePipe: Out << "oo"; break; + // ::= pp # ++ + case OO_PlusPlus: Out << "pp"; break; + // ::= mm # -- + case OO_MinusMinus: Out << "mm"; break; + // ::= cm # , + case OO_Comma: Out << "cm"; break; + // ::= pm # ->* + case OO_ArrowStar: Out << "pm"; break; + // ::= pt # -> + case OO_Arrow: Out << "pt"; break; + // ::= cl # () + case OO_Call: Out << "cl"; break; + // ::= ix # [] + case OO_Subscript: Out << "ix"; break; + + // ::= qu # ? + // The conditional operator can't be overloaded, but we still handle it when + // mangling expressions. + case OO_Conditional: Out << "qu"; break; + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an overloaded operator"); + break; + } +} + +void CXXNameMangler::mangleQualifiers(Qualifiers Quals) { + // <CV-qualifiers> ::= [r] [V] [K] # restrict (C99), volatile, const + if (Quals.hasRestrict()) + Out << 'r'; + if (Quals.hasVolatile()) + Out << 'V'; + if (Quals.hasConst()) + Out << 'K'; + + if (Quals.hasAddressSpace()) { + // Extension: + // + // <type> ::= U <address-space-number> + // + // where <address-space-number> is a source name consisting of 'AS' + // followed by the address space <number>. + llvm::SmallString<64> ASString; + ASString = "AS" + llvm::utostr_32(Quals.getAddressSpace()); + Out << 'U' << ASString.size() << ASString; + } + + // FIXME: For now, just drop all extension qualifiers on the floor. +} + +void CXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { + // <ref-qualifier> ::= R # lvalue reference + // ::= O # rvalue-reference + // Proposal to Itanium C++ ABI list on 1/26/11 + switch (RefQualifier) { + case RQ_None: + break; + + case RQ_LValue: + Out << 'R'; + break; + + case RQ_RValue: + Out << 'O'; + break; + } +} + +void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +void CXXNameMangler::mangleType(QualType nonCanon) { + // Only operate on the canonical type! + QualType canon = nonCanon.getCanonicalType(); + + SplitQualType split = canon.split(); + Qualifiers quals = split.second; + const Type *ty = split.first; + + bool isSubstitutable = quals || !isa<BuiltinType>(ty); + if (isSubstitutable && mangleSubstitution(canon)) + return; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (quals && isa<ArrayType>(ty)) { + ty = Context.getASTContext().getAsArrayType(canon); + quals = Qualifiers(); + + // Note that we don't update canon: we want to add the + // substitution at the canonical type. + } + + if (quals) { + mangleQualifiers(quals); + // Recurse: even if the qualified type isn't yet substitutable, + // the unqualified type might be. + mangleType(QualType(ty, 0)); + } else { + switch (ty->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ + return; +#define TYPE(CLASS, PARENT) \ + case Type::CLASS: \ + mangleType(static_cast<const CLASS##Type*>(ty)); \ + break; +#include "clang/AST/TypeNodes.def" + } + } + + // Add the substitution. + if (isSubstitutable) + addSubstitution(canon); +} + +void CXXNameMangler::mangleNameOrStandardSubstitution(const NamedDecl *ND) { + if (!mangleStandardSubstitution(ND)) + mangleName(ND); +} + +void CXXNameMangler::mangleType(const BuiltinType *T) { + // <type> ::= <builtin-type> + // <builtin-type> ::= v # void + // ::= w # wchar_t + // ::= b # bool + // ::= c # char + // ::= a # signed char + // ::= h # unsigned char + // ::= s # short + // ::= t # unsigned short + // ::= i # int + // ::= j # unsigned int + // ::= l # long + // ::= m # unsigned long + // ::= x # long long, __int64 + // ::= y # unsigned long long, __int64 + // ::= n # __int128 + // UNSUPPORTED: ::= o # unsigned __int128 + // ::= f # float + // ::= d # double + // ::= e # long double, __float80 + // UNSUPPORTED: ::= g # __float128 + // UNSUPPORTED: ::= Dd # IEEE 754r decimal floating point (64 bits) + // UNSUPPORTED: ::= De # IEEE 754r decimal floating point (128 bits) + // UNSUPPORTED: ::= Df # IEEE 754r decimal floating point (32 bits) + // UNSUPPORTED: ::= Dh # IEEE 754r half-precision floating point (16 bits) + // ::= Di # char32_t + // ::= Ds # char16_t + // ::= Dn # std::nullptr_t (i.e., decltype(nullptr)) + // ::= u <source-name> # vendor extended type + switch (T->getKind()) { + case BuiltinType::Void: Out << 'v'; break; + case BuiltinType::Bool: Out << 'b'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'c'; break; + case BuiltinType::UChar: Out << 'h'; break; + case BuiltinType::UShort: Out << 't'; break; + case BuiltinType::UInt: Out << 'j'; break; + case BuiltinType::ULong: Out << 'm'; break; + case BuiltinType::ULongLong: Out << 'y'; break; + case BuiltinType::UInt128: Out << 'o'; break; + case BuiltinType::SChar: Out << 'a'; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << 'w'; break; + case BuiltinType::Char16: Out << "Ds"; break; + case BuiltinType::Char32: Out << "Di"; break; + case BuiltinType::Short: Out << 's'; break; + case BuiltinType::Int: Out << 'i'; break; + case BuiltinType::Long: Out << 'l'; break; + case BuiltinType::LongLong: Out << 'x'; break; + case BuiltinType::Int128: Out << 'n'; break; + case BuiltinType::Float: Out << 'f'; break; + case BuiltinType::Double: Out << 'd'; break; + case BuiltinType::LongDouble: Out << 'e'; break; + case BuiltinType::NullPtr: Out << "Dn"; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + llvm_unreachable("mangling a placeholder type"); + break; + case BuiltinType::ObjCId: Out << "11objc_object"; break; + case BuiltinType::ObjCClass: Out << "10objc_class"; break; + case BuiltinType::ObjCSel: Out << "13objc_selector"; break; + } +} + +// <type> ::= <function-type> +// <function-type> ::= F [Y] <bare-function-type> E +void CXXNameMangler::mangleType(const FunctionProtoType *T) { + Out << 'F'; + // FIXME: We don't have enough information in the AST to produce the 'Y' + // encoding for extern "C" function types. + mangleBareFunctionType(T, /*MangleReturnType=*/true); + Out << 'E'; +} +void CXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} +void CXXNameMangler::mangleBareFunctionType(const FunctionType *T, + bool MangleReturnType) { + // We should never be mangling something without a prototype. + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // Record that we're in a function type. See mangleFunctionParam + // for details on what we're trying to achieve here. + FunctionTypeDepthState saved = FunctionTypeDepth.push(); + + // <bare-function-type> ::= <signature type>+ + if (MangleReturnType) { + FunctionTypeDepth.enterResultType(); + mangleType(Proto->getResultType()); + FunctionTypeDepth.leaveResultType(); + } + + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + // <builtin-type> ::= v # void + Out << 'v'; + + FunctionTypeDepth.pop(saved); + return; + } + + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); + + FunctionTypeDepth.pop(saved); + + // <builtin-type> ::= z # ellipsis + if (Proto->isVariadic()) + Out << 'z'; +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const UnresolvedUsingType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <class-enum-type> +// <class-enum-type> ::= <name> +void CXXNameMangler::mangleType(const EnumType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const RecordType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void CXXNameMangler::mangleType(const TagType *T) { + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= A <positive dimension number> _ <element type> +// ::= A [<dimension expression>] _ <element type> +void CXXNameMangler::mangleType(const ConstantArrayType *T) { + Out << 'A' << T->getSize() << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const VariableArrayType *T) { + Out << 'A'; + // decayed vla types (size 0) will just be skipped. + if (T->getSizeExpr()) + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const DependentSizedArrayType *T) { + Out << 'A'; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const IncompleteArrayType *T) { + Out << "A_"; + mangleType(T->getElementType()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= M <class type> <member type> +void CXXNameMangler::mangleType(const MemberPointerType *T) { + Out << 'M'; + mangleType(QualType(T->getClass(), 0)); + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { + mangleQualifiers(Qualifiers::fromCVRMask(FPT->getTypeQuals())); + mangleRefQualifier(FPT->getRefQualifier()); + mangleType(FPT); + + // Itanium C++ ABI 5.1.8: + // + // The type of a non-static member function is considered to be different, + // for the purposes of substitution, from the type of a namespace-scope or + // static member function whose type appears similar. The types of two + // non-static member functions are considered to be different, for the + // purposes of substitution, if the functions are members of different + // classes. In other words, for the purposes of substitution, the class of + // which the function is a member is considered part of the type of + // function. + + // We increment the SeqID here to emulate adding an entry to the + // substitution table. We can't actually add it because we don't want this + // particular function type to be substituted. + ++SeqID; + } else + mangleType(PointeeType); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { + mangleTemplateParameter(T->getIndex()); +} + +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { + mangleTemplateParameter(T->getReplacedParameter()->getIndex()); +} + +// <type> ::= P <type> # pointer-to +void CXXNameMangler::mangleType(const PointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} +void CXXNameMangler::mangleType(const ObjCObjectPointerType *T) { + Out << 'P'; + mangleType(T->getPointeeType()); +} + +// <type> ::= R <type> # reference-to +void CXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'R'; + mangleType(T->getPointeeType()); +} + +// <type> ::= O <type> # rvalue reference-to (C++0x) +void CXXNameMangler::mangleType(const RValueReferenceType *T) { + Out << 'O'; + mangleType(T->getPointeeType()); +} + +// <type> ::= C <type> # complex pair (C 2000) +void CXXNameMangler::mangleType(const ComplexType *T) { + Out << 'C'; + mangleType(T->getElementType()); +} + +// ARM's ABI for Neon vector types specifies that they should be mangled as +// if they are structs (to match ARM's initial implementation). The +// vector type must be one of the special types predefined by ARM. +void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { + QualType EltType = T->getElementType(); + assert(EltType->isBuiltinType() && "Neon vector element not a BuiltinType"); + const char *EltName = 0; + if (T->getVectorKind() == VectorType::NeonPolyVector) { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "poly8_t"; break; + case BuiltinType::Short: EltName = "poly16_t"; break; + default: llvm_unreachable("unexpected Neon polynomial vector element type"); + } + } else { + switch (cast<BuiltinType>(EltType)->getKind()) { + case BuiltinType::SChar: EltName = "int8_t"; break; + case BuiltinType::UChar: EltName = "uint8_t"; break; + case BuiltinType::Short: EltName = "int16_t"; break; + case BuiltinType::UShort: EltName = "uint16_t"; break; + case BuiltinType::Int: EltName = "int32_t"; break; + case BuiltinType::UInt: EltName = "uint32_t"; break; + case BuiltinType::LongLong: EltName = "int64_t"; break; + case BuiltinType::ULongLong: EltName = "uint64_t"; break; + case BuiltinType::Float: EltName = "float32_t"; break; + default: llvm_unreachable("unexpected Neon vector element type"); + } + } + const char *BaseName = 0; + unsigned BitSize = (T->getNumElements() * + getASTContext().getTypeSize(EltType)); + if (BitSize == 64) + BaseName = "__simd64_"; + else { + assert(BitSize == 128 && "Neon vector type not 64 or 128 bits"); + BaseName = "__simd128_"; + } + Out << strlen(BaseName) + strlen(EltName); + Out << BaseName << EltName; +} + +// GNU extension: vector types +// <type> ::= <vector-type> +// <vector-type> ::= Dv <positive dimension number> _ +// <extended element type> +// ::= Dv [<dimension expression>] _ <element type> +// <extended element type> ::= <element type> +// ::= p # AltiVec vector pixel +void CXXNameMangler::mangleType(const VectorType *T) { + if ((T->getVectorKind() == VectorType::NeonVector || + T->getVectorKind() == VectorType::NeonPolyVector)) { + mangleNeonVectorType(T); + return; + } + Out << "Dv" << T->getNumElements() << '_'; + if (T->getVectorKind() == VectorType::AltiVecPixel) + Out << 'p'; + else if (T->getVectorKind() == VectorType::AltiVecBool) + Out << 'b'; + else + mangleType(T->getElementType()); +} +void CXXNameMangler::mangleType(const ExtVectorType *T) { + mangleType(static_cast<const VectorType*>(T)); +} +void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { + Out << "Dv"; + mangleExpression(T->getSizeExpr()); + Out << '_'; + mangleType(T->getElementType()); +} + +void CXXNameMangler::mangleType(const PackExpansionType *T) { + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(T->getPattern()); +} + +void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { + mangleSourceName(T->getDecl()->getIdentifier()); +} + +void CXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + +void CXXNameMangler::mangleType(const BlockPointerType *T) { + Out << "U13block_pointer"; + mangleType(T->getPointeeType()); +} + +void CXXNameMangler::mangleType(const InjectedClassNameType *T) { + // Mangle injected class name types as if the user had written the + // specialization out fully. It may not actually be possible to see + // this mangling, though. + mangleType(T->getInjectedSpecializationType()); +} + +void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { + if (TemplateDecl *TD = T->getTemplateName().getAsTemplateDecl()) { + mangleName(TD, T->getArgs(), T->getNumArgs()); + } else { + if (mangleSubstitution(QualType(T, 0))) + return; + + mangleTemplatePrefix(T->getTemplateName()); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + addSubstitution(QualType(T, 0)); + } +} + +void CXXNameMangler::mangleType(const DependentNameType *T) { + // Typename types are always nested + Out << 'N'; + manglePrefix(T->getQualifier()); + mangleSourceName(T->getIdentifier()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { + // Dependently-scoped template types are nested if they have a prefix. + Out << 'N'; + + // TODO: avoid making this TemplateName. + TemplateName Prefix = + getASTContext().getDependentTemplateName(T->getQualifier(), + T->getIdentifier()); + mangleTemplatePrefix(Prefix); + + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs()); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const TypeOfType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const TypeOfExprType *T) { + // FIXME: this is pretty unsatisfactory, but there isn't an obvious + // "extension with parameters" mangling. + Out << "u6typeof"; +} + +void CXXNameMangler::mangleType(const DecltypeType *T) { + Expr *E = T->getUnderlyingExpr(); + + // type ::= Dt <expression> E # decltype of an id-expression + // # or class member access + // ::= DT <expression> E # decltype of an expression + + // This purports to be an exhaustive list of id-expressions and + // class member accesses. Note that we do not ignore parentheses; + // parentheses change the semantics of decltype for these + // expressions (and cause the mangler to use the other form). + if (isa<DeclRefExpr>(E) || + isa<MemberExpr>(E) || + isa<UnresolvedLookupExpr>(E) || + isa<DependentScopeDeclRefExpr>(E) || + isa<CXXDependentScopeMemberExpr>(E) || + isa<UnresolvedMemberExpr>(E)) + Out << "Dt"; + else + Out << "DT"; + mangleExpression(E); + Out << 'E'; +} + +void CXXNameMangler::mangleType(const UnaryTransformType *T) { + // If this is dependent, we need to record that. If not, we simply + // mangle it as the underlying type since they are equivalent. + if (T->isDependentType()) { + Out << 'U'; + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + Out << "3eut"; + break; + } + } + + mangleType(T->getUnderlyingType()); +} + +void CXXNameMangler::mangleType(const AutoType *T) { + QualType D = T->getDeducedType(); + // <builtin-type> ::= Da # dependent auto + if (D.isNull()) + Out << "Da"; + else + mangleType(D); +} + +void CXXNameMangler::mangleIntegerLiteral(QualType T, + const llvm::APSInt &Value) { + // <expr-primary> ::= L <type> <value number> E # integer literal + Out << 'L'; + + mangleType(T); + if (T->isBooleanType()) { + // Boolean values are encoded as 0/1. + Out << (Value.getBoolValue() ? '1' : '0'); + } else { + mangleNumber(Value); + } + Out << 'E'; + +} + +/// Mangles a member expression. Implicit accesses are not handled, +/// but that should be okay, because you shouldn't be able to +/// make an implicit access in a function template declaration. +void CXXNameMangler::mangleMemberExpr(const Expr *base, + bool isArrow, + NestedNameSpecifier *qualifier, + NamedDecl *firstQualifierLookup, + DeclarationName member, + unsigned arity) { + // <expression> ::= dt <expression> <unresolved-name> + // ::= pt <expression> <unresolved-name> + Out << (isArrow ? "pt" : "dt"); + mangleExpression(base); + mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); +} + +/// Look at the callee of the given call expression and determine if +/// it's a parenthesized id-expression which would have triggered ADL +/// otherwise. +static bool isParenthesizedADLCallee(const CallExpr *call) { + const Expr *callee = call->getCallee(); + const Expr *fn = callee->IgnoreParens(); + + // Must be parenthesized. IgnoreParens() skips __extension__ nodes, + // too, but for those to appear in the callee, it would have to be + // parenthesized. + if (callee == fn) return false; + + // Must be an unresolved lookup. + const UnresolvedLookupExpr *lookup = dyn_cast<UnresolvedLookupExpr>(fn); + if (!lookup) return false; + + assert(!lookup->requiresADL()); + + // Must be an unqualified lookup. + if (lookup->getQualifier()) return false; + + // Must not have found a class member. Note that if one is a class + // member, they're all class members. + if (lookup->getNumDecls() > 0 && + (*lookup->decls_begin())->isCXXClassMember()) + return false; + + // Otherwise, ADL would have been triggered. + return true; +} + +void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { + // <expression> ::= <unary operator-name> <expression> + // ::= <binary operator-name> <expression> <expression> + // ::= <trinary operator-name> <expression> <expression> <expression> + // ::= cv <type> expression # conversion with one argument + // ::= cv <type> _ <expression>* E # conversion with a different number of arguments + // ::= st <type> # sizeof (a type) + // ::= at <type> # alignof (a type) + // ::= <template-param> + // ::= <function-param> + // ::= sr <type> <unqualified-name> # dependent name + // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + // ::= ds <expression> <expression> # expr.*expr + // ::= sZ <template-param> # size of a parameter pack + // ::= sZ <function-param> # size of a function parameter pack + // ::= <expr-primary> + // <expr-primary> ::= L <type> <value number> E # integer literal + // ::= L <type <value float> E # floating literal + // ::= L <mangled-name> E # external name + switch (E->getStmtClass()) { + case Expr::NoStmtClass: +#define ABSTRACT_STMT(Type) +#define EXPR(Type, Base) +#define STMT(Type, Base) \ + case Expr::Type##Class: +#include "clang/AST/StmtNodes.inc" + // fallthrough + + // These all can only appear in local or variable-initialization + // contexts and so should never appear in a mangling. + case Expr::AddrLabelExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::CXXThisExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::InitListExprClass: + case Expr::ParenListExprClass: + case Expr::CXXScalarValueInitExprClass: + llvm_unreachable("unexpected statement kind"); + break; + + // FIXME: invent manglings for all these. + case Expr::BlockExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::ChooseExprClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::GenericSelectionExprClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::OffsetOfExprClass: + case Expr::PredefinedExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::StmtExprClass: + case Expr::UnaryTypeTraitExprClass: + case Expr::BinaryTypeTraitExprClass: + case Expr::ArrayTypeTraitExprClass: + case Expr::ExpressionTraitExprClass: + case Expr::VAArgExprClass: + case Expr::CXXUuidofExprClass: + case Expr::CXXNoexceptExprClass: + case Expr::CUDAKernelCallExprClass: + case Expr::AsTypeExprClass: + { + // As bad as this diagnostic is, it's better than crashing. + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // Even gcc-4.5 doesn't mangle this. + case Expr::BinaryConditionalOperatorClass: { + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = + Diags.getCustomDiagID(Diagnostic::Error, + "?: operator with omitted middle operand cannot be mangled"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); + break; + } + + // These are used for internal purposes and cannot be meaningfully mangled. + case Expr::OpaqueValueExprClass: + llvm_unreachable("cannot mangle opaque value; mangling wrong thing?"); + + case Expr::CXXDefaultArgExprClass: + mangleExpression(cast<CXXDefaultArgExpr>(E)->getExpr(), Arity); + break; + + case Expr::CXXMemberCallExprClass: // fallthrough + case Expr::CallExprClass: { + const CallExpr *CE = cast<CallExpr>(E); + + // <expression> ::= cp <simple-id> <expression>* E + // We use this mangling only when the call would use ADL except + // for being parenthesized. Per discussion with David + // Vandervoorde, 2011.04.25. + if (isParenthesizedADLCallee(CE)) { + Out << "cp"; + // The callee here is a parenthesized UnresolvedLookupExpr with + // no qualifier and should always get mangled as a <simple-id> + // anyway. + + // <expression> ::= cl <expression>* E + } else { + Out << "cl"; + } + + mangleExpression(CE->getCallee(), CE->getNumArgs()); + for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) + mangleExpression(CE->getArg(I)); + Out << 'E'; + break; + } + + case Expr::CXXNewExprClass: { + // Proposal from David Vandervoorde, 2010.06.30 + const CXXNewExpr *New = cast<CXXNewExpr>(E); + if (New->isGlobalNew()) Out << "gs"; + Out << (New->isArray() ? "na" : "nw"); + for (CXXNewExpr::const_arg_iterator I = New->placement_arg_begin(), + E = New->placement_arg_end(); I != E; ++I) + mangleExpression(*I); + Out << '_'; + mangleType(New->getAllocatedType()); + if (New->hasInitializer()) { + Out << "pi"; + for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(), + E = New->constructor_arg_end(); I != E; ++I) + mangleExpression(*I); + } + Out << 'E'; + break; + } + + case Expr::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), 0, ME->getMemberDecl()->getDeclName(), + Arity); + break; + } + + case Expr::UnresolvedMemberExprClass: { + const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), 0, ME->getMemberName(), + Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXDependentScopeMemberExprClass: { + const CXXDependentScopeMemberExpr *ME + = cast<CXXDependentScopeMemberExpr>(E); + mangleMemberExpr(ME->getBase(), ME->isArrow(), + ME->getQualifier(), ME->getFirstQualifierFoundInScope(), + ME->getMember(), Arity); + if (ME->hasExplicitTemplateArgs()) + mangleTemplateArgs(ME->getExplicitTemplateArgs()); + break; + } + + case Expr::UnresolvedLookupExprClass: { + const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); + mangleUnresolvedName(ULE->getQualifier(), 0, ULE->getName(), Arity); + if (ULE->hasExplicitTemplateArgs()) + mangleTemplateArgs(ULE->getExplicitTemplateArgs()); + break; + } + + case Expr::CXXUnresolvedConstructExprClass: { + const CXXUnresolvedConstructExpr *CE = cast<CXXUnresolvedConstructExpr>(E); + unsigned N = CE->arg_size(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXConstructExprClass: { + const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); + unsigned N = CE->getNumArgs(); + + Out << "cv"; + mangleType(CE->getType()); + if (N != 1) Out << '_'; + for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); + if (N != 1) Out << 'E'; + break; + } + + case Expr::UnaryExprOrTypeTraitExprClass: { + const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); + switch(SAE->getKind()) { + case UETT_SizeOf: + Out << 's'; + break; + case UETT_AlignOf: + Out << 'a'; + break; + case UETT_VecStep: + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot yet mangle vec_step expression"); + Diags.Report(DiagID); + return; + } + if (SAE->isArgumentType()) { + Out << 't'; + mangleType(SAE->getArgumentType()); + } else { + Out << 'z'; + mangleExpression(SAE->getArgumentExpr()); + } + break; + } + + case Expr::CXXThrowExprClass: { + const CXXThrowExpr *TE = cast<CXXThrowExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TE->getSubExpr()) { + Out << "tw"; + mangleExpression(TE->getSubExpr()); + } else { + Out << "tr"; + } + break; + } + + case Expr::CXXTypeidExprClass: { + const CXXTypeidExpr *TIE = cast<CXXTypeidExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (TIE->isTypeOperand()) { + Out << "ti"; + mangleType(TIE->getTypeOperand()); + } else { + Out << "te"; + mangleExpression(TIE->getExprOperand()); + } + break; + } + + case Expr::CXXDeleteExprClass: { + const CXXDeleteExpr *DE = cast<CXXDeleteExpr>(E); + + // Proposal from David Vandervoorde, 2010.06.30 + if (DE->isGlobalDelete()) Out << "gs"; + Out << (DE->isArrayForm() ? "da" : "dl"); + mangleExpression(DE->getArgument()); + break; + } + + case Expr::UnaryOperatorClass: { + const UnaryOperator *UO = cast<UnaryOperator>(E); + mangleOperatorName(UnaryOperator::getOverloadedOperator(UO->getOpcode()), + /*Arity=*/1); + mangleExpression(UO->getSubExpr()); + break; + } + + case Expr::ArraySubscriptExprClass: { + const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(E); + + // Array subscript is treated as a syntactically weird form of + // binary operator. + Out << "ix"; + mangleExpression(AE->getLHS()); + mangleExpression(AE->getRHS()); + break; + } + + case Expr::CompoundAssignOperatorClass: // fallthrough + case Expr::BinaryOperatorClass: { + const BinaryOperator *BO = cast<BinaryOperator>(E); + if (BO->getOpcode() == BO_PtrMemD) + Out << "ds"; + else + mangleOperatorName(BinaryOperator::getOverloadedOperator(BO->getOpcode()), + /*Arity=*/2); + mangleExpression(BO->getLHS()); + mangleExpression(BO->getRHS()); + break; + } + + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *CO = cast<ConditionalOperator>(E); + mangleOperatorName(OO_Conditional, /*Arity=*/3); + mangleExpression(CO->getCond()); + mangleExpression(CO->getLHS(), Arity); + mangleExpression(CO->getRHS(), Arity); + break; + } + + case Expr::ImplicitCastExprClass: { + mangleExpression(cast<ImplicitCastExpr>(E)->getSubExpr(), Arity); + break; + } + + case Expr::CStyleCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXFunctionalCastExprClass: { + const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); + Out << "cv"; + mangleType(ECE->getType()); + mangleExpression(ECE->getSubExpr()); + break; + } + + case Expr::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); + unsigned NumArgs = CE->getNumArgs(); + mangleOperatorName(CE->getOperator(), /*Arity=*/NumArgs); + // Mangle the arguments. + for (unsigned i = 0; i != NumArgs; ++i) + mangleExpression(CE->getArg(i)); + break; + } + + case Expr::ParenExprClass: + mangleExpression(cast<ParenExpr>(E)->getSubExpr(), Arity); + break; + + case Expr::DeclRefExprClass: { + const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl(); + + switch (D->getKind()) { + default: + // <expr-primary> ::= L <mangled-name> E # external name + Out << 'L'; + mangle(D, "_Z"); + Out << 'E'; + break; + + case Decl::ParmVar: + mangleFunctionParam(cast<ParmVarDecl>(D)); + break; + + case Decl::EnumConstant: { + const EnumConstantDecl *ED = cast<EnumConstantDecl>(D); + mangleIntegerLiteral(ED->getType(), ED->getInitVal()); + break; + } + + case Decl::NonTypeTemplateParm: { + const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D); + mangleTemplateParameter(PD->getIndex()); + break; + } + + } + + break; + } + + case Expr::SubstNonTypeTemplateParmPackExprClass: + mangleTemplateParameter( + cast<SubstNonTypeTemplateParmPackExpr>(E)->getParameterPack()->getIndex()); + break; + + case Expr::DependentScopeDeclRefExprClass: { + const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); + NestedNameSpecifier *NNS = DRE->getQualifier(); + const Type *QTy = NNS->getAsType(); + + // When we're dealing with a nested-name-specifier that has just a + // dependent identifier in it, mangle that as a typename. FIXME: + // It isn't clear that we ever actually want to have such a + // nested-name-specifier; why not just represent it as a typename type? + if (!QTy && NNS->getAsIdentifier() && NNS->getPrefix()) { + QTy = getASTContext().getDependentNameType(ETK_Typename, + NNS->getPrefix(), + NNS->getAsIdentifier()) + .getTypePtr(); + } + assert(QTy && "Qualifier was not type!"); + + // ::= sr <type> <unqualified-name> # dependent name + // ::= sr <type> <unqualified-name> <template-args> # dependent template-id + Out << "sr"; + mangleType(QualType(QTy, 0)); + mangleUnqualifiedName(0, DRE->getDeclName(), Arity); + if (DRE->hasExplicitTemplateArgs()) + mangleTemplateArgs(DRE->getExplicitTemplateArgs()); + + break; + } + + case Expr::CXXBindTemporaryExprClass: + mangleExpression(cast<CXXBindTemporaryExpr>(E)->getSubExpr()); + break; + + case Expr::ExprWithCleanupsClass: + mangleExpression(cast<ExprWithCleanups>(E)->getSubExpr(), Arity); + break; + + case Expr::FloatingLiteralClass: { + const FloatingLiteral *FL = cast<FloatingLiteral>(E); + Out << 'L'; + mangleType(FL->getType()); + mangleFloat(FL->getValue()); + Out << 'E'; + break; + } + + case Expr::CharacterLiteralClass: + Out << 'L'; + mangleType(E->getType()); + Out << cast<CharacterLiteral>(E)->getValue(); + Out << 'E'; + break; + + case Expr::CXXBoolLiteralExprClass: + Out << "Lb"; + Out << (cast<CXXBoolLiteralExpr>(E)->getValue() ? '1' : '0'); + Out << 'E'; + break; + + case Expr::IntegerLiteralClass: { + llvm::APSInt Value(cast<IntegerLiteral>(E)->getValue()); + if (E->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleIntegerLiteral(E->getType(), Value); + break; + } + + case Expr::ImaginaryLiteralClass: { + const ImaginaryLiteral *IE = cast<ImaginaryLiteral>(E); + // Mangle as if a complex literal. + // Proposal from David Vandevoorde, 2010.06.30. + Out << 'L'; + mangleType(E->getType()); + if (const FloatingLiteral *Imag = + dyn_cast<FloatingLiteral>(IE->getSubExpr())) { + // Mangle a floating-point zero of the appropriate type. + mangleFloat(llvm::APFloat(Imag->getValue().getSemantics())); + Out << '_'; + mangleFloat(Imag->getValue()); + } else { + Out << "0_"; + llvm::APSInt Value(cast<IntegerLiteral>(IE->getSubExpr())->getValue()); + if (IE->getSubExpr()->getType()->isSignedIntegerType()) + Value.setIsSigned(true); + mangleNumber(Value); + } + Out << 'E'; + break; + } + + case Expr::StringLiteralClass: { + // Revised proposal from David Vandervoorde, 2010.07.15. + Out << 'L'; + assert(isa<ConstantArrayType>(E->getType())); + mangleType(E->getType()); + Out << 'E'; + break; + } + + case Expr::GNUNullExprClass: + // FIXME: should this really be mangled the same as nullptr? + // fallthrough + + case Expr::CXXNullPtrLiteralExprClass: { + // Proposal from David Vandervoorde, 2010.06.30, as + // modified by ABI list discussion. + Out << "LDnE"; + break; + } + + case Expr::PackExpansionExprClass: + Out << "sp"; + mangleExpression(cast<PackExpansionExpr>(E)->getPattern()); + break; + + case Expr::SizeOfPackExprClass: { + Out << "sZ"; + const NamedDecl *Pack = cast<SizeOfPackExpr>(E)->getPack(); + if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack)) + mangleTemplateParameter(TTP->getIndex()); + else if (const NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Pack)) + mangleTemplateParameter(NTTP->getIndex()); + else if (const TemplateTemplateParmDecl *TempTP + = dyn_cast<TemplateTemplateParmDecl>(Pack)) + mangleTemplateParameter(TempTP->getIndex()); + else { + // Note: proposed by Mike Herrick on 11/30/10 + // <expression> ::= sZ <function-param> # size of function parameter pack + Diagnostic &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, + "cannot mangle sizeof...(function parameter pack)"); + Diags.Report(DiagID); + return; + } + break; + } + } +} + +/// Mangle an expression which refers to a parameter variable. +/// +/// <expression> ::= <function-param> +/// <function-param> ::= fp <top-level CV-qualifiers> _ # L == 0, I == 0 +/// <function-param> ::= fp <top-level CV-qualifiers> +/// <parameter-2 non-negative number> _ # L == 0, I > 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> _ # L > 0, I == 0 +/// <function-param> ::= fL <L-1 non-negative number> +/// p <top-level CV-qualifiers> +/// <I-1 non-negative number> _ # L > 0, I > 0 +/// +/// L is the nesting depth of the parameter, defined as 1 if the +/// parameter comes from the innermost function prototype scope +/// enclosing the current context, 2 if from the next enclosing +/// function prototype scope, and so on, with one special case: if +/// we've processed the full parameter clause for the innermost +/// function type, then L is one less. This definition conveniently +/// makes it irrelevant whether a function's result type was written +/// trailing or leading, but is otherwise overly complicated; the +/// numbering was first designed without considering references to +/// parameter in locations other than return types, and then the +/// mangling had to be generalized without changing the existing +/// manglings. +/// +/// I is the zero-based index of the parameter within its parameter +/// declaration clause. Note that the original ABI document describes +/// this using 1-based ordinals. +void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { + unsigned parmDepth = parm->getFunctionScopeDepth(); + unsigned parmIndex = parm->getFunctionScopeIndex(); + + // Compute 'L'. + // parmDepth does not include the declaring function prototype. + // FunctionTypeDepth does account for that. + assert(parmDepth < FunctionTypeDepth.getDepth()); + unsigned nestingDepth = FunctionTypeDepth.getDepth() - parmDepth; + if (FunctionTypeDepth.isInResultType()) + nestingDepth--; + + if (nestingDepth == 0) { + Out << "fp"; + } else { + Out << "fL" << (nestingDepth - 1) << 'p'; + } + + // Top-level qualifiers. We don't have to worry about arrays here, + // because parameters declared as arrays should already have been + // tranformed to have pointer type. FIXME: apparently these don't + // get mangled if used as an rvalue of a known non-class type? + assert(!parm->getType()->isArrayType() + && "parameter's type is still an array type?"); + mangleQualifiers(parm->getType().getQualifiers()); + + // Parameter index. + if (parmIndex != 0) { + Out << (parmIndex - 1); + } + Out << '_'; +} + +void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { + // <ctor-dtor-name> ::= C1 # complete object constructor + // ::= C2 # base object constructor + // ::= C3 # complete object allocating constructor + // + switch (T) { + case Ctor_Complete: + Out << "C1"; + break; + case Ctor_Base: + Out << "C2"; + break; + case Ctor_CompleteAllocating: + Out << "C3"; + break; + } +} + +void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { + // <ctor-dtor-name> ::= D0 # deleting destructor + // ::= D1 # complete object destructor + // ::= D2 # base object destructor + // + switch (T) { + case Dtor_Deleting: + Out << "D0"; + break; + case Dtor_Complete: + Out << "D1"; + break; + case Dtor_Base: + Out << "D2"; + break; + } +} + +void CXXNameMangler::mangleTemplateArgs( + const ExplicitTemplateArgumentList &TemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) + mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument()); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(TemplateName Template, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, + NumTemplateArgs); + + mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs); +} + +void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args, + unsigned numArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != numArgs; ++i) + mangleTemplateArg(0, args[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgumentList &AL) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0, e = AL.size(); i != e; ++i) + mangleTemplateArg(PL.getParam(i), AL[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs) { + // <template-args> ::= I <template-arg>+ E + Out << 'I'; + for (unsigned i = 0; i != NumTemplateArgs; ++i) + mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); + Out << 'E'; +} + +void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, + const TemplateArgument &A) { + // <template-arg> ::= <type> # type or template + // ::= X <expression> E # expression + // ::= <expr-primary> # simple expressions + // ::= J <template-arg>* E # argument pack + // ::= sp <expression> # pack expansion of (C++0x) + switch (A.getKind()) { + case TemplateArgument::Null: + llvm_unreachable("Cannot mangle NULL template argument"); + + case TemplateArgument::Type: + mangleType(A.getAsType()); + break; + case TemplateArgument::Template: + // This is mangled as <type>. + mangleType(A.getAsTemplate()); + break; + case TemplateArgument::TemplateExpansion: + // <type> ::= Dp <type> # pack expansion (C++0x) + Out << "Dp"; + mangleType(A.getAsTemplateOrTemplatePattern()); + break; + case TemplateArgument::Expression: + Out << 'X'; + mangleExpression(A.getAsExpr()); + Out << 'E'; + break; + case TemplateArgument::Integral: + mangleIntegerLiteral(A.getIntegralType(), *A.getAsIntegral()); + break; + case TemplateArgument::Declaration: { + assert(P && "Missing template parameter for declaration argument"); + // <expr-primary> ::= L <mangled-name> E # external name + + // Clang produces AST's where pointer-to-member-function expressions + // and pointer-to-function expressions are represented as a declaration not + // an expression. We compensate for it here to produce the correct mangling. + NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); + const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); + bool compensateMangling = !Parameter->getType()->isReferenceType(); + if (compensateMangling) { + Out << 'X'; + mangleOperatorName(OO_Amp, 1); + } + + Out << 'L'; + // References to external entities use the mangled name; if the name would + // not normally be manged then mangle it as unqualified. + // + // FIXME: The ABI specifies that external names here should have _Z, but + // gcc leaves this off. + if (compensateMangling) + mangle(D, "_Z"); + else + mangle(D, "Z"); + Out << 'E'; + + if (compensateMangling) + Out << 'E'; + + break; + } + + case TemplateArgument::Pack: { + // Note: proposal by Mike Herrick on 12/20/10 + Out << 'J'; + for (TemplateArgument::pack_iterator PA = A.pack_begin(), + PAEnd = A.pack_end(); + PA != PAEnd; ++PA) + mangleTemplateArg(P, *PA); + Out << 'E'; + } + } +} + +void CXXNameMangler::mangleTemplateParameter(unsigned Index) { + // <template-param> ::= T_ # first template parameter + // ::= T <parameter-2 non-negative number> _ + if (Index == 0) + Out << "T_"; + else + Out << 'T' << (Index - 1) << '_'; +} + +// <substitution> ::= S <seq-id> _ +// ::= S_ +bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { + // Try one of the standard substitutions first. + if (mangleStandardSubstitution(ND)) + return true; + + ND = cast<NamedDecl>(ND->getCanonicalDecl()); + return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); +} + +bool CXXNameMangler::mangleSubstitution(QualType T) { + if (!T.getCVRQualifiers()) { + if (const RecordType *RT = T->getAs<RecordType>()) + return mangleSubstitution(RT->getDecl()); + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + + return mangleSubstitution(TypePtr); +} + +bool CXXNameMangler::mangleSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return mangleSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + return mangleSubstitution( + reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +bool CXXNameMangler::mangleSubstitution(uintptr_t Ptr) { + llvm::DenseMap<uintptr_t, unsigned>::iterator I = Substitutions.find(Ptr); + if (I == Substitutions.end()) + return false; + + unsigned SeqID = I->second; + if (SeqID == 0) + Out << "S_"; + else { + SeqID--; + + // <seq-id> is encoded in base-36, using digits and upper case letters. + char Buffer[10]; + char *BufferPtr = llvm::array_endof(Buffer); + + if (SeqID == 0) *--BufferPtr = '0'; + + while (SeqID) { + assert(BufferPtr > Buffer && "Buffer overflow!"); + + char c = static_cast<char>(SeqID % 36); + + *--BufferPtr = (c < 10 ? '0' + c : 'A' + c - 10); + SeqID /= 36; + } + + Out << 'S' + << llvm::StringRef(BufferPtr, llvm::array_endof(Buffer)-BufferPtr) + << '_'; + } + + return true; +} + +static bool isCharType(QualType T) { + if (T.isNull()) + return false; + + return T->isSpecificBuiltinType(BuiltinType::Char_S) || + T->isSpecificBuiltinType(BuiltinType::Char_U); +} + +/// isCharSpecialization - Returns whether a given type is a template +/// specialization of a given name with a single argument of type char. +static bool isCharSpecialization(QualType T, const char *Name) { + if (T.isNull()) + return false; + + const RecordType *RT = T->getAs<RecordType>(); + if (!RT) + return false; + + const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(RT->getDecl()); + if (!SD) + return false; + + if (!isStdNamespace(SD->getDeclContext())) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 1) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + return SD->getIdentifier()->getName() == Name; +} + +template <std::size_t StrLen> +static bool isStreamCharSpecialization(const ClassTemplateSpecializationDecl*SD, + const char (&Str)[StrLen]) { + if (!SD->getIdentifier()->isStr(Str)) + return false; + + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + if (TemplateArgs.size() != 2) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + return true; +} + +bool CXXNameMangler::mangleStandardSubstitution(const NamedDecl *ND) { + // <substitution> ::= St # ::std:: + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (isStd(NS)) { + Out << "St"; + return true; + } + } + + if (const ClassTemplateDecl *TD = dyn_cast<ClassTemplateDecl>(ND)) { + if (!isStdNamespace(TD->getDeclContext())) + return false; + + // <substitution> ::= Sa # ::std::allocator + if (TD->getIdentifier()->isStr("allocator")) { + Out << "Sa"; + return true; + } + + // <<substitution> ::= Sb # ::std::basic_string + if (TD->getIdentifier()->isStr("basic_string")) { + Out << "Sb"; + return true; + } + } + + if (const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(ND)) { + if (!isStdNamespace(SD->getDeclContext())) + return false; + + // <substitution> ::= Ss # ::std::basic_string<char, + // ::std::char_traits<char>, + // ::std::allocator<char> > + if (SD->getIdentifier()->isStr("basic_string")) { + const TemplateArgumentList &TemplateArgs = SD->getTemplateArgs(); + + if (TemplateArgs.size() != 3) + return false; + + if (!isCharType(TemplateArgs[0].getAsType())) + return false; + + if (!isCharSpecialization(TemplateArgs[1].getAsType(), "char_traits")) + return false; + + if (!isCharSpecialization(TemplateArgs[2].getAsType(), "allocator")) + return false; + + Out << "Ss"; + return true; + } + + // <substitution> ::= Si # ::std::basic_istream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_istream")) { + Out << "Si"; + return true; + } + + // <substitution> ::= So # ::std::basic_ostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_ostream")) { + Out << "So"; + return true; + } + + // <substitution> ::= Sd # ::std::basic_iostream<char, + // ::std::char_traits<char> > + if (isStreamCharSpecialization(SD, "basic_iostream")) { + Out << "Sd"; + return true; + } + } + return false; +} + +void CXXNameMangler::addSubstitution(QualType T) { + if (!T.getCVRQualifiers()) { + if (const RecordType *RT = T->getAs<RecordType>()) { + addSubstitution(RT->getDecl()); + return; + } + } + + uintptr_t TypePtr = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr()); + addSubstitution(TypePtr); +} + +void CXXNameMangler::addSubstitution(TemplateName Template) { + if (TemplateDecl *TD = Template.getAsTemplateDecl()) + return addSubstitution(TD); + + Template = Context.getASTContext().getCanonicalTemplateName(Template); + addSubstitution(reinterpret_cast<uintptr_t>(Template.getAsVoidPointer())); +} + +void CXXNameMangler::addSubstitution(uintptr_t Ptr) { + assert(!Substitutions.count(Ptr) && "Substitution already exists!"); + Substitutions[Ptr] = SeqID++; +} + +// + +/// \brief Mangles the name of the declaration D and emits that name to the +/// given output stream. +/// +/// If the declaration D requires a mangled name, this routine will emit that +/// mangled name to \p os and return true. Otherwise, \p os will be unchanged +/// and this routine will return false. In this case, the caller should just +/// emit the identifier of the declaration (\c D->getIdentifier()) as its +/// name. +void ItaniumMangleContext::mangleName(const NamedDecl *D, + llvm::raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + CXXNameMangler Mangler(*this, Out, D); + return Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + llvm::raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + llvm::raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Type); + Mangler.mangle(D); +} + +void ItaniumMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + // <special-name> ::= Tc <call-offset> <call-offset> <base encoding> + // # base is the nominal target function of thunk + // # first call-offset is 'this' adjustment + // # second call-offset is result adjustment + + assert(!isa<CXXDestructorDecl>(MD) && + "Use mangleCXXDtor for destructor decls!"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZT"; + if (!Thunk.Return.isEmpty()) + Mangler.getStream() << 'c'; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(Thunk.This.NonVirtual, Thunk.This.VCallOffsetOffset); + + // Mangle the return pointer adjustment if there is one. + if (!Thunk.Return.isEmpty()) + Mangler.mangleCallOffset(Thunk.Return.NonVirtual, + Thunk.Return.VBaseOffsetOffset); + + Mangler.mangleFunctionEncoding(MD); +} + +void +ItaniumMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &Out) { + // <special-name> ::= T <call-offset> <base encoding> + // # base is the nominal target function of thunk + CXXNameMangler Mangler(*this, Out, DD, Type); + Mangler.getStream() << "_ZT"; + + // Mangle the 'this' pointer adjustment. + Mangler.mangleCallOffset(ThisAdjustment.NonVirtual, + ThisAdjustment.VCallOffsetOffset); + + Mangler.mangleFunctionEncoding(DD); +} + +/// mangleGuardVariable - Returns the mangled name for a guard variable +/// for the passed in VarDecl. +void ItaniumMangleContext::mangleItaniumGuardVariable(const VarDecl *D, + llvm::raw_ostream &Out) { + // <special-name> ::= GV <object name> # Guard variable for one-time + // # initialization + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGV"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleReferenceTemporary(const VarDecl *D, + llvm::raw_ostream &Out) { + // We match the GCC mangling here. + // <special-name> ::= GR <object name> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZGR"; + Mangler.mangleName(D); +} + +void ItaniumMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &Out) { + // <special-name> ::= TV <type> # virtual table + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTV"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &Out) { + // <special-name> ::= TT <type> # VTT structure + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTT"; + Mangler.mangleNameOrStandardSubstitution(RD); +} + +void ItaniumMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &Out) { + // <special-name> ::= TC <type> <offset number> _ <base type> + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTC"; + Mangler.mangleNameOrStandardSubstitution(RD); + Mangler.getStream() << Offset; + Mangler.getStream() << '_'; + Mangler.mangleNameOrStandardSubstitution(Type); +} + +void ItaniumMangleContext::mangleCXXRTTI(QualType Ty, + llvm::raw_ostream &Out) { + // <special-name> ::= TI <type> # typeinfo structure + assert(!Ty.hasQualifiers() && "RTTI info cannot have top-level qualifiers"); + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTI"; + Mangler.mangleType(Ty); +} + +void ItaniumMangleContext::mangleCXXRTTIName(QualType Ty, + llvm::raw_ostream &Out) { + // <special-name> ::= TS <type> # typeinfo name (null terminated byte string) + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_ZTS"; + Mangler.mangleType(Ty); +} + +MangleContext *clang::createItaniumMangleContext(ASTContext &Context, + Diagnostic &Diags) { + return new ItaniumMangleContext(Context, Diags); +} diff --git a/contrib/llvm/tools/clang/lib/AST/Mangle.cpp b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp new file mode 100644 index 000000000000..c3f3b11caccf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Mangle.cpp @@ -0,0 +1,140 @@ +//===--- Mangle.cpp - Mangle C++ Names --------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Implements generic name mangling support for blocks and Objective-C. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/ErrorHandling.h" + +#define MANGLE_CHECKER 0 + +#if MANGLE_CHECKER +#include <cxxabi.h> +#endif + +using namespace clang; + +// FIXME: For blocks we currently mimic GCC's mangling scheme, which leaves +// much to be desired. Come up with a better mangling scheme. + +namespace { + +static void mangleFunctionBlock(MangleContext &Context, + llvm::StringRef Outer, + const BlockDecl *BD, + llvm::raw_ostream &Out) { + Out << "__" << Outer << "_block_invoke_" << Context.getBlockId(BD, true); +} + +static void checkMangleDC(const DeclContext *DC, const BlockDecl *BD) { +#ifndef NDEBUG + const DeclContext *ExpectedDC = BD->getDeclContext(); + while (isa<BlockDecl>(ExpectedDC) || isa<EnumDecl>(ExpectedDC)) + ExpectedDC = ExpectedDC->getParent(); + // In-class initializers for non-static data members are lexically defined + // within the class, but are mangled as if they were specified as constructor + // member initializers. + if (isa<CXXRecordDecl>(ExpectedDC) && DC != ExpectedDC) + DC = DC->getParent(); + assert(DC == ExpectedDC && "Given decl context did not match expected!"); +#endif +} + +} + +void MangleContext::mangleGlobalBlock(const BlockDecl *BD, + llvm::raw_ostream &Out) { + Out << "__block_global_" << getBlockId(BD, false); +} + +void MangleContext::mangleCtorBlock(const CXXConstructorDecl *CD, + CXXCtorType CT, const BlockDecl *BD, + llvm::raw_ostream &ResStream) { + checkMangleDC(CD, BD); + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Out(Buffer); + mangleCXXCtor(CD, CT, Out); + Out.flush(); + mangleFunctionBlock(*this, Buffer, BD, ResStream); +} + +void MangleContext::mangleDtorBlock(const CXXDestructorDecl *DD, + CXXDtorType DT, const BlockDecl *BD, + llvm::raw_ostream &ResStream) { + checkMangleDC(DD, BD); + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Out(Buffer); + mangleCXXDtor(DD, DT, Out); + Out.flush(); + mangleFunctionBlock(*this, Buffer, BD, ResStream); +} + +void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, + llvm::raw_ostream &Out) { + assert(!isa<CXXConstructorDecl>(DC) && !isa<CXXDestructorDecl>(DC)); + checkMangleDC(DC, BD); + + llvm::SmallString<64> Buffer; + llvm::raw_svector_ostream Stream(Buffer); + if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) { + mangleObjCMethodName(Method, Stream); + } else { + const NamedDecl *ND = cast<NamedDecl>(DC); + if (IdentifierInfo *II = ND->getIdentifier()) + Stream << II->getName(); + else { + // FIXME: We were doing a mangleUnqualifiedName() before, but that's + // a private member of a class that will soon itself be private to the + // Itanium C++ ABI object. What should we do now? Right now, I'm just + // calling the mangleName() method on the MangleContext; is there a + // better way? + mangleName(ND, Stream); + } + } + Stream.flush(); + mangleFunctionBlock(*this, Buffer, BD, Out); +} + +void MangleContext::mangleObjCMethodName(const ObjCMethodDecl *MD, + llvm::raw_ostream &Out) { + llvm::SmallString<64> Name; + llvm::raw_svector_ostream OS(Name); + + const ObjCContainerDecl *CD = + dyn_cast<ObjCContainerDecl>(MD->getDeclContext()); + assert (CD && "Missing container decl in GetNameForMethod"); + OS << (MD->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); + if (const ObjCCategoryImplDecl *CID = dyn_cast<ObjCCategoryImplDecl>(CD)) + OS << '(' << CID << ')'; + OS << ' ' << MD->getSelector().getAsString() << ']'; + + Out << OS.str().size() << OS.str(); +} + +void MangleContext::mangleBlock(const BlockDecl *BD, + llvm::raw_ostream &Out) { + const DeclContext *DC = BD->getDeclContext(); + while (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) + DC = DC->getParent(); + if (DC->isFunctionOrMethod()) + mangleBlock(DC, BD, Out); + else + mangleGlobalBlock(BD, Out); +} diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp new file mode 100644 index 000000000000..206f6dd0c9eb --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftCXXABI.cpp @@ -0,0 +1,71 @@ +//===------- MicrosoftCXXABI.cpp - AST support for the Microsoft C++ ABI --===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ AST support targeting the Microsoft Visual C++ +// ABI. +// +//===----------------------------------------------------------------------===// + +#include "CXXABI.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/Type.h" +#include "clang/Basic/TargetInfo.h" + +using namespace clang; + +namespace { +class MicrosoftCXXABI : public CXXABI { + ASTContext &Context; +public: + MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } + + unsigned getMemberPointerSize(const MemberPointerType *MPT) const; + + CallingConv getDefaultMethodCallConv() const { + if (Context.Target.getTriple().getArch() == llvm::Triple::x86) + return CC_X86ThisCall; + else + return CC_C; + } + + bool isNearlyEmpty(const CXXRecordDecl *RD) const { + // FIXME: Audit the corners + if (!RD->isDynamicClass()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // In the Microsoft ABI, classes can have one or two vtable pointers. + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + return Layout.getNonVirtualSize() == PointerSize || + Layout.getNonVirtualSize() == PointerSize * 2; + } +}; +} + +unsigned MicrosoftCXXABI::getMemberPointerSize(const MemberPointerType *MPT) const { + QualType Pointee = MPT->getPointeeType(); + CXXRecordDecl *RD = MPT->getClass()->getAsCXXRecordDecl(); + if (RD->getNumVBases() > 0) { + if (Pointee->isFunctionType()) + return 3; + else + return 2; + } else if (RD->getNumBases() > 1 && Pointee->isFunctionType()) + return 2; + return 1; +} + +CXXABI *clang::CreateMicrosoftCXXABI(ASTContext &Ctx) { + return new MicrosoftCXXABI(Ctx); +} + diff --git a/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp new file mode 100644 index 000000000000..4f920f9aaca7 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/MicrosoftMangle.cpp @@ -0,0 +1,1189 @@ +//===--- MicrosoftMangle.cpp - Microsoft Visual C++ Name Mangling ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This provides C++ name mangling targeting the Microsoft Visual C++ ABI. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Mangle.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" +#include "clang/Basic/ABI.h" + +using namespace clang; + +namespace { + +/// MicrosoftCXXNameMangler - Manage the mangling of a single name for the +/// Microsoft Visual C++ ABI. +class MicrosoftCXXNameMangler { + MangleContext &Context; + llvm::raw_ostream &Out; + + ASTContext &getASTContext() const { return Context.getASTContext(); } + +public: + MicrosoftCXXNameMangler(MangleContext &C, llvm::raw_ostream &Out_) + : Context(C), Out(Out_) { } + + void mangle(const NamedDecl *D, llvm::StringRef Prefix = "?"); + void mangleName(const NamedDecl *ND); + void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleVariableEncoding(const VarDecl *VD); + void mangleNumber(int64_t Number); + void mangleType(QualType T); + +private: + void mangleUnqualifiedName(const NamedDecl *ND) { + mangleUnqualifiedName(ND, ND->getDeclName()); + } + void mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name); + void mangleSourceName(const IdentifierInfo *II); + void manglePostfix(const DeclContext *DC, bool NoFunction=false); + void mangleOperatorName(OverloadedOperatorKind OO); + void mangleQualifiers(Qualifiers Quals, bool IsMember); + + void mangleObjCMethodName(const ObjCMethodDecl *MD); + + // Declare manglers for every type class. +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T); +#include "clang/AST/TypeNodes.def" + + void mangleType(const TagType*); + void mangleType(const FunctionType *T, const FunctionDecl *D, + bool IsStructor, bool IsInstMethod); + void mangleType(const ArrayType *T, bool IsGlobal); + void mangleExtraDimensions(QualType T); + void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); + void mangleThrowSpecification(const FunctionProtoType *T); + +}; + +/// MicrosoftMangleContext - Overrides the default MangleContext for the +/// Microsoft Visual C++ ABI. +class MicrosoftMangleContext : public MangleContext { +public: + MicrosoftMangleContext(ASTContext &Context, + Diagnostic &Diags) : MangleContext(Context, Diags) { } + virtual bool shouldMangleDeclName(const NamedDecl *D); + virtual void mangleName(const NamedDecl *D, llvm::raw_ostream &Out); + virtual void mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &); + virtual void mangleCXXDtorThunk(const CXXDestructorDecl *DD, CXXDtorType Type, + const ThisAdjustment &ThisAdjustment, + llvm::raw_ostream &); + virtual void mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &); + virtual void mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &); + virtual void mangleCXXCtorVTable(const CXXRecordDecl *RD, int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &); + virtual void mangleCXXRTTI(QualType T, llvm::raw_ostream &); + virtual void mangleCXXRTTIName(QualType T, llvm::raw_ostream &); + virtual void mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, + llvm::raw_ostream &); + virtual void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, + llvm::raw_ostream &); + virtual void mangleReferenceTemporary(const clang::VarDecl *, + llvm::raw_ostream &); +}; + +} + +static bool isInCLinkageSpecification(const Decl *D) { + D = D->getCanonicalDecl(); + for (const DeclContext *DC = D->getDeclContext(); + !DC->isTranslationUnit(); DC = DC->getParent()) { + if (const LinkageSpecDecl *Linkage = dyn_cast<LinkageSpecDecl>(DC)) + return Linkage->getLanguage() == LinkageSpecDecl::lang_c; + } + + return false; +} + +bool MicrosoftMangleContext::shouldMangleDeclName(const NamedDecl *D) { + // In C, functions with no attributes never need to be mangled. Fastpath them. + if (!getASTContext().getLangOptions().CPlusPlus && !D->hasAttrs()) + return false; + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (D->hasAttr<AsmLabelAttr>()) + return true; + + // Clang's "overloadable" attribute extension to C/C++ implies name mangling + // (always) as does passing a C++ member function and a function + // whose name is not a simple identifier. + const FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (FD && (FD->hasAttr<OverloadableAttr>() || isa<CXXMethodDecl>(FD) || + !FD->getDeclName().isIdentifier())) + return true; + + // Otherwise, no mangling is done outside C++ mode. + if (!getASTContext().getLangOptions().CPlusPlus) + return false; + + // Variables at global scope with internal linkage are not mangled. + if (!FD) { + const DeclContext *DC = D->getDeclContext(); + if (DC->isTranslationUnit() && D->getLinkage() == InternalLinkage) + return false; + } + + // C functions and "main" are not mangled. + if ((FD && FD->isMain()) || isInCLinkageSpecification(D)) + return false; + + return true; +} + +void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, + llvm::StringRef Prefix) { + // MSVC doesn't mangle C++ names the same way it mangles extern "C" names. + // Therefore it's really important that we don't decorate the + // name with leading underscores or leading/trailing at signs. So, emit a + // asm marker at the start so we get the name right. + Out << '\01'; // LLVM IR Marker for __asm("foo") + + // Any decl can be declared with __asm("foo") on it, and this takes precedence + // over all other naming in the .o file. + if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { + // If we have an asm name, then we use it as the mangling. + Out << ALA->getLabel(); + return; + } + + // <mangled-name> ::= ? <name> <type-encoding> + Out << Prefix; + mangleName(D); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + mangleFunctionEncoding(FD); + else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) + mangleVariableEncoding(VD); + // TODO: Fields? Can MSVC even mangle them? +} + +void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { + // <type-encoding> ::= <function-class> <function-type> + + // Don't mangle in the type if this isn't a decl we should typically mangle. + if (!Context.shouldMangleDeclName(FD)) + return; + + // We should never ever see a FunctionNoProtoType at this point. + // We don't even know how to mangle their types anyway :). + const FunctionProtoType *FT = cast<FunctionProtoType>(FD->getType()); + + bool InStructor = false, InInstMethod = false; + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); + if (MD) { + if (MD->isInstance()) + InInstMethod = true; + if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + InStructor = true; + } + + // First, the function class. + mangleFunctionClass(FD); + + mangleType(FT, FD, InStructor, InInstMethod); +} + +void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { + // <type-encoding> ::= <storage-class> <variable-type> + // <storage-class> ::= 0 # private static member + // ::= 1 # protected static member + // ::= 2 # public static member + // ::= 3 # global + // ::= 4 # static local + + // The first character in the encoding (after the name) is the storage class. + if (VD->isStaticDataMember()) { + // If it's a static member, it also encodes the access level. + switch (VD->getAccess()) { + default: + case AS_private: Out << '0'; break; + case AS_protected: Out << '1'; break; + case AS_public: Out << '2'; break; + } + } + else if (!VD->isStaticLocal()) + Out << '3'; + else + Out << '4'; + // Now mangle the type. + // <variable-type> ::= <type> <cvr-qualifiers> + // ::= <type> A # pointers, references, arrays + // Pointers and references are odd. The type of 'int * const foo;' gets + // mangled as 'QAHA' instead of 'PAHB', for example. + QualType Ty = VD->getType(); + if (Ty->isPointerType() || Ty->isReferenceType()) { + mangleType(Ty); + Out << 'A'; + } else if (Ty->isArrayType()) { + // Global arrays are funny, too. + mangleType(cast<ArrayType>(Ty.getTypePtr()), true); + Out << 'A'; + } else { + mangleType(Ty.getLocalUnqualifiedType()); + mangleQualifiers(Ty.getLocalQualifiers(), false); + } +} + +void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { + // <name> ::= <unscoped-name> {[<named-scope>]+ | [<nested-name>]}? @ + const DeclContext *DC = ND->getDeclContext(); + + // Always start with the unqualified name. + mangleUnqualifiedName(ND); + + // If this is an extern variable declared locally, the relevant DeclContext + // is that of the containing namespace, or the translation unit. + if (isa<FunctionDecl>(DC) && ND->hasLinkage()) + while (!DC->isNamespace() && !DC->isTranslationUnit()) + DC = DC->getParent(); + + manglePostfix(DC); + + // Terminate the whole name with an '@'. + Out << '@'; +} + +void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { + // <number> ::= [?] <decimal digit> # <= 9 + // ::= [?] <hex digit>+ @ # > 9; A = 0, B = 1, etc... + if (Number < 0) { + Out << '?'; + Number = -Number; + } + if (Number >= 1 && Number <= 10) { + Out << Number-1; + } else { + // We have to build up the encoding in reverse order, so it will come + // out right when we write it out. + char Encoding[16]; + char *EndPtr = Encoding+sizeof(Encoding); + char *CurPtr = EndPtr; + while (Number) { + *--CurPtr = 'A' + (Number % 16); + Number /= 16; + } + Out.write(CurPtr, EndPtr-CurPtr); + Out << '@'; + } +} + +void +MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, + DeclarationName Name) { + // <unqualified-name> ::= <operator-name> + // ::= <ctor-dtor-name> + // ::= <source-name> + switch (Name.getNameKind()) { + case DeclarationName::Identifier: { + if (const IdentifierInfo *II = Name.getAsIdentifierInfo()) { + mangleSourceName(II); + break; + } + + // Otherwise, an anonymous entity. We must have a declaration. + assert(ND && "mangling empty name without declaration"); + + if (const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(ND)) { + if (NS->isAnonymousNamespace()) { + Out << "?A"; + break; + } + } + + // We must have an anonymous struct. + const TagDecl *TD = cast<TagDecl>(ND); + if (const TypedefNameDecl *D = TD->getTypedefNameForAnonDecl()) { + assert(TD->getDeclContext() == D->getDeclContext() && + "Typedef should not be in another decl context!"); + assert(D->getDeclName().getAsIdentifierInfo() && + "Typedef was not named!"); + mangleSourceName(D->getDeclName().getAsIdentifierInfo()); + break; + } + + // When VC encounters an anonymous type with no tag and no typedef, + // it literally emits '<unnamed-tag>'. + Out << "<unnamed-tag>"; + break; + } + + case DeclarationName::ObjCZeroArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCMultiArgSelector: + assert(false && "Can't mangle Objective-C selector names here!"); + break; + + case DeclarationName::CXXConstructorName: + assert(false && "Can't mangle constructors yet!"); + break; + + case DeclarationName::CXXDestructorName: + assert(false && "Can't mangle destructors yet!"); + break; + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= ?B # (cast) + // The target type is encoded as the return type. + Out << "?B"; + break; + + case DeclarationName::CXXOperatorName: + mangleOperatorName(Name.getCXXOverloadedOperator()); + break; + + case DeclarationName::CXXLiteralOperatorName: + // FIXME: Was this added in VS2010? Does MS even know how to mangle this? + assert(false && "Don't know how to mangle literal operators yet!"); + break; + + case DeclarationName::CXXUsingDirective: + assert(false && "Can't mangle a using directive name!"); + break; + } +} + +void MicrosoftCXXNameMangler::manglePostfix(const DeclContext *DC, + bool NoFunction) { + // <postfix> ::= <unqualified-name> [<postfix>] + // ::= <template-postfix> <template-args> [<postfix>] + // ::= <template-param> + // ::= <substitution> [<postfix>] + + if (!DC) return; + + while (isa<LinkageSpecDecl>(DC)) + DC = DC->getParent(); + + if (DC->isTranslationUnit()) + return; + + if (const BlockDecl *BD = dyn_cast<BlockDecl>(DC)) { + Context.mangleBlock(BD, Out); + Out << '@'; + return manglePostfix(DC->getParent(), NoFunction); + } + + if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC))) + return; + else if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) + mangleObjCMethodName(Method); + else { + mangleUnqualifiedName(cast<NamedDecl>(DC)); + manglePostfix(DC->getParent(), NoFunction); + } +} + +void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO) { + switch (OO) { + // ?0 # constructor + // ?1 # destructor + // <operator-name> ::= ?2 # new + case OO_New: Out << "?2"; break; + // <operator-name> ::= ?3 # delete + case OO_Delete: Out << "?3"; break; + // <operator-name> ::= ?4 # = + case OO_Equal: Out << "?4"; break; + // <operator-name> ::= ?5 # >> + case OO_GreaterGreater: Out << "?5"; break; + // <operator-name> ::= ?6 # << + case OO_LessLess: Out << "?6"; break; + // <operator-name> ::= ?7 # ! + case OO_Exclaim: Out << "?7"; break; + // <operator-name> ::= ?8 # == + case OO_EqualEqual: Out << "?8"; break; + // <operator-name> ::= ?9 # != + case OO_ExclaimEqual: Out << "?9"; break; + // <operator-name> ::= ?A # [] + case OO_Subscript: Out << "?A"; break; + // ?B # conversion + // <operator-name> ::= ?C # -> + case OO_Arrow: Out << "?C"; break; + // <operator-name> ::= ?D # * + case OO_Star: Out << "?D"; break; + // <operator-name> ::= ?E # ++ + case OO_PlusPlus: Out << "?E"; break; + // <operator-name> ::= ?F # -- + case OO_MinusMinus: Out << "?F"; break; + // <operator-name> ::= ?G # - + case OO_Minus: Out << "?G"; break; + // <operator-name> ::= ?H # + + case OO_Plus: Out << "?H"; break; + // <operator-name> ::= ?I # & + case OO_Amp: Out << "?I"; break; + // <operator-name> ::= ?J # ->* + case OO_ArrowStar: Out << "?J"; break; + // <operator-name> ::= ?K # / + case OO_Slash: Out << "?K"; break; + // <operator-name> ::= ?L # % + case OO_Percent: Out << "?L"; break; + // <operator-name> ::= ?M # < + case OO_Less: Out << "?M"; break; + // <operator-name> ::= ?N # <= + case OO_LessEqual: Out << "?N"; break; + // <operator-name> ::= ?O # > + case OO_Greater: Out << "?O"; break; + // <operator-name> ::= ?P # >= + case OO_GreaterEqual: Out << "?P"; break; + // <operator-name> ::= ?Q # , + case OO_Comma: Out << "?Q"; break; + // <operator-name> ::= ?R # () + case OO_Call: Out << "?R"; break; + // <operator-name> ::= ?S # ~ + case OO_Tilde: Out << "?S"; break; + // <operator-name> ::= ?T # ^ + case OO_Caret: Out << "?T"; break; + // <operator-name> ::= ?U # | + case OO_Pipe: Out << "?U"; break; + // <operator-name> ::= ?V # && + case OO_AmpAmp: Out << "?V"; break; + // <operator-name> ::= ?W # || + case OO_PipePipe: Out << "?W"; break; + // <operator-name> ::= ?X # *= + case OO_StarEqual: Out << "?X"; break; + // <operator-name> ::= ?Y # += + case OO_PlusEqual: Out << "?Y"; break; + // <operator-name> ::= ?Z # -= + case OO_MinusEqual: Out << "?Z"; break; + // <operator-name> ::= ?_0 # /= + case OO_SlashEqual: Out << "?_0"; break; + // <operator-name> ::= ?_1 # %= + case OO_PercentEqual: Out << "?_1"; break; + // <operator-name> ::= ?_2 # >>= + case OO_GreaterGreaterEqual: Out << "?_2"; break; + // <operator-name> ::= ?_3 # <<= + case OO_LessLessEqual: Out << "?_3"; break; + // <operator-name> ::= ?_4 # &= + case OO_AmpEqual: Out << "?_4"; break; + // <operator-name> ::= ?_5 # |= + case OO_PipeEqual: Out << "?_5"; break; + // <operator-name> ::= ?_6 # ^= + case OO_CaretEqual: Out << "?_6"; break; + // ?_7 # vftable + // ?_8 # vbtable + // ?_9 # vcall + // ?_A # typeof + // ?_B # local static guard + // ?_C # string + // ?_D # vbase destructor + // ?_E # vector deleting destructor + // ?_F # default constructor closure + // ?_G # scalar deleting destructor + // ?_H # vector constructor iterator + // ?_I # vector destructor iterator + // ?_J # vector vbase constructor iterator + // ?_K # virtual displacement map + // ?_L # eh vector constructor iterator + // ?_M # eh vector destructor iterator + // ?_N # eh vector vbase constructor iterator + // ?_O # copy constructor closure + // ?_P<name> # udt returning <name> + // ?_Q # <unknown> + // ?_R0 # RTTI Type Descriptor + // ?_R1 # RTTI Base Class Descriptor at (a,b,c,d) + // ?_R2 # RTTI Base Class Array + // ?_R3 # RTTI Class Hierarchy Descriptor + // ?_R4 # RTTI Complete Object Locator + // ?_S # local vftable + // ?_T # local vftable constructor closure + // <operator-name> ::= ?_U # new[] + case OO_Array_New: Out << "?_U"; break; + // <operator-name> ::= ?_V # delete[] + case OO_Array_Delete: Out << "?_V"; break; + + case OO_Conditional: + assert(false && "Don't know how to mangle ?:"); + break; + + case OO_None: + case NUM_OVERLOADED_OPERATORS: + assert(false && "Not an overloaded operator"); + break; + } +} + +void MicrosoftCXXNameMangler::mangleSourceName(const IdentifierInfo *II) { + // <source name> ::= <identifier> @ + Out << II->getName() << '@'; +} + +void MicrosoftCXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { + Context.mangleObjCMethodName(MD, Out); +} + +void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, + bool IsMember) { + // <cvr-qualifiers> ::= [E] [F] [I] <base-cvr-qualifiers> + // 'E' means __ptr64 (32-bit only); 'F' means __unaligned (32/64-bit only); + // 'I' means __restrict (32/64-bit). + // Note that the MSVC __restrict keyword isn't the same as the C99 restrict + // keyword! + // <base-cvr-qualifiers> ::= A # near + // ::= B # near const + // ::= C # near volatile + // ::= D # near const volatile + // ::= E # far (16-bit) + // ::= F # far const (16-bit) + // ::= G # far volatile (16-bit) + // ::= H # far const volatile (16-bit) + // ::= I # huge (16-bit) + // ::= J # huge const (16-bit) + // ::= K # huge volatile (16-bit) + // ::= L # huge const volatile (16-bit) + // ::= M <basis> # based + // ::= N <basis> # based const + // ::= O <basis> # based volatile + // ::= P <basis> # based const volatile + // ::= Q # near member + // ::= R # near const member + // ::= S # near volatile member + // ::= T # near const volatile member + // ::= U # far member (16-bit) + // ::= V # far const member (16-bit) + // ::= W # far volatile member (16-bit) + // ::= X # far const volatile member (16-bit) + // ::= Y # huge member (16-bit) + // ::= Z # huge const member (16-bit) + // ::= 0 # huge volatile member (16-bit) + // ::= 1 # huge const volatile member (16-bit) + // ::= 2 <basis> # based member + // ::= 3 <basis> # based const member + // ::= 4 <basis> # based volatile member + // ::= 5 <basis> # based const volatile member + // ::= 6 # near function (pointers only) + // ::= 7 # far function (pointers only) + // ::= 8 # near method (pointers only) + // ::= 9 # far method (pointers only) + // ::= _A <basis> # based function (pointers only) + // ::= _B <basis> # based function (far?) (pointers only) + // ::= _C <basis> # based method (pointers only) + // ::= _D <basis> # based method (far?) (pointers only) + // ::= _E # block (Clang) + // <basis> ::= 0 # __based(void) + // ::= 1 # __based(segment)? + // ::= 2 <name> # __based(name) + // ::= 3 # ? + // ::= 4 # ? + // ::= 5 # not really based + if (!IsMember) { + if (!Quals.hasVolatile()) { + if (!Quals.hasConst()) + Out << 'A'; + else + Out << 'B'; + } else { + if (!Quals.hasConst()) + Out << 'C'; + else + Out << 'D'; + } + } else { + if (!Quals.hasVolatile()) { + if (!Quals.hasConst()) + Out << 'Q'; + else + Out << 'R'; + } else { + if (!Quals.hasConst()) + Out << 'S'; + else + Out << 'T'; + } + } + + // FIXME: For now, just drop all extension qualifiers on the floor. +} + +void MicrosoftCXXNameMangler::mangleType(QualType T) { + // Only operate on the canonical type! + T = getASTContext().getCanonicalType(T); + + Qualifiers Quals = T.getLocalQualifiers(); + if (Quals) { + // We have to mangle these now, while we still have enough information. + // <pointer-cvr-qualifiers> ::= P # pointer + // ::= Q # const pointer + // ::= R # volatile pointer + // ::= S # const volatile pointer + if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + if (!Quals.hasVolatile()) + Out << 'Q'; + else { + if (!Quals.hasConst()) + Out << 'R'; + else + Out << 'S'; + } + } else + // Just emit qualifiers like normal. + // NB: When we mangle a pointer/reference type, and the pointee + // type has no qualifiers, the lack of qualifier gets mangled + // in there. + mangleQualifiers(Quals, false); + } else if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + Out << 'P'; + } + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define NON_CANONICAL_TYPE(CLASS, PARENT) \ +case Type::CLASS: \ +llvm_unreachable("can't mangle non-canonical type " #CLASS "Type"); \ +return; +#define TYPE(CLASS, PARENT) \ +case Type::CLASS: \ +mangleType(static_cast<const CLASS##Type*>(T.getTypePtr())); \ +break; +#include "clang/AST/TypeNodes.def" + } +} + +void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T) { + // <type> ::= <builtin-type> + // <builtin-type> ::= X # void + // ::= C # signed char + // ::= D # char + // ::= E # unsigned char + // ::= F # short + // ::= G # unsigned short (or wchar_t if it's not a builtin) + // ::= H # int + // ::= I # unsigned int + // ::= J # long + // ::= K # unsigned long + // L # <none> + // ::= M # float + // ::= N # double + // ::= O # long double (__float80 is mangled differently) + // ::= _J # long long, __int64 + // ::= _K # unsigned long long, __int64 + // ::= _L # __int128 + // ::= _M # unsigned __int128 + // ::= _N # bool + // _O # <array in parameter> + // ::= _T # __float80 (Intel) + // ::= _W # wchar_t + // ::= _Z # __float80 (Digital Mars) + switch (T->getKind()) { + case BuiltinType::Void: Out << 'X'; break; + case BuiltinType::SChar: Out << 'C'; break; + case BuiltinType::Char_U: case BuiltinType::Char_S: Out << 'D'; break; + case BuiltinType::UChar: Out << 'E'; break; + case BuiltinType::Short: Out << 'F'; break; + case BuiltinType::UShort: Out << 'G'; break; + case BuiltinType::Int: Out << 'H'; break; + case BuiltinType::UInt: Out << 'I'; break; + case BuiltinType::Long: Out << 'J'; break; + case BuiltinType::ULong: Out << 'K'; break; + case BuiltinType::Float: Out << 'M'; break; + case BuiltinType::Double: Out << 'N'; break; + // TODO: Determine size and mangle accordingly + case BuiltinType::LongDouble: Out << 'O'; break; + case BuiltinType::LongLong: Out << "_J"; break; + case BuiltinType::ULongLong: Out << "_K"; break; + case BuiltinType::Int128: Out << "_L"; break; + case BuiltinType::UInt128: Out << "_M"; break; + case BuiltinType::Bool: Out << "_N"; break; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: Out << "_W"; break; + + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::UnknownAny: + case BuiltinType::BoundMember: + assert(false && + "Overloaded and dependent types shouldn't get to name mangling"); + break; + case BuiltinType::ObjCId: Out << "PAUobjc_object@@"; break; + case BuiltinType::ObjCClass: Out << "PAUobjc_class@@"; break; + case BuiltinType::ObjCSel: Out << "PAUobjc_selector@@"; break; + + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::NullPtr: + assert(false && "Don't know how to mangle this type"); + break; + } +} + +// <type> ::= <function-type> +void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T) { + // Structors only appear in decls, so at this point we know it's not a + // structor type. + // I'll probably have mangleType(MemberPointerType) call the mangleType() + // method directly. + mangleType(T, NULL, false, false); +} +void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T) { + llvm_unreachable("Can't mangle K&R function prototypes"); +} + +void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, + const FunctionDecl *D, + bool IsStructor, + bool IsInstMethod) { + // <function-type> ::= <this-cvr-qualifiers> <calling-convention> + // <return-type> <argument-list> <throw-spec> + const FunctionProtoType *Proto = cast<FunctionProtoType>(T); + + // If this is a C++ instance method, mangle the CVR qualifiers for the + // this pointer. + if (IsInstMethod) + mangleQualifiers(Qualifiers::fromCVRMask(Proto->getTypeQuals()), false); + + mangleCallingConvention(T, IsInstMethod); + + // <return-type> ::= <type> + // ::= @ # structors (they have no declared return type) + if (IsStructor) + Out << '@'; + else + mangleType(Proto->getResultType()); + + // <argument-list> ::= X # void + // ::= <type>+ @ + // ::= <type>* Z # varargs + if (Proto->getNumArgs() == 0 && !Proto->isVariadic()) { + Out << 'X'; + } else { + if (D) { + // If we got a decl, use the "types-as-written" to make sure arrays + // get mangled right. + for (FunctionDecl::param_const_iterator Parm = D->param_begin(), + ParmEnd = D->param_end(); + Parm != ParmEnd; ++Parm) + mangleType((*Parm)->getTypeSourceInfo()->getType()); + } else { + for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), + ArgEnd = Proto->arg_type_end(); + Arg != ArgEnd; ++Arg) + mangleType(*Arg); + } + // <builtin-type> ::= Z # ellipsis + if (Proto->isVariadic()) + Out << 'Z'; + else + Out << '@'; + } + + mangleThrowSpecification(Proto); +} + +void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { + // <function-class> ::= A # private: near + // ::= B # private: far + // ::= C # private: static near + // ::= D # private: static far + // ::= E # private: virtual near + // ::= F # private: virtual far + // ::= G # private: thunk near + // ::= H # private: thunk far + // ::= I # protected: near + // ::= J # protected: far + // ::= K # protected: static near + // ::= L # protected: static far + // ::= M # protected: virtual near + // ::= N # protected: virtual far + // ::= O # protected: thunk near + // ::= P # protected: thunk far + // ::= Q # public: near + // ::= R # public: far + // ::= S # public: static near + // ::= T # public: static far + // ::= U # public: virtual near + // ::= V # public: virtual far + // ::= W # public: thunk near + // ::= X # public: thunk far + // ::= Y # global near + // ::= Z # global far + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { + switch (MD->getAccess()) { + default: + case AS_private: + if (MD->isStatic()) + Out << 'C'; + else if (MD->isVirtual()) + Out << 'E'; + else + Out << 'A'; + break; + case AS_protected: + if (MD->isStatic()) + Out << 'K'; + else if (MD->isVirtual()) + Out << 'M'; + else + Out << 'I'; + break; + case AS_public: + if (MD->isStatic()) + Out << 'S'; + else if (MD->isVirtual()) + Out << 'U'; + else + Out << 'Q'; + } + } else + Out << 'Y'; +} +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, + bool IsInstMethod) { + // <calling-convention> ::= A # __cdecl + // ::= B # __export __cdecl + // ::= C # __pascal + // ::= D # __export __pascal + // ::= E # __thiscall + // ::= F # __export __thiscall + // ::= G # __stdcall + // ::= H # __export __stdcall + // ::= I # __fastcall + // ::= J # __export __fastcall + // The 'export' calling conventions are from a bygone era + // (*cough*Win16*cough*) when functions were declared for export with + // that keyword. (It didn't actually export them, it just made them so + // that they could be in a DLL and somebody from another module could call + // them.) + CallingConv CC = T->getCallConv(); + if (CC == CC_Default) + CC = IsInstMethod ? getASTContext().getDefaultMethodCallConv() : CC_C; + switch (CC) { + default: + assert(0 && "Unsupported CC for mangling"); + case CC_Default: + case CC_C: Out << 'A'; break; + case CC_X86Pascal: Out << 'C'; break; + case CC_X86ThisCall: Out << 'E'; break; + case CC_X86StdCall: Out << 'G'; break; + case CC_X86FastCall: Out << 'I'; break; + } +} +void MicrosoftCXXNameMangler::mangleThrowSpecification( + const FunctionProtoType *FT) { + // <throw-spec> ::= Z # throw(...) (default) + // ::= @ # throw() or __declspec/__attribute__((nothrow)) + // ::= <type>+ + // NOTE: Since the Microsoft compiler ignores throw specifications, they are + // all actually mangled as 'Z'. (They're ignored because their associated + // functionality isn't implemented, and probably never will be.) + Out << 'Z'; +} + +void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T) { + assert(false && "Don't know how to mangle UnresolvedUsingTypes yet!"); +} + +// <type> ::= <union-type> | <struct-type> | <class-type> | <enum-type> +// <union-type> ::= T <name> +// <struct-type> ::= U <name> +// <class-type> ::= V <name> +// <enum-type> ::= W <size> <name> +void MicrosoftCXXNameMangler::mangleType(const EnumType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const RecordType *T) { + mangleType(static_cast<const TagType*>(T)); +} +void MicrosoftCXXNameMangler::mangleType(const TagType *T) { + switch (T->getDecl()->getTagKind()) { + case TTK_Union: + Out << 'T'; + break; + case TTK_Struct: + Out << 'U'; + break; + case TTK_Class: + Out << 'V'; + break; + case TTK_Enum: + Out << 'W'; + Out << getASTContext().getTypeSizeInChars( + cast<EnumDecl>(T->getDecl())->getIntegerType()).getQuantity(); + break; + } + mangleName(T->getDecl()); +} + +// <type> ::= <array-type> +// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as global +// ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] +// <element-type> # as param +// It's supposed to be the other way around, but for some strange reason, it +// isn't. Today this behavior is retained for the sole purpose of backwards +// compatibility. +void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { + // This isn't a recursive mangling, so now we have to do it all in this + // one call. + if (IsGlobal) + Out << 'P'; + else + Out << 'Q'; + mangleExtraDimensions(T->getElementType()); +} +void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T) { + mangleType(static_cast<const ArrayType *>(T), false); +} +void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { + llvm::SmallVector<llvm::APInt, 3> Dimensions; + for (;;) { + if (ElementTy->isConstantArrayType()) { + const ConstantArrayType *CAT = + static_cast<const ConstantArrayType *>(ElementTy.getTypePtr()); + Dimensions.push_back(CAT->getSize()); + ElementTy = CAT->getElementType(); + } else if (ElementTy->isVariableArrayType()) { + assert(false && "Don't know how to mangle VLAs!"); + } else if (ElementTy->isDependentSizedArrayType()) { + // The dependent expression has to be folded into a constant (TODO). + assert(false && "Don't know how to mangle dependent-sized arrays!"); + } else if (ElementTy->isIncompleteArrayType()) continue; + else break; + } + mangleQualifiers(ElementTy.getQualifiers(), false); + // If there are any additional dimensions, mangle them now. + if (Dimensions.size() > 0) { + Out << 'Y'; + // <dimension-count> ::= <number> # number of extra dimensions + mangleNumber(Dimensions.size()); + for (unsigned Dim = 0; Dim < Dimensions.size(); ++Dim) { + mangleNumber(Dimensions[Dim].getLimitedValue()); + } + } + mangleType(ElementTy.getLocalUnqualifiedType()); +} + +// <type> ::= <pointer-to-member-type> +// <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// <class name> <type> +void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T) { + QualType PointeeType = T->getPointeeType(); + if (const FunctionProtoType *FPT = dyn_cast<FunctionProtoType>(PointeeType)) { + Out << '8'; + mangleName(cast<RecordType>(T->getClass())->getDecl()); + mangleType(FPT, NULL, false, true); + } else { + mangleQualifiers(PointeeType.getQualifiers(), true); + mangleName(cast<RecordType>(T->getClass())->getDecl()); + mangleType(PointeeType.getLocalUnqualifiedType()); + } +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) { + assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType( + const SubstTemplateTypeParmPackType *T) { + assert(false && + "Don't know how to mangle SubstTemplateTypeParmPackTypes yet!"); +} + +// <type> ::= <pointer-type> +// <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const PointerType *T) { + QualType PointeeTy = T->getPointeeType(); + if (PointeeTy->isArrayType()) { + // Pointers to arrays are mangled like arrays. + mangleExtraDimensions(T->getPointeeType()); + } else if (PointeeTy->isFunctionType()) { + // Function pointers are special. + Out << '6'; + mangleType(static_cast<const FunctionType *>(PointeeTy.getTypePtr()), + NULL, false, false); + } else { + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); + } +} +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T) { + // Object pointers never have qualifiers. + Out << 'A'; + mangleType(T->getPointeeType()); +} + +// <type> ::= <reference-type> +// <reference-type> ::= A <cvr-qualifiers> <type> +void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T) { + Out << 'A'; + QualType PointeeTy = T->getPointeeType(); + if (!PointeeTy.hasQualifiers()) + // Lack of qualifiers is mangled as 'A'. + Out << 'A'; + mangleType(PointeeTy); +} + +void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T) { + assert(false && "Don't know how to mangle RValueReferenceTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const ComplexType *T) { + assert(false && "Don't know how to mangle ComplexTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const VectorType *T) { + assert(false && "Don't know how to mangle VectorTypes yet!"); +} +void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T) { + assert(false && "Don't know how to mangle ExtVectorTypes yet!"); +} +void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { + assert(false && "Don't know how to mangle DependentSizedExtVectorTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T) { + // ObjC interfaces have structs underlying them. + Out << 'U'; + mangleName(T->getDecl()); +} + +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T) { + // We don't allow overloading by different protocol qualification, + // so mangling them isn't necessary. + mangleType(T->getBaseType()); +} + +void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T) { + Out << "_E"; + mangleType(T->getPointeeType()); +} + +void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T) { + assert(false && "Don't know how to mangle InjectedClassNameTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T) { + assert(false && "Don't know how to mangle TemplateSpecializationTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T) { + assert(false && "Don't know how to mangle DependentNameTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType( + const DependentTemplateSpecializationType *T) { + assert(false && + "Don't know how to mangle DependentTemplateSpecializationTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) { + assert(false && "Don't know how to mangle PackExpansionTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) { + assert(false && "Don't know how to mangle TypeOfTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T) { + assert(false && "Don't know how to mangle TypeOfExprTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T) { + assert(false && "Don't know how to mangle DecltypeTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T) { + assert(false && "Don't know how to mangle UnaryTransformationTypes yet!"); +} + +void MicrosoftCXXNameMangler::mangleType(const AutoType *T) { + assert(false && "Don't know how to mangle AutoTypes yet!"); +} + +void MicrosoftMangleContext::mangleName(const NamedDecl *D, + llvm::raw_ostream &Out) { + assert((isa<FunctionDecl>(D) || isa<VarDecl>(D)) && + "Invalid mangleName() call, argument is not a variable or function!"); + assert(!isa<CXXConstructorDecl>(D) && !isa<CXXDestructorDecl>(D) && + "Invalid mangleName() call on 'structor decl!"); + + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling declaration"); + + MicrosoftCXXNameMangler Mangler(*this, Out); + return Mangler.mangle(D); +} +void MicrosoftMangleContext::mangleThunk(const CXXMethodDecl *MD, + const ThunkInfo &Thunk, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle thunks!"); +} +void MicrosoftMangleContext::mangleCXXDtorThunk(const CXXDestructorDecl *DD, + CXXDtorType Type, + const ThisAdjustment &, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle destructor thunks!"); +} +void MicrosoftMangleContext::mangleCXXVTable(const CXXRecordDecl *RD, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle virtual tables!"); +} +void MicrosoftMangleContext::mangleCXXVTT(const CXXRecordDecl *RD, + llvm::raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have virtual table tables!"); +} +void MicrosoftMangleContext::mangleCXXCtorVTable(const CXXRecordDecl *RD, + int64_t Offset, + const CXXRecordDecl *Type, + llvm::raw_ostream &) { + llvm_unreachable("The MS C++ ABI does not have constructor vtables!"); +} +void MicrosoftMangleContext::mangleCXXRTTI(QualType T, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle RTTI!"); +} +void MicrosoftMangleContext::mangleCXXRTTIName(QualType T, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle RTTI names!"); +} +void MicrosoftMangleContext::mangleCXXCtor(const CXXConstructorDecl *D, + CXXCtorType Type, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle constructors!"); +} +void MicrosoftMangleContext::mangleCXXDtor(const CXXDestructorDecl *D, + CXXDtorType Type, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle destructors!"); +} +void MicrosoftMangleContext::mangleReferenceTemporary(const clang::VarDecl *, + llvm::raw_ostream &) { + assert(false && "Can't yet mangle reference temporaries!"); +} + +MangleContext *clang::createMicrosoftMangleContext(ASTContext &Context, + Diagnostic &Diags) { + return new MicrosoftMangleContext(Context, Diags); +} diff --git a/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp new file mode 100644 index 000000000000..2878dff3edc4 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/NestedNameSpecifier.cpp @@ -0,0 +1,619 @@ +//===--- 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/DeclCXX.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "llvm/Support/raw_ostream.h" +#include <cassert> + +using namespace clang; + +NestedNameSpecifier * +NestedNameSpecifier::FindOrInsert(const 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(const 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(StoredIdentifier); + Mockup.Specifier = II; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(const 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(StoredNamespaceOrAlias); + Mockup.Specifier = NS; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + NamespaceAliasDecl *Alias) { + assert(Alias && "Namespace alias cannot be NULL"); + assert((!Prefix || + (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) && + "Broken nested name specifier"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(Prefix); + Mockup.Prefix.setInt(StoredNamespaceOrAlias); + Mockup.Specifier = Alias; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + bool Template, const Type *T) { + assert(T && "Type cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(Prefix); + Mockup.Prefix.setInt(Template? StoredTypeSpecWithTemplate : StoredTypeSpec); + Mockup.Specifier = const_cast<Type*>(T); + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { + assert(II && "Identifier cannot be NULL"); + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(0); + Mockup.Prefix.setInt(StoredIdentifier); + Mockup.Specifier = II; + return FindOrInsert(Context, Mockup); +} + +NestedNameSpecifier * +NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { + if (!Context.GlobalNestedNameSpecifier) + Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier(); + return Context.GlobalNestedNameSpecifier; +} + +NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { + if (Specifier == 0) + return Global; + + switch (Prefix.getInt()) { + case StoredIdentifier: + return Identifier; + + case StoredNamespaceOrAlias: + return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace + : NamespaceAlias; + + case StoredTypeSpec: + return TypeSpec; + + case StoredTypeSpecWithTemplate: + return TypeSpecWithTemplate; + } + + return Global; +} + +/// \brief Retrieve the namespace stored in this nested name +/// specifier. +NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { + if (Prefix.getInt() == StoredNamespaceOrAlias) + return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier)); + + return 0; +} + +/// \brief Retrieve the namespace alias stored in this nested name +/// specifier. +NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { + if (Prefix.getInt() == StoredNamespaceOrAlias) + return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier)); + + return 0; +} + + +/// \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 NamespaceAlias: + case Global: + return false; + + case TypeSpec: + case TypeSpecWithTemplate: + return getAsType()->isDependentType(); + } + + // Necessary to suppress a GCC warning. + return false; +} + +bool NestedNameSpecifier::containsUnexpandedParameterPack() const { + switch (getKind()) { + case Identifier: + return getPrefix() && getPrefix()->containsUnexpandedParameterPack(); + + case Namespace: + case NamespaceAlias: + case Global: + return false; + + case TypeSpec: + case TypeSpecWithTemplate: + return getAsType()->containsUnexpandedParameterPack(); + } + + // 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()->getName(); + break; + + case NamespaceAlias: + OS << getAsNamespaceAlias()->getName(); + break; + + case Global: + break; + + case TypeSpecWithTemplate: + OS << "template "; + // Fall through to print the type. + + case TypeSpec: { + std::string TypeStr; + const Type *T = getAsType(); + + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressScope = true; + + // Nested-name-specifiers are intended to contain minimally-qualified + // types. An actual ElaboratedType will not occur, since we'll store + // just the type that is referred to in the nested-name-specifier (e.g., + // a TypedefType, TagType, etc.). However, when we are dealing with + // dependent template-id types (e.g., Outer<T>::template Inner<U>), + // the type requires its own nested-name-specifier for uniqueness, so we + // suppress that nested-name-specifier during printing. + assert(!isa<ElaboratedType>(T) && + "Elaborated type in nested-name-specifier"); + if (const TemplateSpecializationType *SpecType + = dyn_cast<TemplateSpecializationType>(T)) { + // Print the template name without its corresponding + // nested-name-specifier. + SpecType->getTemplateName().print(OS, InnerPolicy, true); + + // Print the template argument list. + TypeStr = TemplateSpecializationType::PrintTemplateArgumentList( + SpecType->getArgs(), + SpecType->getNumArgs(), + InnerPolicy); + } else { + // Print the type normally + TypeStr = QualType(T, 0).getAsString(InnerPolicy); + } + OS << TypeStr; + break; + } + } + + OS << "::"; +} + +void NestedNameSpecifier::dump(const LangOptions &LO) { + print(llvm::errs(), PrintingPolicy(LO)); +} + +unsigned +NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { + assert(Qualifier && "Expected a non-NULL qualifier"); + + // Location of the trailing '::'. + unsigned Length = sizeof(unsigned); + + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + // Nothing more to add. + break; + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + // The location of the identifier or namespace name. + Length += sizeof(unsigned); + break; + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::TypeSpec: + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + Length += sizeof(void *); + break; + } + + return Length; +} + +unsigned +NestedNameSpecifierLoc::getDataLength(NestedNameSpecifier *Qualifier) { + unsigned Length = 0; + for (; Qualifier; Qualifier = Qualifier->getPrefix()) + Length += getLocalDataLength(Qualifier); + return Length; +} + +namespace { + /// \brief Load a (possibly unaligned) source location from a given address + /// and offset. + SourceLocation LoadSourceLocation(void *Data, unsigned Offset) { + unsigned Raw; + memcpy(&Raw, static_cast<char *>(Data) + Offset, sizeof(unsigned)); + return SourceLocation::getFromRawEncoding(Raw); + } + + /// \brief Load a (possibly unaligned) pointer from a given address and + /// offset. + void *LoadPointer(void *Data, unsigned Offset) { + void *Result; + memcpy(&Result, static_cast<char *>(Data) + Offset, sizeof(void*)); + return Result; + } +} + +SourceRange NestedNameSpecifierLoc::getSourceRange() const { + if (!Qualifier) + return SourceRange(); + + NestedNameSpecifierLoc First = *this; + while (NestedNameSpecifierLoc Prefix = First.getPrefix()) + First = Prefix; + + return SourceRange(First.getLocalSourceRange().getBegin(), + getLocalSourceRange().getEnd()); +} + +SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { + if (!Qualifier) + return SourceRange(); + + unsigned Offset = getDataLength(Qualifier->getPrefix()); + switch (Qualifier->getKind()) { + case NestedNameSpecifier::Global: + return LoadSourceLocation(Data, Offset); + + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + return SourceRange(LoadSourceLocation(Data, Offset), + LoadSourceLocation(Data, Offset + sizeof(unsigned))); + + case NestedNameSpecifier::TypeSpecWithTemplate: + case NestedNameSpecifier::TypeSpec: { + // The "void*" that points at the TypeLoc data. + // Note: the 'template' keyword is part of the TypeLoc. + void *TypeData = LoadPointer(Data, Offset); + TypeLoc TL(Qualifier->getAsType(), TypeData); + return SourceRange(TL.getBeginLoc(), + LoadSourceLocation(Data, Offset + sizeof(void*))); + } + } + + return SourceRange(); +} + +TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { + assert((Qualifier->getKind() == NestedNameSpecifier::TypeSpec || + Qualifier->getKind() == NestedNameSpecifier::TypeSpecWithTemplate) && + "Nested-name-specifier location is not a type"); + + // The "void*" that points at the TypeLoc data. + unsigned Offset = getDataLength(Qualifier->getPrefix()); + void *TypeData = LoadPointer(Data, Offset); + return TypeLoc(Qualifier->getAsType(), TypeData); +} + +namespace { + void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + if (BufferSize + (End - Start) > BufferCapacity) { + // Reallocate the buffer. + unsigned NewCapacity + = std::max((unsigned)(BufferCapacity? BufferCapacity * 2 + : sizeof(void*) * 2), + (unsigned)(BufferSize + (End - Start))); + char *NewBuffer = static_cast<char *>(malloc(NewCapacity)); + memcpy(NewBuffer, Buffer, BufferSize); + + if (BufferCapacity) + free(Buffer); + Buffer = NewBuffer; + BufferCapacity = NewCapacity; + } + + memcpy(Buffer + BufferSize, Start, End - Start); + BufferSize += End-Start; + } + + /// \brief Save a source location to the given buffer. + void SaveSourceLocation(SourceLocation Loc, char *&Buffer, + unsigned &BufferSize, unsigned &BufferCapacity) { + unsigned Raw = Loc.getRawEncoding(); + Append(reinterpret_cast<char *>(&Raw), + reinterpret_cast<char *>(&Raw) + sizeof(unsigned), + Buffer, BufferSize, BufferCapacity); + } + + /// \brief Save a pointer to the given buffer. + void SavePointer(void *Ptr, char *&Buffer, unsigned &BufferSize, + unsigned &BufferCapacity) { + Append(reinterpret_cast<char *>(&Ptr), + reinterpret_cast<char *>(&Ptr) + sizeof(void *), + Buffer, BufferSize, BufferCapacity); + } +} + +NestedNameSpecifierLocBuilder::NestedNameSpecifierLocBuilder() + : Representation(0), Buffer(0), BufferSize(0), BufferCapacity(0) { } + +NestedNameSpecifierLocBuilder:: +NestedNameSpecifierLocBuilder(const NestedNameSpecifierLocBuilder &Other) + : Representation(Other.Representation), Buffer(0), + BufferSize(0), BufferCapacity(0) +{ + if (!Other.Buffer) + return; + + if (Other.BufferCapacity == 0) { + // Shallow copy is okay. + Buffer = Other.Buffer; + BufferSize = Other.BufferSize; + return; + } + + // Deep copy + BufferSize = Other.BufferSize; + BufferCapacity = Other.BufferSize; + Buffer = static_cast<char *>(malloc(BufferCapacity)); + memcpy(Buffer, Other.Buffer, BufferSize); +} + +NestedNameSpecifierLocBuilder & +NestedNameSpecifierLocBuilder:: +operator=(const NestedNameSpecifierLocBuilder &Other) { + Representation = Other.Representation; + + if (Buffer && Other.Buffer && BufferCapacity >= Other.BufferSize) { + // Re-use our storage. + BufferSize = Other.BufferSize; + memcpy(Buffer, Other.Buffer, BufferSize); + return *this; + } + + // Free our storage, if we have any. + if (BufferCapacity) { + free(Buffer); + BufferCapacity = 0; + } + + if (!Other.Buffer) { + // Empty. + Buffer = 0; + BufferSize = 0; + return *this; + } + + if (Other.BufferCapacity == 0) { + // Shallow copy is okay. + Buffer = Other.Buffer; + BufferSize = Other.BufferSize; + return *this; + } + + // Deep copy. + BufferSize = Other.BufferSize; + BufferCapacity = BufferSize; + Buffer = static_cast<char *>(malloc(BufferSize)); + memcpy(Buffer, Other.Buffer, BufferSize); + return *this; +} + +NestedNameSpecifierLocBuilder::~NestedNameSpecifierLocBuilder() { + if (BufferCapacity) + free(Buffer); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + SourceLocation TemplateKWLoc, + TypeLoc TL, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + TemplateKWLoc.isValid(), + TL.getTypePtr()); + + // Push source-location info into the buffer. + SavePointer(TL.getOpaqueData(), Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + IdentifierInfo *Identifier, + SourceLocation IdentifierLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + Identifier); + + // Push source-location info into the buffer. + SaveSourceLocation(IdentifierLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + NamespaceDecl *Namespace, + SourceLocation NamespaceLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, + Namespace); + + // Push source-location info into the buffer. + SaveSourceLocation(NamespaceLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::Extend(ASTContext &Context, + NamespaceAliasDecl *Alias, + SourceLocation AliasLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::Create(Context, Representation, Alias); + + // Push source-location info into the buffer. + SaveSourceLocation(AliasLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, + SourceLocation ColonColonLoc) { + assert(!Representation && "Already have a nested-name-specifier!?"); + Representation = NestedNameSpecifier::GlobalSpecifier(Context); + + // Push source-location info into the buffer. + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + +void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, + NestedNameSpecifier *Qualifier, + SourceRange R) { + Representation = Qualifier; + + // Construct bogus (but well-formed) source information for the + // nested-name-specifier. + BufferSize = 0; + llvm::SmallVector<NestedNameSpecifier *, 4> Stack; + for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) + Stack.push_back(NNS); + while (!Stack.empty()) { + NestedNameSpecifier *NNS = Stack.back(); + Stack.pop_back(); + switch (NNS->getKind()) { + case NestedNameSpecifier::Identifier: + case NestedNameSpecifier::Namespace: + case NestedNameSpecifier::NamespaceAlias: + SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); + break; + + case NestedNameSpecifier::TypeSpec: + case NestedNameSpecifier::TypeSpecWithTemplate: { + TypeSourceInfo *TSInfo + = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), + R.getBegin()); + SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, + BufferCapacity); + break; + } + + case NestedNameSpecifier::Global: + break; + } + + // Save the location of the '::'. + SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), + Buffer, BufferSize, BufferCapacity); + } +} + +void NestedNameSpecifierLocBuilder::Adopt(NestedNameSpecifierLoc Other) { + if (BufferCapacity) + free(Buffer); + + if (!Other) { + Representation = 0; + BufferSize = 0; + return; + } + + // Rather than copying the data (which is wasteful), "adopt" the + // pointer (which points into the ASTContext) but set the capacity to zero to + // indicate that we don't own it. + Representation = Other.getNestedNameSpecifier(); + Buffer = static_cast<char *>(Other.getOpaqueData()); + BufferSize = Other.getDataLength(); + BufferCapacity = 0; +} + +NestedNameSpecifierLoc +NestedNameSpecifierLocBuilder::getWithLocInContext(ASTContext &Context) const { + if (!Representation) + return NestedNameSpecifierLoc(); + + // If we adopted our data pointer from elsewhere in the AST context, there's + // no need to copy the memory. + if (BufferCapacity == 0) + return NestedNameSpecifierLoc(Representation, Buffer); + + // FIXME: After copying the source-location information, should we free + // our (temporary) buffer and adopt the ASTContext-allocated memory? + // Doing so would optimize repeated calls to getWithLocInContext(). + void *Mem = Context.Allocate(BufferSize, llvm::alignOf<void *>()); + memcpy(Mem, Buffer, BufferSize); + return NestedNameSpecifierLoc(Representation, Mem); +} + diff --git a/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp b/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp new file mode 100644 index 000000000000..eca351aec8dd --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ParentMap.cpp @@ -0,0 +1,109 @@ +//===--- 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_range I = S->children(); I; ++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; +} + +void ParentMap::addStmt(Stmt* S) { + if (S) { + BuildParentMap(*(MapTy*) Impl, S); + } +} + +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; +} + +Stmt *ParentMap::getParentIgnoreParenCasts(Stmt *S) const { + do { + S = getParent(S); + } + while (S && (isa<ParenExpr>(S) || isa<CastExpr>(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()!=BO_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/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp new file mode 100644 index 000000000000..035c48fd0827 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayout.cpp @@ -0,0 +1,81 @@ +//===-- RecordLayout.cpp - Layout information for a struct/union -*- 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 RecordLayout interface. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" + +using namespace clang; + +void ASTRecordLayout::Destroy(ASTContext &Ctx) { + if (FieldOffsets) + Ctx.Deallocate(FieldOffsets); + if (CXXInfo) { + Ctx.Deallocate(CXXInfo); + CXXInfo->~CXXRecordLayoutInfo(); + } + this->~ASTRecordLayout(); + Ctx.Deallocate(this); +} + +ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, CharUnits size, + CharUnits alignment, CharUnits datasize, + const uint64_t *fieldoffsets, + unsigned fieldcount) + : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), + FieldCount(fieldcount), CXXInfo(0) { + if (FieldCount > 0) { + FieldOffsets = new (Ctx) uint64_t[FieldCount]; + memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); + } +} + +// Constructor for C++ records. +ASTRecordLayout::ASTRecordLayout(const ASTContext &Ctx, + CharUnits size, CharUnits alignment, + CharUnits datasize, + const uint64_t *fieldoffsets, + unsigned fieldcount, + CharUnits nonvirtualsize, + CharUnits nonvirtualalign, + CharUnits SizeOfLargestEmptySubobject, + const CXXRecordDecl *PrimaryBase, + bool IsPrimaryBaseVirtual, + const BaseOffsetsMapTy& BaseOffsets, + const BaseOffsetsMapTy& VBaseOffsets) + : Size(size), DataSize(datasize), FieldOffsets(0), Alignment(alignment), + FieldCount(fieldcount), CXXInfo(new (Ctx) CXXRecordLayoutInfo) +{ + if (FieldCount > 0) { + FieldOffsets = new (Ctx) uint64_t[FieldCount]; + memcpy(FieldOffsets, fieldoffsets, FieldCount * sizeof(*FieldOffsets)); + } + + CXXInfo->PrimaryBase.setPointer(PrimaryBase); + CXXInfo->PrimaryBase.setInt(IsPrimaryBaseVirtual); + CXXInfo->NonVirtualSize = nonvirtualsize; + CXXInfo->NonVirtualAlign = nonvirtualalign; + CXXInfo->SizeOfLargestEmptySubobject = SizeOfLargestEmptySubobject; + CXXInfo->BaseOffsets = BaseOffsets; + CXXInfo->VBaseOffsets = VBaseOffsets; + +#ifndef NDEBUG + if (const CXXRecordDecl *PrimaryBase = getPrimaryBase()) { + if (isPrimaryBaseVirtual()) + assert(getVBaseClassOffset(PrimaryBase).isZero() && + "Primary virtual base must be at offset 0!"); + else + assert(getBaseClassOffsetInBits(PrimaryBase) == 0 && + "Primary base must be at offset 0!"); + } +#endif +} diff --git a/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp new file mode 100644 index 000000000000..de0b1d0ed9db --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/RecordLayoutBuilder.cpp @@ -0,0 +1,2078 @@ +//=== RecordLayoutBuilder.cpp - Helper class for building record layouts ---==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/RecordLayout.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "llvm/Support/Format.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/CrashRecoveryContext.h" + +using namespace clang; + +namespace { + +/// BaseSubobjectInfo - Represents a single base subobject in a complete class. +/// For a class hierarchy like +/// +/// class A { }; +/// class B : A { }; +/// class C : A, B { }; +/// +/// The BaseSubobjectInfo graph for C will have three BaseSubobjectInfo +/// instances, one for B and two for A. +/// +/// If a base is virtual, it will only have one BaseSubobjectInfo allocated. +struct BaseSubobjectInfo { + /// Class - The class for this base info. + const CXXRecordDecl *Class; + + /// IsVirtual - Whether the BaseInfo represents a virtual base or not. + bool IsVirtual; + + /// Bases - Information about the base subobjects. + llvm::SmallVector<BaseSubobjectInfo*, 4> Bases; + + /// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base + /// of this base info (if one exists). + BaseSubobjectInfo *PrimaryVirtualBaseInfo; + + // FIXME: Document. + const BaseSubobjectInfo *Derived; +}; + +/// EmptySubobjectMap - Keeps track of which empty subobjects exist at different +/// offsets while laying out a C++ class. +class EmptySubobjectMap { + const ASTContext &Context; + uint64_t CharWidth; + + /// Class - The class whose empty entries we're keeping track of. + const CXXRecordDecl *Class; + + /// EmptyClassOffsets - A map from offsets to empty record decls. + typedef llvm::SmallVector<const CXXRecordDecl *, 1> ClassVectorTy; + typedef llvm::DenseMap<CharUnits, ClassVectorTy> EmptyClassOffsetsMapTy; + EmptyClassOffsetsMapTy EmptyClassOffsets; + + /// MaxEmptyClassOffset - The highest offset known to contain an empty + /// base subobject. + CharUnits MaxEmptyClassOffset; + + /// ComputeEmptySubobjectSizes - Compute the size of the largest base or + /// member subobject that is empty. + void ComputeEmptySubobjectSizes(); + + void AddSubobjectAtOffset(const CXXRecordDecl *RD, CharUnits Offset); + + void UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, + CharUnits Offset, bool PlacingEmptyBase); + + void UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + CharUnits Offset); + void UpdateEmptyFieldSubobjects(const FieldDecl *FD, CharUnits Offset); + + /// AnyEmptySubobjectsBeyondOffset - Returns whether there are any empty + /// subobjects beyond the given offset. + bool AnyEmptySubobjectsBeyondOffset(CharUnits Offset) const { + return Offset <= MaxEmptyClassOffset; + } + + CharUnits + getFieldOffset(const ASTRecordLayout &Layout, unsigned FieldNo) const { + uint64_t FieldOffset = Layout.getFieldOffset(FieldNo); + assert(FieldOffset % CharWidth == 0 && + "Field offset not at char boundary!"); + + return Context.toCharUnitsFromBits(FieldOffset); + } + +protected: + bool CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) const; + + bool CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset); + + bool CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + CharUnits Offset) const; + bool CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + CharUnits Offset) const; + +public: + /// This holds the size of the largest empty subobject (either a base + /// or a member). Will be zero if the record being built doesn't contain + /// any empty classes. + CharUnits SizeOfLargestEmptySubobject; + + EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class) + : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { + ComputeEmptySubobjectSizes(); + } + + /// CanPlaceBaseAtOffset - Return whether the given base class can be placed + /// at the given offset. + /// Returns false if placing the record will result in two components + /// (direct or indirect) of the same type having the same offset. + bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset); + + /// CanPlaceFieldAtOffset - Return whether a field can be placed at the given + /// offset. + bool CanPlaceFieldAtOffset(const FieldDecl *FD, CharUnits Offset); +}; + +void EmptySubobjectMap::ComputeEmptySubobjectSizes() { + // Check the bases. + for (CXXRecordDecl::base_class_const_iterator I = Class->bases_begin(), + E = Class->bases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits EmptySize; + const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); + if (BaseDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } + + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } + + // Check the fields. + for (CXXRecordDecl::field_iterator I = Class->field_begin(), + E = Class->field_end(); I != E; ++I) { + const FieldDecl *FD = *I; + + const RecordType *RT = + Context.getBaseElementType(FD->getType())->getAs<RecordType>(); + + // We only care about record types. + if (!RT) + continue; + + CharUnits EmptySize; + const CXXRecordDecl *MemberDecl = cast<CXXRecordDecl>(RT->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(MemberDecl); + if (MemberDecl->isEmpty()) { + // If the class decl is empty, get its size. + EmptySize = Layout.getSize(); + } else { + // Otherwise, we get the largest empty subobject for the decl. + EmptySize = Layout.getSizeOfLargestEmptySubobject(); + } + + if (EmptySize > SizeOfLargestEmptySubobject) + SizeOfLargestEmptySubobject = EmptySize; + } +} + +bool +EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) const { + // We only need to check empty bases. + if (!RD->isEmpty()) + return true; + + EmptyClassOffsetsMapTy::const_iterator I = EmptyClassOffsets.find(Offset); + if (I == EmptyClassOffsets.end()) + return true; + + const ClassVectorTy& Classes = I->second; + if (std::find(Classes.begin(), Classes.end(), RD) == Classes.end()) + return true; + + // There is already an empty class of the same type at this offset. + return false; +} + +void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) { + // We only care about empty bases. + if (!RD->isEmpty()) + return; + + // If we have empty structures inside an union, we can assign both + // the same offset. Just avoid pushing them twice in the list. + ClassVectorTy& Classes = EmptyClassOffsets[Offset]; + if (std::find(Classes.begin(), Classes.end(), RD) != Classes.end()) + return; + + Classes.push_back(RD); + + // Update the empty class offset. + if (Offset > MaxEmptyClassOffset) + MaxEmptyClassOffset = Offset; +} + +bool +EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset) { + // We don't have to keep looking past the maximum offset that's known to + // contain an empty class. + if (!AnyEmptySubobjectsBeyondOffset(Offset)) + return true; + + if (!CanPlaceSubobjectAtOffset(Info->Class, Offset)) + return false; + + // Traverse all non-virtual bases. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { + BaseSubobjectInfo* Base = Info->Bases[I]; + if (Base->IsVirtual) + continue; + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + + if (!CanPlaceBaseSubobjectAtOffset(Base, BaseOffset)) + return false; + } + + if (Info->PrimaryVirtualBaseInfo) { + BaseSubobjectInfo *PrimaryVirtualBaseInfo = Info->PrimaryVirtualBaseInfo; + + if (Info == PrimaryVirtualBaseInfo->Derived) { + if (!CanPlaceBaseSubobjectAtOffset(PrimaryVirtualBaseInfo, Offset)) + return false; + } + } + + // Traverse all member variables. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(), + E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); + if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) + return false; + } + + return true; +} + +void EmptySubobjectMap::UpdateEmptyBaseSubobjects(const BaseSubobjectInfo *Info, + CharUnits Offset, + bool PlacingEmptyBase) { + if (!PlacingEmptyBase && Offset >= SizeOfLargestEmptySubobject) { + // We know that the only empty subobjects that can conflict with empty + // subobject of non-empty bases, are empty bases that can be placed at + // offset zero. Because of this, we only need to keep track of empty base + // subobjects with offsets less than the size of the largest empty + // subobject for our class. + return; + } + + AddSubobjectAtOffset(Info->Class, Offset); + + // Traverse all non-virtual bases. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { + BaseSubobjectInfo* Base = Info->Bases[I]; + if (Base->IsVirtual) + continue; + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + UpdateEmptyBaseSubobjects(Base, BaseOffset, PlacingEmptyBase); + } + + if (Info->PrimaryVirtualBaseInfo) { + BaseSubobjectInfo *PrimaryVirtualBaseInfo = Info->PrimaryVirtualBaseInfo; + + if (Info == PrimaryVirtualBaseInfo->Derived) + UpdateEmptyBaseSubobjects(PrimaryVirtualBaseInfo, Offset, + PlacingEmptyBase); + } + + // Traverse all member variables. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = Info->Class->field_begin(), + E = Info->Class->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); + UpdateEmptyFieldSubobjects(FD, FieldOffset); + } +} + +bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset) { + // If we know this class doesn't have any empty subobjects we don't need to + // bother checking. + if (SizeOfLargestEmptySubobject.isZero()) + return true; + + if (!CanPlaceBaseSubobjectAtOffset(Info, Offset)) + return false; + + // We are able to place the base at this offset. Make sure to update the + // empty base subobject map. + UpdateEmptyBaseSubobjects(Info, Offset, Info->Class->isEmpty()); + return true; +} + +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + CharUnits Offset) const { + // We don't have to keep looking past the maximum offset that's known to + // contain an empty class. + if (!AnyEmptySubobjectsBeyondOffset(Offset)) + return true; + + if (!CanPlaceSubobjectAtOffset(RD, Offset)) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Traverse all non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + if (!CanPlaceFieldSubobjectAtOffset(BaseDecl, Class, BaseOffset)) + return false; + } + + if (RD == Class) { + // This is the most derived class, traverse virtual bases as well. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *VBaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + if (!CanPlaceFieldSubobjectAtOffset(VBaseDecl, Class, VBaseOffset)) + return false; + } + } + + // Traverse all member variables. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); + + if (!CanPlaceFieldSubobjectAtOffset(FD, FieldOffset)) + return false; + } + + return true; +} + +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + CharUnits Offset) const { + // We don't have to keep looking past the maximum offset that's known to + // contain an empty class. + if (!AnyEmptySubobjectsBeyondOffset(Offset)) + return true; + + QualType T = FD->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + return CanPlaceFieldSubobjectAtOffset(RD, RD, Offset); + } + + // If we have an array type we need to look at every element. + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs<RecordType>(); + if (!RT) + return true; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); + CharUnits ElementOffset = Offset; + for (uint64_t I = 0; I != NumElements; ++I) { + // We don't have to keep looking past the maximum offset that's known to + // contain an empty class. + if (!AnyEmptySubobjectsBeyondOffset(ElementOffset)) + return true; + + if (!CanPlaceFieldSubobjectAtOffset(RD, RD, ElementOffset)) + return false; + + ElementOffset += Layout.getSize(); + } + } + + return true; +} + +bool +EmptySubobjectMap::CanPlaceFieldAtOffset(const FieldDecl *FD, + CharUnits Offset) { + if (!CanPlaceFieldSubobjectAtOffset(FD, Offset)) + return false; + + // We are able to place the member variable at this offset. + // Make sure to update the empty base subobject map. + UpdateEmptyFieldSubobjects(FD, Offset); + return true; +} + +void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + CharUnits Offset) { + // We know that the only empty subobjects that can conflict with empty + // field subobjects are subobjects of empty bases that can be placed at offset + // zero. Because of this, we only need to keep track of empty field + // subobjects with offsets less than the size of the largest empty + // subobject for our class. + if (Offset >= SizeOfLargestEmptySubobject) + return; + + AddSubobjectAtOffset(RD, Offset); + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Traverse all non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(BaseDecl); + UpdateEmptyFieldSubobjects(BaseDecl, Class, BaseOffset); + } + + if (RD == Class) { + // This is the most derived class, traverse virtual bases as well. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *VBaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBaseDecl); + UpdateEmptyFieldSubobjects(VBaseDecl, Class, VBaseOffset); + } + } + + // Traverse all member variables. + unsigned FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); + I != E; ++I, ++FieldNo) { + const FieldDecl *FD = *I; + if (FD->isBitField()) + continue; + + CharUnits FieldOffset = Offset + getFieldOffset(Layout, FieldNo); + + UpdateEmptyFieldSubobjects(FD, FieldOffset); + } +} + +void EmptySubobjectMap::UpdateEmptyFieldSubobjects(const FieldDecl *FD, + CharUnits Offset) { + QualType T = FD->getType(); + if (const RecordType *RT = T->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + UpdateEmptyFieldSubobjects(RD, RD, Offset); + return; + } + + // If we have an array type we need to update every element. + if (const ConstantArrayType *AT = Context.getAsConstantArrayType(T)) { + QualType ElemTy = Context.getBaseElementType(AT); + const RecordType *RT = ElemTy->getAs<RecordType>(); + if (!RT) + return; + + const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + uint64_t NumElements = Context.getConstantArrayElementCount(AT); + CharUnits ElementOffset = Offset; + + for (uint64_t I = 0; I != NumElements; ++I) { + // We know that the only empty subobjects that can conflict with empty + // field subobjects are subobjects of empty bases that can be placed at + // offset zero. Because of this, we only need to keep track of empty field + // subobjects with offsets less than the size of the largest empty + // subobject for our class. + if (ElementOffset >= SizeOfLargestEmptySubobject) + return; + + UpdateEmptyFieldSubobjects(RD, RD, ElementOffset); + ElementOffset += Layout.getSize(); + } + } +} + +class RecordLayoutBuilder { +protected: + // FIXME: Remove this and make the appropriate fields public. + friend class clang::ASTContext; + + const ASTContext &Context; + + EmptySubobjectMap *EmptySubobjects; + + /// Size - The current size of the record layout. + uint64_t Size; + + /// Alignment - The current alignment of the record layout. + CharUnits Alignment; + + /// \brief The alignment if attribute packed is not used. + CharUnits UnpackedAlignment; + + llvm::SmallVector<uint64_t, 16> FieldOffsets; + + /// Packed - Whether the record is packed or not. + unsigned Packed : 1; + + unsigned IsUnion : 1; + + unsigned IsMac68kAlign : 1; + + unsigned IsMsStruct : 1; + + /// UnfilledBitsInLastByte - If the last field laid out was a bitfield, + /// this contains the number of bits in the last byte that can be used for + /// an adjacent bitfield if necessary. + unsigned char UnfilledBitsInLastByte; + + /// MaxFieldAlignment - The maximum allowed field alignment. This is set by + /// #pragma pack. + CharUnits MaxFieldAlignment; + + /// DataSize - The data size of the record being laid out. + uint64_t DataSize; + + CharUnits NonVirtualSize; + CharUnits NonVirtualAlignment; + + FieldDecl *ZeroLengthBitfield; + + /// PrimaryBase - the primary base class (if one exists) of the class + /// we're laying out. + const CXXRecordDecl *PrimaryBase; + + /// PrimaryBaseIsVirtual - Whether the primary base of the class we're laying + /// out is virtual. + bool PrimaryBaseIsVirtual; + + typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; + + /// Bases - base classes and their offsets in the record. + BaseOffsetsMapTy Bases; + + // VBases - virtual base classes and their offsets in the record. + BaseOffsetsMapTy VBases; + + /// IndirectPrimaryBases - Virtual base classes, direct or indirect, that are + /// primary base classes for some other direct or indirect base class. + CXXIndirectPrimaryBaseSet IndirectPrimaryBases; + + /// FirstNearlyEmptyVBase - The first nearly empty virtual base class in + /// inheritance graph order. Used for determining the primary base class. + const CXXRecordDecl *FirstNearlyEmptyVBase; + + /// VisitedVirtualBases - A set of all the visited virtual bases, used to + /// avoid visiting virtual bases more than once. + llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; + + RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap + *EmptySubobjects) + : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), + Alignment(CharUnits::One()), UnpackedAlignment(Alignment), + Packed(false), IsUnion(false), + IsMac68kAlign(false), IsMsStruct(false), + UnfilledBitsInLastByte(0), MaxFieldAlignment(CharUnits::Zero()), + DataSize(0), NonVirtualSize(CharUnits::Zero()), + NonVirtualAlignment(CharUnits::One()), + ZeroLengthBitfield(0), PrimaryBase(0), + PrimaryBaseIsVirtual(false), FirstNearlyEmptyVBase(0) { } + + void Layout(const RecordDecl *D); + void Layout(const CXXRecordDecl *D); + void Layout(const ObjCInterfaceDecl *D); + + void LayoutFields(const RecordDecl *D); + void LayoutField(const FieldDecl *D); + void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize, + bool FieldPacked, const FieldDecl *D); + void LayoutBitField(const FieldDecl *D); + + /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. + llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; + + typedef llvm::DenseMap<const CXXRecordDecl *, BaseSubobjectInfo *> + BaseSubobjectInfoMapTy; + + /// VirtualBaseInfo - Map from all the (direct or indirect) virtual bases + /// of the class we're laying out to their base subobject info. + BaseSubobjectInfoMapTy VirtualBaseInfo; + + /// NonVirtualBaseInfo - Map from all the direct non-virtual bases of the + /// class we're laying out to their base subobject info. + BaseSubobjectInfoMapTy NonVirtualBaseInfo; + + /// ComputeBaseSubobjectInfo - Compute the base subobject information for the + /// bases of the given class. + void ComputeBaseSubobjectInfo(const CXXRecordDecl *RD); + + /// ComputeBaseSubobjectInfo - Compute the base subobject information for a + /// single class and all of its base classes. + BaseSubobjectInfo *ComputeBaseSubobjectInfo(const CXXRecordDecl *RD, + bool IsVirtual, + BaseSubobjectInfo *Derived); + + /// DeterminePrimaryBase - Determine the primary base of the given class. + void DeterminePrimaryBase(const CXXRecordDecl *RD); + + void SelectPrimaryVBase(const CXXRecordDecl *RD); + + virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; + + /// LayoutNonVirtualBases - Determines the primary base class (if any) and + /// lays it out. Will then proceed to lay out all non-virtual base clasess. + void LayoutNonVirtualBases(const CXXRecordDecl *RD); + + /// LayoutNonVirtualBase - Lays out a single non-virtual base. + void LayoutNonVirtualBase(const BaseSubobjectInfo *Base); + + void AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, + CharUnits Offset); + + /// LayoutVirtualBases - Lays out all the virtual bases. + void LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass); + + /// LayoutVirtualBase - Lays out a single virtual base. + void LayoutVirtualBase(const BaseSubobjectInfo *Base); + + /// LayoutBase - Will lay out a base and return the offset where it was + /// placed, in chars. + CharUnits LayoutBase(const BaseSubobjectInfo *Base); + + /// InitializeLayout - Initialize record layout for the given record decl. + void InitializeLayout(const Decl *D); + + /// FinishLayout - Finalize record layout. Adjust record size based on the + /// alignment. + void FinishLayout(const NamedDecl *D); + + void UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment); + void UpdateAlignment(CharUnits NewAlignment) { + UpdateAlignment(NewAlignment, NewAlignment); + } + + void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, + uint64_t UnpackedOffset, unsigned UnpackedAlign, + bool isPacked, const FieldDecl *D); + + DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); + + CharUnits getSize() const { + assert(Size % Context.getCharWidth() == 0); + return Context.toCharUnitsFromBits(Size); + } + uint64_t getSizeInBits() const { return Size; } + + void setSize(CharUnits NewSize) { Size = Context.toBits(NewSize); } + void setSize(uint64_t NewSize) { Size = NewSize; } + + CharUnits getDataSize() const { + assert(DataSize % Context.getCharWidth() == 0); + return Context.toCharUnitsFromBits(DataSize); + } + uint64_t getDataSizeInBits() const { return DataSize; } + + void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } + void setDataSize(uint64_t NewSize) { DataSize = NewSize; } + + + RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT + void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT +public: + static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); + + virtual ~RecordLayoutBuilder() { } +}; +} // end anonymous namespace + +void +RecordLayoutBuilder::SelectPrimaryVBase(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Check if this is a nearly empty virtual base. + if (I->isVirtual() && Context.isNearlyEmpty(Base)) { + // If it's not an indirect primary base, then we've found our primary + // base. + if (!IndirectPrimaryBases.count(Base)) { + PrimaryBase = Base; + PrimaryBaseIsVirtual = true; + return; + } + + // Is this the first nearly empty virtual base? + if (!FirstNearlyEmptyVBase) + FirstNearlyEmptyVBase = Base; + } + + SelectPrimaryVBase(Base); + if (PrimaryBase) + return; + } +} + +CharUnits +RecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + return Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); +} + +/// DeterminePrimaryBase - Determine the primary base of the given class. +void RecordLayoutBuilder::DeterminePrimaryBase(const CXXRecordDecl *RD) { + // If the class isn't dynamic, it won't have a primary base. + if (!RD->isDynamicClass()) + return; + + // Compute all the primary virtual bases for all of our direct and + // indirect bases, and record all their primary virtual base classes. + RD->getIndirectPrimaryBases(IndirectPrimaryBases); + + // If the record has a dynamic base class, attempt to choose a primary base + // class. It is the first (in direct base class order) non-virtual dynamic + // base class, if one exists. + for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(), + e = RD->bases_end(); i != e; ++i) { + // Ignore virtual bases. + if (i->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isDynamicClass()) { + // We found it. + PrimaryBase = Base; + PrimaryBaseIsVirtual = false; + return; + } + } + + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary virtual base class, if one exists. + if (RD->getNumVBases() != 0) { + SelectPrimaryVBase(RD); + if (PrimaryBase) + return; + } + + // Otherwise, it is the first nearly empty virtual base that is not an + // indirect primary virtual base class, if one exists. + if (FirstNearlyEmptyVBase) { + PrimaryBase = FirstNearlyEmptyVBase; + PrimaryBaseIsVirtual = true; + return; + } + + // Otherwise there is no primary base class. + assert(!PrimaryBase && "Should not get here with a primary base!"); + + // Allocate the virtual table pointer at offset zero. + assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); + + // Update the size. + setSize(getSize() + GetVirtualPointersSize(RD)); + setDataSize(getSize()); + + CharUnits UnpackedBaseAlign = + Context.toCharUnitsFromBits(Context.Target.getPointerAlign(0)); + CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + + // The maximum field alignment overrides base align. + if (!MaxFieldAlignment.isZero()) { + BaseAlign = std::min(BaseAlign, MaxFieldAlignment); + UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment); + } + + // Update the alignment. + UpdateAlignment(BaseAlign, UnpackedBaseAlign); +} + +BaseSubobjectInfo * +RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD, + bool IsVirtual, + BaseSubobjectInfo *Derived) { + BaseSubobjectInfo *Info; + + if (IsVirtual) { + // Check if we already have info about this virtual base. + BaseSubobjectInfo *&InfoSlot = VirtualBaseInfo[RD]; + if (InfoSlot) { + assert(InfoSlot->Class == RD && "Wrong class for virtual base info!"); + return InfoSlot; + } + + // We don't, create it. + InfoSlot = new (BaseSubobjectInfoAllocator.Allocate()) BaseSubobjectInfo; + Info = InfoSlot; + } else { + Info = new (BaseSubobjectInfoAllocator.Allocate()) BaseSubobjectInfo; + } + + Info->Class = RD; + Info->IsVirtual = IsVirtual; + Info->Derived = 0; + Info->PrimaryVirtualBaseInfo = 0; + + const CXXRecordDecl *PrimaryVirtualBase = 0; + BaseSubobjectInfo *PrimaryVirtualBaseInfo = 0; + + // Check if this base has a primary virtual base. + if (RD->getNumVBases()) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + if (Layout.isPrimaryBaseVirtual()) { + // This base does have a primary virtual base. + PrimaryVirtualBase = Layout.getPrimaryBase(); + assert(PrimaryVirtualBase && "Didn't have a primary virtual base!"); + + // Now check if we have base subobject info about this primary base. + PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase); + + if (PrimaryVirtualBaseInfo) { + if (PrimaryVirtualBaseInfo->Derived) { + // We did have info about this primary base, and it turns out that it + // has already been claimed as a primary virtual base for another + // base. + PrimaryVirtualBase = 0; + } else { + // We can claim this base as our primary base. + Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo; + PrimaryVirtualBaseInfo->Derived = Info; + } + } + } + } + + // Now go through all direct bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + bool IsVirtual = I->isVirtual(); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + Info->Bases.push_back(ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, Info)); + } + + if (PrimaryVirtualBase && !PrimaryVirtualBaseInfo) { + // Traversing the bases must have created the base info for our primary + // virtual base. + PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase); + assert(PrimaryVirtualBaseInfo && + "Did not create a primary virtual base!"); + + // Claim the primary virtual base as our primary virtual base. + Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo; + PrimaryVirtualBaseInfo->Derived = Info; + } + + return Info; +} + +void RecordLayoutBuilder::ComputeBaseSubobjectInfo(const CXXRecordDecl *RD) { + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + bool IsVirtual = I->isVirtual(); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Compute the base subobject info for this base. + BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, 0); + + if (IsVirtual) { + // ComputeBaseInfo has already added this base for us. + assert(VirtualBaseInfo.count(BaseDecl) && + "Did not add virtual base!"); + } else { + // Add the base info to the map of non-virtual bases. + assert(!NonVirtualBaseInfo.count(BaseDecl) && + "Non-virtual base already exists!"); + NonVirtualBaseInfo.insert(std::make_pair(BaseDecl, Info)); + } + } +} + +void +RecordLayoutBuilder::LayoutNonVirtualBases(const CXXRecordDecl *RD) { + // Then, determine the primary base class. + DeterminePrimaryBase(RD); + + // Compute base subobject info. + ComputeBaseSubobjectInfo(RD); + + // If we have a primary base class, lay it out. + if (PrimaryBase) { + if (PrimaryBaseIsVirtual) { + // If the primary virtual base was a primary virtual base of some other + // base class we'll have to steal it. + BaseSubobjectInfo *PrimaryBaseInfo = VirtualBaseInfo.lookup(PrimaryBase); + PrimaryBaseInfo->Derived = 0; + + // We have a virtual primary base, insert it as an indirect primary base. + IndirectPrimaryBases.insert(PrimaryBase); + + assert(!VisitedVirtualBases.count(PrimaryBase) && + "vbase already visited!"); + VisitedVirtualBases.insert(PrimaryBase); + + LayoutVirtualBase(PrimaryBaseInfo); + } else { + BaseSubobjectInfo *PrimaryBaseInfo = + NonVirtualBaseInfo.lookup(PrimaryBase); + assert(PrimaryBaseInfo && + "Did not find base info for non-virtual primary base!"); + + LayoutNonVirtualBase(PrimaryBaseInfo); + } + } + + // Now lay out the non-virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + + // Ignore virtual bases. + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + // Skip the primary base. + if (BaseDecl == PrimaryBase && !PrimaryBaseIsVirtual) + continue; + + // Lay out the base. + BaseSubobjectInfo *BaseInfo = NonVirtualBaseInfo.lookup(BaseDecl); + assert(BaseInfo && "Did not find base info for non-virtual base!"); + + LayoutNonVirtualBase(BaseInfo); + } +} + +void RecordLayoutBuilder::LayoutNonVirtualBase(const BaseSubobjectInfo *Base) { + // Layout the base. + CharUnits Offset = LayoutBase(Base); + + // Add its base class offset. + assert(!Bases.count(Base->Class) && "base offset already exists!"); + Bases.insert(std::make_pair(Base->Class, Offset)); + + AddPrimaryVirtualBaseOffsets(Base, Offset); +} + +void +RecordLayoutBuilder::AddPrimaryVirtualBaseOffsets(const BaseSubobjectInfo *Info, + CharUnits Offset) { + // This base isn't interesting, it has no virtual bases. + if (!Info->Class->getNumVBases()) + return; + + // First, check if we have a virtual primary base to add offsets for. + if (Info->PrimaryVirtualBaseInfo) { + assert(Info->PrimaryVirtualBaseInfo->IsVirtual && + "Primary virtual base is not virtual!"); + if (Info->PrimaryVirtualBaseInfo->Derived == Info) { + // Add the offset. + assert(!VBases.count(Info->PrimaryVirtualBaseInfo->Class) && + "primary vbase offset already exists!"); + VBases.insert(std::make_pair(Info->PrimaryVirtualBaseInfo->Class, + Offset)); + + // Traverse the primary virtual base. + AddPrimaryVirtualBaseOffsets(Info->PrimaryVirtualBaseInfo, Offset); + } + } + + // Now go through all direct non-virtual bases. + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Info->Class); + for (unsigned I = 0, E = Info->Bases.size(); I != E; ++I) { + const BaseSubobjectInfo *Base = Info->Bases[I]; + if (Base->IsVirtual) + continue; + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base->Class); + AddPrimaryVirtualBaseOffsets(Base, BaseOffset); + } +} + +void +RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, + const CXXRecordDecl *MostDerivedClass) { + const CXXRecordDecl *PrimaryBase; + bool PrimaryBaseIsVirtual; + + if (MostDerivedClass == RD) { + PrimaryBase = this->PrimaryBase; + PrimaryBaseIsVirtual = this->PrimaryBaseIsVirtual; + } else { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + PrimaryBase = Layout.getPrimaryBase(); + PrimaryBaseIsVirtual = Layout.isPrimaryBaseVirtual(); + } + + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + if (I->isVirtual()) { + if (PrimaryBase != BaseDecl || !PrimaryBaseIsVirtual) { + bool IndirectPrimaryBase = IndirectPrimaryBases.count(BaseDecl); + + // Only lay out the virtual base if it's not an indirect primary base. + if (!IndirectPrimaryBase) { + // Only visit virtual bases once. + if (!VisitedVirtualBases.insert(BaseDecl)) + continue; + + const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl); + assert(BaseInfo && "Did not find virtual base info!"); + LayoutVirtualBase(BaseInfo); + } + } + } + + if (!BaseDecl->getNumVBases()) { + // This base isn't interesting since it doesn't have any virtual bases. + continue; + } + + LayoutVirtualBases(BaseDecl, MostDerivedClass); + } +} + +void RecordLayoutBuilder::LayoutVirtualBase(const BaseSubobjectInfo *Base) { + assert(!Base->Derived && "Trying to lay out a primary virtual base!"); + + // Layout the base. + CharUnits Offset = LayoutBase(Base); + + // Add its base class offset. + assert(!VBases.count(Base->Class) && "vbase offset already exists!"); + VBases.insert(std::make_pair(Base->Class, Offset)); + + AddPrimaryVirtualBaseOffsets(Base, Offset); +} + +CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { + const ASTRecordLayout &Layout = Context.getASTRecordLayout(Base->Class); + + // If we have an empty base class, try to place it at offset 0. + if (Base->Class->isEmpty() && + EmptySubobjects->CanPlaceBaseAtOffset(Base, CharUnits::Zero())) { + setSize(std::max(getSize(), Layout.getSize())); + + return CharUnits::Zero(); + } + + CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlign(); + CharUnits BaseAlign = (Packed) ? CharUnits::One() : UnpackedBaseAlign; + + // The maximum field alignment overrides base align. + if (!MaxFieldAlignment.isZero()) { + BaseAlign = std::min(BaseAlign, MaxFieldAlignment); + UnpackedBaseAlign = std::min(UnpackedBaseAlign, MaxFieldAlignment); + } + + // Round up the current record size to the base's alignment boundary. + CharUnits Offset = getDataSize().RoundUpToAlignment(BaseAlign); + + // Try to place the base. + while (!EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset)) + Offset += BaseAlign; + + if (!Base->Class->isEmpty()) { + // Update the data size. + setDataSize(Offset + Layout.getNonVirtualSize()); + + setSize(std::max(getSize(), getDataSize())); + } else + setSize(std::max(getSize(), Offset + Layout.getSize())); + + // Remember max struct/class alignment. + UpdateAlignment(BaseAlign, UnpackedBaseAlign); + + return Offset; +} + +void RecordLayoutBuilder::InitializeLayout(const Decl *D) { + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) + IsUnion = RD->isUnion(); + + Packed = D->hasAttr<PackedAttr>(); + + IsMsStruct = D->hasAttr<MsStructAttr>(); + + // mac68k alignment supersedes maximum field alignment and attribute aligned, + // and forces all structures to have 2-byte alignment. The IBM docs on it + // allude to additional (more complicated) semantics, especially with regard + // to bit-fields, but gcc appears not to follow that. + if (D->hasAttr<AlignMac68kAttr>()) { + IsMac68kAlign = true; + MaxFieldAlignment = CharUnits::fromQuantity(2); + Alignment = CharUnits::fromQuantity(2); + } else { + if (const MaxFieldAlignmentAttr *MFAA = D->getAttr<MaxFieldAlignmentAttr>()) + MaxFieldAlignment = Context.toCharUnitsFromBits(MFAA->getAlignment()); + + if (unsigned MaxAlign = D->getMaxAlignment()) + UpdateAlignment(Context.toCharUnitsFromBits(MaxAlign)); + } +} + +void RecordLayoutBuilder::Layout(const RecordDecl *D) { + InitializeLayout(D); + LayoutFields(D); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(D); +} + +void RecordLayoutBuilder::Layout(const CXXRecordDecl *RD) { + InitializeLayout(RD); + + // Lay out the vtable and the non-virtual bases. + LayoutNonVirtualBases(RD); + + LayoutFields(RD); + + NonVirtualSize = Context.toCharUnitsFromBits( + llvm::RoundUpToAlignment(getSizeInBits(), + Context.Target.getCharAlign())); + NonVirtualAlignment = Alignment; + + // Lay out the virtual bases and add the primary virtual base offsets. + LayoutVirtualBases(RD, RD); + + VisitedVirtualBases.clear(); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(RD); + +#ifndef NDEBUG + // Check that we have base offsets for all bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + if (I->isVirtual()) + continue; + + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(Bases.count(BaseDecl) && "Did not find base offset!"); + } + + // And all virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + const CXXRecordDecl *BaseDecl = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + assert(VBases.count(BaseDecl) && "Did not find base offset!"); + } +#endif +} + +void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { + if (ObjCInterfaceDecl *SD = D->getSuperClass()) { + const ASTRecordLayout &SL = Context.getASTObjCInterfaceLayout(SD); + + UpdateAlignment(SL.getAlignment()); + + // We start laying out ivars not at the end of the superclass + // structure, but at the next byte following the last field. + setSize(SL.getDataSize()); + setDataSize(getSize()); + } + + InitializeLayout(D); + + // Layout each ivar sequentially. + llvm::SmallVector<ObjCIvarDecl*, 16> Ivars; + Context.ShallowCollectObjCIvars(D, Ivars); + for (unsigned i = 0, e = Ivars.size(); i != e; ++i) + LayoutField(Ivars[i]); + + // Finally, round the size of the total struct up to the alignment of the + // struct itself. + FinishLayout(D); +} + +void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { + // Layout each field, for now, just sequentially, respecting alignment. In + // the future, this will need to be tweakable by targets. + const FieldDecl *LastFD = 0; + ZeroLengthBitfield = 0; + unsigned RemainingInAlignment = 0; + for (RecordDecl::field_iterator Field = D->field_begin(), + FieldEnd = D->field_end(); Field != FieldEnd; ++Field) { + if (IsMsStruct) { + FieldDecl *FD = (*Field); + if (Context.ZeroBitfieldFollowsBitfield(FD, LastFD)) + ZeroLengthBitfield = FD; + // Zero-length bitfields following non-bitfield members are + // ignored: + else if (Context.ZeroBitfieldFollowsNonBitfield(FD, LastFD)) + continue; + // FIXME. streamline these conditions into a simple one. + else if (Context.BitfieldFollowsBitfield(FD, LastFD) || + Context.BitfieldFollowsNoneBitfield(FD, LastFD) || + Context.NoneBitfieldFollowsBitfield(FD, LastFD)) { + // 1) Adjacent bit fields are packed into the same 1-, 2-, or + // 4-byte allocation unit if the integral types are the same + // size and if the next bit field fits into the current + // allocation unit without crossing the boundary imposed by the + // common alignment requirements of the bit fields. + // 2) Establish a new alignment for a bitfield following + // a non-bitfield if size of their types differ. + // 3) Establish a new alignment for a non-bitfield following + // a bitfield if size of their types differ. + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + // This check is needed for 'long long' in -m32 mode. + if (TypeSize > FieldAlign) + FieldAlign = TypeSize; + FieldInfo = Context.getTypeInfo(LastFD->getType()); + uint64_t TypeSizeLastFD = FieldInfo.first; + unsigned FieldAlignLastFD = FieldInfo.second; + // This check is needed for 'long long' in -m32 mode. + if (TypeSizeLastFD > FieldAlignLastFD) + FieldAlignLastFD = TypeSizeLastFD; + + if (TypeSizeLastFD != TypeSize) { + if (RemainingInAlignment && + LastFD && LastFD->isBitField() && + LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + // If previous field was a bitfield with some remaining unfilled + // bits, pad the field so current field starts on its type boundary. + uint64_t FieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + RemainingInAlignment = 0; + } + + uint64_t UnpaddedFieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + FieldAlign = std::max(FieldAlign, FieldAlignLastFD); + + // The maximum field alignment overrides the aligned attribute. + if (!MaxFieldAlignment.isZero()) { + unsigned MaxFieldAlignmentInBits = + Context.toBits(MaxFieldAlignment); + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + } + + uint64_t NewSizeInBits = + llvm::RoundUpToAlignment(UnpaddedFieldOffset, FieldAlign); + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + } + if (FD->isBitField()) { + uint64_t FieldSize = + FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + assert (FieldSize > 0 && "LayoutFields - ms_struct layout"); + if (RemainingInAlignment < FieldSize) + RemainingInAlignment = TypeSize - FieldSize; + else + RemainingInAlignment -= FieldSize; + } + } + else if (FD->isBitField()) { + uint64_t FieldSize = + FD->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(FD->getType()); + uint64_t TypeSize = FieldInfo.first; + RemainingInAlignment = TypeSize - FieldSize; + } + LastFD = FD; + } + LayoutField(*Field); + } + if (IsMsStruct && RemainingInAlignment && + LastFD && LastFD->isBitField() && + LastFD->getBitWidth()->EvaluateAsInt(Context).getZExtValue()) { + // If we ended a bitfield before the full length of the type then + // pad the struct out to the full length of the last type. + uint64_t FieldOffset = + getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t NewSizeInBits = RemainingInAlignment + FieldOffset; + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + } +} + +void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, + uint64_t TypeSize, + bool FieldPacked, + const FieldDecl *D) { + assert(Context.getLangOptions().CPlusPlus && + "Can only have wide bit-fields in C++!"); + + // Itanium C++ ABI 2.4: + // If sizeof(T)*8 < n, let T' be the largest integral POD type with + // sizeof(T')*8 <= n. + + QualType IntegralPODTypes[] = { + Context.UnsignedCharTy, Context.UnsignedShortTy, Context.UnsignedIntTy, + Context.UnsignedLongTy, Context.UnsignedLongLongTy + }; + + QualType Type; + for (unsigned I = 0, E = llvm::array_lengthof(IntegralPODTypes); + I != E; ++I) { + uint64_t Size = Context.getTypeSize(IntegralPODTypes[I]); + + if (Size > FieldSize) + break; + + Type = IntegralPODTypes[I]; + } + assert(!Type.isNull() && "Did not find a type!"); + + CharUnits TypeAlign = Context.getTypeAlignInChars(Type); + + // We're not going to use any of the unfilled bits in the last byte. + UnfilledBitsInLastByte = 0; + + uint64_t FieldOffset; + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; + + if (IsUnion) { + setDataSize(std::max(getDataSizeInBits(), FieldSize)); + FieldOffset = 0; + } else { + // The bitfield is allocated starting at the next offset aligned appropriately + // for T', with length n bits. + FieldOffset = llvm::RoundUpToAlignment(getDataSizeInBits(), + Context.toBits(TypeAlign)); + + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + } + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, FieldOffset, + Context.toBits(TypeAlign), FieldPacked, D); + + // Update the size. + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + + // Remember max struct/class alignment. + UpdateAlignment(TypeAlign); +} + +void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { + bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; + uint64_t FieldOffset = IsUnion ? 0 : UnpaddedFieldOffset; + uint64_t FieldSize = D->getBitWidth()->EvaluateAsInt(Context).getZExtValue(); + + std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.first; + unsigned FieldAlign = FieldInfo.second; + + // This check is needed for 'long long' in -m32 mode. + if (IsMsStruct && (TypeSize > FieldAlign)) + FieldAlign = TypeSize; + + if (ZeroLengthBitfield) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + if (ZeroLengthBitfield != D) { + std::pair<uint64_t, unsigned> FieldInfo = + Context.getTypeInfo(ZeroLengthBitfield->getType()); + unsigned ZeroLengthBitfieldAlignment = FieldInfo.second; + // Ignore alignment of subsequent zero-length bitfields. + if ((ZeroLengthBitfieldAlignment > FieldAlign) || (FieldSize == 0)) + FieldAlign = ZeroLengthBitfieldAlignment; + if (FieldSize) + ZeroLengthBitfield = 0; + } + } + + if (FieldSize > TypeSize) { + LayoutWideBitField(FieldSize, TypeSize, FieldPacked, D); + return; + } + + // The align if the field is not packed. This is to check if the attribute + // was unnecessary (-Wpacked). + unsigned UnpackedFieldAlign = FieldAlign; + uint64_t UnpackedFieldOffset = FieldOffset; + if (!Context.Target.useBitFieldTypeAlignment()) + UnpackedFieldAlign = 1; + + if (FieldPacked || !Context.Target.useBitFieldTypeAlignment()) + FieldAlign = 1; + FieldAlign = std::max(FieldAlign, D->getMaxAlignment()); + UnpackedFieldAlign = std::max(UnpackedFieldAlign, D->getMaxAlignment()); + + // The maximum field alignment overrides the aligned attribute. + if (!MaxFieldAlignment.isZero()) { + unsigned MaxFieldAlignmentInBits = Context.toBits(MaxFieldAlignment); + FieldAlign = std::min(FieldAlign, MaxFieldAlignmentInBits); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignmentInBits); + } + + // Check if we need to add padding to give the field the correct alignment. + if (FieldSize == 0 || (FieldOffset & (FieldAlign-1)) + FieldSize > TypeSize) + FieldOffset = llvm::RoundUpToAlignment(FieldOffset, FieldAlign); + + if (FieldSize == 0 || + (UnpackedFieldOffset & (UnpackedFieldAlign-1)) + FieldSize > TypeSize) + UnpackedFieldOffset = llvm::RoundUpToAlignment(UnpackedFieldOffset, + UnpackedFieldAlign); + + // Padding members don't affect overall alignment. + if (!D->getIdentifier()) + FieldAlign = UnpackedFieldAlign = 1; + + // Place this field at the current location. + FieldOffsets.push_back(FieldOffset); + + CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset, + UnpackedFieldAlign, FieldPacked, D); + + // Update DataSize to include the last byte containing (part of) the bitfield. + if (IsUnion) { + // FIXME: I think FieldSize should be TypeSize here. + setDataSize(std::max(getDataSizeInBits(), FieldSize)); + } else { + uint64_t NewSizeInBits = FieldOffset + FieldSize; + + setDataSize(llvm::RoundUpToAlignment(NewSizeInBits, + Context.Target.getCharAlign())); + UnfilledBitsInLastByte = getDataSizeInBits() - NewSizeInBits; + } + + // Update the size. + setSize(std::max(getSizeInBits(), getDataSizeInBits())); + + // Remember max struct/class alignment. + UpdateAlignment(Context.toCharUnitsFromBits(FieldAlign), + Context.toCharUnitsFromBits(UnpackedFieldAlign)); +} + +void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { + if (D->isBitField()) { + LayoutBitField(D); + return; + } + + uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastByte; + + // Reset the unfilled bits. + UnfilledBitsInLastByte = 0; + + bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); + CharUnits FieldOffset = + IsUnion ? CharUnits::Zero() : getDataSize(); + CharUnits FieldSize; + CharUnits FieldAlign; + + if (D->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 = CharUnits::Zero(); + const ArrayType* ATy = Context.getAsArrayType(D->getType()); + FieldAlign = Context.getTypeAlignInChars(ATy->getElementType()); + } else if (const ReferenceType *RT = D->getType()->getAs<ReferenceType>()) { + unsigned AS = RT->getPointeeType().getAddressSpace(); + FieldSize = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(AS)); + FieldAlign = + Context.toCharUnitsFromBits(Context.Target.getPointerAlign(AS)); + } else { + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(D->getType()); + FieldSize = FieldInfo.first; + FieldAlign = FieldInfo.second; + + if (ZeroLengthBitfield) { + // If a zero-length bitfield is inserted after a bitfield, + // and the alignment of the zero-length bitfield is + // greater than the member that follows it, `bar', `bar' + // will be aligned as the type of the zero-length bitfield. + std::pair<CharUnits, CharUnits> FieldInfo = + Context.getTypeInfoInChars(ZeroLengthBitfield->getType()); + CharUnits ZeroLengthBitfieldAlignment = FieldInfo.second; + if (ZeroLengthBitfieldAlignment > FieldAlign) + FieldAlign = ZeroLengthBitfieldAlignment; + ZeroLengthBitfield = 0; + } + + if (Context.getLangOptions().MSBitfields || IsMsStruct) { + // If MS bitfield layout is required, figure out what type is being + // laid out and align the field to the width of that type. + + // Resolve all typedefs down to their base type and round up the field + // alignment if necessary. + QualType T = Context.getBaseElementType(D->getType()); + if (const BuiltinType *BTy = T->getAs<BuiltinType>()) { + CharUnits TypeSize = Context.getTypeSizeInChars(BTy); + if (TypeSize > FieldAlign) + FieldAlign = TypeSize; + } + } + } + + // The align if the field is not packed. This is to check if the attribute + // was unnecessary (-Wpacked). + CharUnits UnpackedFieldAlign = FieldAlign; + CharUnits UnpackedFieldOffset = FieldOffset; + + if (FieldPacked) + FieldAlign = CharUnits::One(); + CharUnits MaxAlignmentInChars = + Context.toCharUnitsFromBits(D->getMaxAlignment()); + FieldAlign = std::max(FieldAlign, MaxAlignmentInChars); + UnpackedFieldAlign = std::max(UnpackedFieldAlign, MaxAlignmentInChars); + + // The maximum field alignment overrides the aligned attribute. + if (!MaxFieldAlignment.isZero()) { + FieldAlign = std::min(FieldAlign, MaxFieldAlignment); + UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); + } + + // Round up the current record size to the field's alignment boundary. + FieldOffset = FieldOffset.RoundUpToAlignment(FieldAlign); + UnpackedFieldOffset = + UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign); + + if (!IsUnion && EmptySubobjects) { + // Check if we can place the field at this offset. + while (!EmptySubobjects->CanPlaceFieldAtOffset(D, FieldOffset)) { + // We couldn't place the field at the offset. Try again at a new offset. + FieldOffset += FieldAlign; + } + } + + // Place this field at the current location. + FieldOffsets.push_back(Context.toBits(FieldOffset)); + + CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset, + Context.toBits(UnpackedFieldOffset), + Context.toBits(UnpackedFieldAlign), FieldPacked, D); + + // Reserve space for this field. + uint64_t FieldSizeInBits = Context.toBits(FieldSize); + if (IsUnion) + setSize(std::max(getSizeInBits(), FieldSizeInBits)); + else + setSize(FieldOffset + FieldSize); + + // Update the data size. + setDataSize(getSizeInBits()); + + // Remember max struct/class alignment. + UpdateAlignment(FieldAlign, UnpackedFieldAlign); +} + +void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { + // In C++, records cannot be of size 0. + if (Context.getLangOptions().CPlusPlus && getSizeInBits() == 0) { + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + // Compatibility with gcc requires a class (pod or non-pod) + // which is not empty but of size 0; such as having fields of + // array of zero-length, remains of Size 0 + if (RD->isEmpty()) + setSize(CharUnits::One()); + } + else + setSize(CharUnits::One()); + } + // Finally, round the size of the record up to the alignment of the + // record itself. + uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpackedSizeInBits = + llvm::RoundUpToAlignment(getSizeInBits(), + Context.toBits(UnpackedAlignment)); + CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); + setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); + + unsigned CharBitNum = Context.Target.getCharWidth(); + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { + // Warn if padding was introduced to the struct/class/union. + if (getSizeInBits() > UnpaddedSize) { + unsigned PadSize = getSizeInBits() - UnpaddedSize; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + Diag(RD->getLocation(), diag::warn_padded_struct_size) + << Context.getTypeDeclType(RD) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not + } + + // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // bother since there won't be alignment issues. + if (Packed && UnpackedAlignment > CharUnits::One() && + getSize() == UnpackedSize) + Diag(D->getLocation(), diag::warn_unnecessary_packed) + << Context.getTypeDeclType(RD); + } +} + +void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment, + CharUnits UnpackedNewAlignment) { + // The alignment is not modified when using 'mac68k' alignment. + if (IsMac68kAlign) + return; + + if (NewAlignment > Alignment) { + assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() && + "Alignment not a power of 2")); + Alignment = NewAlignment; + } + + if (UnpackedNewAlignment > UnpackedAlignment) { + assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() && + "Alignment not a power of 2")); + UnpackedAlignment = UnpackedNewAlignment; + } +} + +void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, + uint64_t UnpaddedOffset, + uint64_t UnpackedOffset, + unsigned UnpackedAlign, + bool isPacked, + const FieldDecl *D) { + // We let objc ivars without warning, objc interfaces generally are not used + // for padding tricks. + if (isa<ObjCIvarDecl>(D)) + return; + + unsigned CharBitNum = Context.Target.getCharWidth(); + + // Warn if padding was introduced to the struct/class. + if (!IsUnion && Offset > UnpaddedOffset) { + unsigned PadSize = Offset - UnpaddedOffset; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + if (D->getIdentifier()) + Diag(D->getLocation(), diag::warn_padded_struct_field) + << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not + << D->getIdentifier(); + else + Diag(D->getLocation(), diag::warn_padded_struct_anon_field) + << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << Context.getTypeDeclType(D->getParent()) + << PadSize + << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not + } + + // Warn if we packed it unnecessarily. If the alignment is 1 byte don't + // bother since there won't be alignment issues. + if (isPacked && UnpackedAlign > CharBitNum && Offset == UnpackedOffset) + Diag(D->getLocation(), diag::warn_unnecessary_packed) + << D->getIdentifier(); +} + +const CXXMethodDecl * +RecordLayoutBuilder::ComputeKeyFunction(const CXXRecordDecl *RD) { + // If a class isn't polymorphic it doesn't have a key function. + if (!RD->isPolymorphic()) + return 0; + + // A class that is not externally visible doesn't have a key function. (Or + // at least, there's no point to assigning a key function to such a class; + // this doesn't affect the ABI.) + if (RD->getLinkage() != ExternalLinkage) + return 0; + + // Template instantiations don't have key functions,see Itanium C++ ABI 5.2.6. + // Same behavior as GCC. + TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind(); + if (TSK == TSK_ImplicitInstantiation || + TSK == TSK_ExplicitInstantiationDefinition) + return 0; + + for (CXXRecordDecl::method_iterator I = RD->method_begin(), + E = RD->method_end(); I != E; ++I) { + const CXXMethodDecl *MD = *I; + + if (!MD->isVirtual()) + continue; + + if (MD->isPure()) + continue; + + // Ignore implicit member functions, they are always marked as inline, but + // they don't have a body until they're defined. + if (MD->isImplicit()) + continue; + + if (MD->isInlineSpecified()) + continue; + + if (MD->hasInlineBody()) + continue; + + // We found it. + return MD; + } + + return 0; +} + +DiagnosticBuilder +RecordLayoutBuilder::Diag(SourceLocation Loc, unsigned DiagID) { + return Context.getDiagnostics().Report(Loc, DiagID); +} + +namespace { + // This class implements layout specific to the Microsoft ABI. + class MSRecordLayoutBuilder : public RecordLayoutBuilder { + public: + MSRecordLayoutBuilder(const ASTContext& Ctx, + EmptySubobjectMap *EmptySubobjects) : + RecordLayoutBuilder(Ctx, EmptySubobjects) {} + + virtual CharUnits GetVirtualPointersSize(const CXXRecordDecl *RD) const; + }; +} + +CharUnits +MSRecordLayoutBuilder::GetVirtualPointersSize(const CXXRecordDecl *RD) const { + // We should reserve space for two pointers if the class has both + // virtual functions and virtual bases. + CharUnits PointerWidth = + Context.toCharUnitsFromBits(Context.Target.getPointerWidth(0)); + if (RD->isPolymorphic() && RD->getNumVBases() > 0) + return 2 * PointerWidth; + return PointerWidth; +} + +/// 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) const { + D = D->getDefinition(); + assert(D && "Cannot get layout of forward declarations!"); + + // Look up this layout, if already laid out, return what we have. + // Note that we can't save a reference to the entry because this function + // is recursive. + const ASTRecordLayout *Entry = ASTRecordLayouts[D]; + if (Entry) return *Entry; + + const ASTRecordLayout *NewEntry; + + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { + EmptySubobjectMap EmptySubobjects(*this, RD); + + // When compiling for Microsoft, use the special MS builder. + llvm::OwningPtr<RecordLayoutBuilder> Builder; + switch (Target.getCXXABI()) { + default: + Builder.reset(new RecordLayoutBuilder(*this, &EmptySubobjects)); + break; + case CXXABI_Microsoft: + Builder.reset(new MSRecordLayoutBuilder(*this, &EmptySubobjects)); + } + // Recover resources if we crash before exiting this method. + llvm::CrashRecoveryContextCleanupRegistrar<RecordLayoutBuilder> + RecordBuilderCleanup(Builder.get()); + + Builder->Layout(RD); + + // FIXME: This is not always correct. See the part about bitfields at + // http://www.codesourcery.com/public/cxx-abi/abi.html#POD for more info. + // FIXME: IsPODForThePurposeOfLayout should be stored in the record layout. + bool IsPODForThePurposeOfLayout = cast<CXXRecordDecl>(D)->isPOD(); + + // FIXME: This should be done in FinalizeLayout. + CharUnits DataSize = + IsPODForThePurposeOfLayout ? Builder->getSize() : Builder->getDataSize(); + CharUnits NonVirtualSize = + IsPODForThePurposeOfLayout ? DataSize : Builder->NonVirtualSize; + + NewEntry = + new (*this) ASTRecordLayout(*this, Builder->getSize(), + Builder->Alignment, + DataSize, + Builder->FieldOffsets.data(), + Builder->FieldOffsets.size(), + NonVirtualSize, + Builder->NonVirtualAlignment, + EmptySubobjects.SizeOfLargestEmptySubobject, + Builder->PrimaryBase, + Builder->PrimaryBaseIsVirtual, + Builder->Bases, Builder->VBases); + } else { + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + Builder.Layout(D); + + NewEntry = + new (*this) ASTRecordLayout(*this, Builder.getSize(), + Builder.Alignment, + Builder.getSize(), + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + } + + ASTRecordLayouts[D] = NewEntry; + + if (getLangOptions().DumpRecordLayouts) { + llvm::errs() << "\n*** Dumping AST Record Layout\n"; + DumpRecordLayout(D, llvm::errs()); + } + + return *NewEntry; +} + +const CXXMethodDecl *ASTContext::getKeyFunction(const CXXRecordDecl *RD) { + RD = cast<CXXRecordDecl>(RD->getDefinition()); + assert(RD && "Cannot get key function for forward declarations!"); + + const CXXMethodDecl *&Entry = KeyFunctions[RD]; + if (!Entry) + Entry = RecordLayoutBuilder::ComputeKeyFunction(RD); + + return Entry; +} + +/// 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) const { + 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; + + // Add in synthesized ivar count if laying out an implementation. + if (Impl) { + unsigned SynthCount = CountNonClassIvars(D); + // 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 (SynthCount == 0) + return getObjCLayout(D, 0); + } + + RecordLayoutBuilder Builder(*this, /*EmptySubobjects=*/0); + Builder.Layout(D); + + const ASTRecordLayout *NewEntry = + new (*this) ASTRecordLayout(*this, Builder.getSize(), + Builder.Alignment, + Builder.getDataSize(), + Builder.FieldOffsets.data(), + Builder.FieldOffsets.size()); + + ObjCLayouts[Key] = NewEntry; + + return *NewEntry; +} + +static void PrintOffset(llvm::raw_ostream &OS, + CharUnits Offset, unsigned IndentLevel) { + OS << llvm::format("%4d | ", Offset.getQuantity()); + OS.indent(IndentLevel * 2); +} + +static void DumpCXXRecordLayout(llvm::raw_ostream &OS, + const CXXRecordDecl *RD, const ASTContext &C, + CharUnits Offset, + unsigned IndentLevel, + const char* Description, + bool IncludeVirtualBases) { + const ASTRecordLayout &Layout = C.getASTRecordLayout(RD); + + PrintOffset(OS, Offset, IndentLevel); + OS << C.getTypeDeclType(const_cast<CXXRecordDecl *>(RD)).getAsString(); + if (Description) + OS << ' ' << Description; + if (RD->isEmpty()) + OS << " (empty)"; + OS << '\n'; + + IndentLevel++; + + const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase(); + + // Vtable pointer. + if (RD->isDynamicClass() && !PrimaryBase) { + PrintOffset(OS, Offset, IndentLevel); + OS << '(' << RD << " vtable pointer)\n"; + } + // Dump (non-virtual) bases + for (CXXRecordDecl::base_class_const_iterator I = RD->bases_begin(), + E = RD->bases_end(); I != E; ++I) { + assert(!I->getType()->isDependentType() && + "Cannot layout class with dependent bases."); + if (I->isVirtual()) + continue; + + const CXXRecordDecl *Base = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base); + + DumpCXXRecordLayout(OS, Base, C, BaseOffset, IndentLevel, + Base == PrimaryBase ? "(primary base)" : "(base)", + /*IncludeVirtualBases=*/false); + } + + // Dump fields. + uint64_t FieldNo = 0; + for (CXXRecordDecl::field_iterator I = RD->field_begin(), + E = RD->field_end(); I != E; ++I, ++FieldNo) { + const FieldDecl *Field = *I; + CharUnits FieldOffset = Offset + + C.toCharUnitsFromBits(Layout.getFieldOffset(FieldNo)); + + if (const RecordType *RT = Field->getType()->getAs<RecordType>()) { + if (const CXXRecordDecl *D = dyn_cast<CXXRecordDecl>(RT->getDecl())) { + DumpCXXRecordLayout(OS, D, C, FieldOffset, IndentLevel, + Field->getName().data(), + /*IncludeVirtualBases=*/true); + continue; + } + } + + PrintOffset(OS, FieldOffset, IndentLevel); + OS << Field->getType().getAsString() << ' ' << Field << '\n'; + } + + if (!IncludeVirtualBases) + return; + + // Dump virtual bases. + for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), + E = RD->vbases_end(); I != E; ++I) { + assert(I->isVirtual() && "Found non-virtual class!"); + const CXXRecordDecl *VBase = + cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + + CharUnits VBaseOffset = Offset + Layout.getVBaseClassOffset(VBase); + DumpCXXRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, + VBase == PrimaryBase ? + "(primary virtual base)" : "(virtual base)", + /*IncludeVirtualBases=*/false); + } + + OS << " sizeof=" << Layout.getSize().getQuantity(); + OS << ", dsize=" << Layout.getDataSize().getQuantity(); + OS << ", align=" << Layout.getAlignment().getQuantity() << '\n'; + OS << " nvsize=" << Layout.getNonVirtualSize().getQuantity(); + OS << ", nvalign=" << Layout.getNonVirtualAlign().getQuantity() << '\n'; + OS << '\n'; +} + +void ASTContext::DumpRecordLayout(const RecordDecl *RD, + llvm::raw_ostream &OS) const { + const ASTRecordLayout &Info = getASTRecordLayout(RD); + + if (const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + return DumpCXXRecordLayout(OS, CXXRD, *this, CharUnits(), 0, 0, + /*IncludeVirtualBases=*/true); + + OS << "Type: " << getTypeDeclType(RD).getAsString() << "\n"; + OS << "Record: "; + RD->dump(); + OS << "\nLayout: "; + OS << "<ASTRecordLayout\n"; + OS << " Size:" << toBits(Info.getSize()) << "\n"; + OS << " DataSize:" << toBits(Info.getDataSize()) << "\n"; + OS << " Alignment:" << toBits(Info.getAlignment()) << "\n"; + OS << " FieldOffsets: ["; + for (unsigned i = 0, e = Info.getFieldCount(); i != e; ++i) { + if (i) OS << ", "; + OS << Info.getFieldOffset(i); + } + OS << "]>\n"; +} diff --git a/contrib/llvm/tools/clang/lib/AST/Stmt.cpp b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp new file mode 100644 index 000000000000..380ad94ca224 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Stmt.cpp @@ -0,0 +1,770 @@ +//===--- 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" +#include "clang/Basic/TargetInfo.h" +#include <cstdio> +using namespace clang; + +static struct StmtClassNameTable { + const char *Name; + unsigned Counter; + unsigned Size; +} StmtClassInfo[Stmt::lastStmtConstant+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 ABSTRACT_STMT(STMT) +#define STMT(CLASS, PARENT) \ + StmtClassInfo[(unsigned)Stmt::CLASS##Class].Name = #CLASS; \ + StmtClassInfo[(unsigned)Stmt::CLASS##Class].Size = sizeof(CLASS); +#include "clang/AST/StmtNodes.inc" + + return StmtClassInfo[E]; +} + +const char *Stmt::getStmtClassName() const { + return getStmtInfoTableEntry((StmtClass) StmtBits.sClass).Name; +} + +void Stmt::PrintStats() { + // Ensure the table is primed. + getStmtInfoTableEntry(Stmt::NullStmtClass); + + unsigned sum = 0; + fprintf(stderr, "*** Stmt/Expr Stats:\n"); + for (int i = 0; i != Stmt::lastStmtConstant+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::lastStmtConstant+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; +} + +namespace { + struct good {}; + struct bad {}; + + // These silly little functions have to be static inline to suppress + // unused warnings, and they have to be defined to suppress other + // warnings. + static inline good is_good(good) { return good(); } + + typedef Stmt::child_range children_t(); + template <class T> good implements_children(children_t T::*) { + return good(); + } + static inline bad implements_children(children_t Stmt::*) { + return bad(); + } + + typedef SourceRange getSourceRange_t() const; + template <class T> good implements_getSourceRange(getSourceRange_t T::*) { + return good(); + } + static inline bad implements_getSourceRange(getSourceRange_t Stmt::*) { + return bad(); + } + +#define ASSERT_IMPLEMENTS_children(type) \ + (void) sizeof(is_good(implements_children(&type::children))) +#define ASSERT_IMPLEMENTS_getSourceRange(type) \ + (void) sizeof(is_good(implements_getSourceRange(&type::getSourceRange))) +} + +/// Check whether the various Stmt classes implement their member +/// functions. +static inline void check_implementations() { +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + ASSERT_IMPLEMENTS_children(type); \ + ASSERT_IMPLEMENTS_getSourceRange(type); +#include "clang/AST/StmtNodes.inc" +} + +Stmt::child_range Stmt::children() { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<type*>(this)->children(); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind!"); + return child_range(); +} + +SourceRange Stmt::getSourceRange() const { + switch (getStmtClass()) { + case Stmt::NoStmtClass: llvm_unreachable("statement without class"); +#define ABSTRACT_STMT(type) +#define STMT(type, base) \ + case Stmt::type##Class: \ + return static_cast<const type*>(this)->getSourceRange(); +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("unknown statement kind!"); + return SourceRange(); +} + +void CompoundStmt::setStmts(ASTContext &C, Stmt **Stmts, unsigned NumStmts) { + if (this->Body) + C.Deallocate(Body); + this->CompoundStmtBits.NumStmts = NumStmts; + + Body = new (C) Stmt*[NumStmts]; + memcpy(Body, Stmts, sizeof(Stmt *) * NumStmts); +} + +const char *LabelStmt::getName() const { + return getDecl()->getIdentifier()->getNameStart(); +} + +// 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 (StmtBits.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() == BO_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 '+'). +llvm::StringRef AsmStmt::getOutputConstraint(unsigned i) const { + return getOutputConstraintLiteral(i)->getString(); +} + +/// 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]); +} +void AsmStmt::setInputExpr(unsigned i, Expr *E) { + Exprs[i + NumOutputs] = E; +} + + +/// getInputConstraint - Return the specified input constraint. Unlike output +/// constraints, these can be empty. +llvm::StringRef AsmStmt::getInputConstraint(unsigned i) const { + return getInputConstraintLiteral(i)->getString(); +} + + +void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, + IdentifierInfo **Names, + StringLiteral **Constraints, + Stmt **Exprs, + unsigned NumOutputs, + unsigned NumInputs, + StringLiteral **Clobbers, + unsigned NumClobbers) { + this->NumOutputs = NumOutputs; + this->NumInputs = NumInputs; + this->NumClobbers = NumClobbers; + + unsigned NumExprs = NumOutputs + NumInputs; + + C.Deallocate(this->Names); + this->Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(Names, Names + NumExprs, this->Names); + + C.Deallocate(this->Exprs); + this->Exprs = new (C) Stmt*[NumExprs]; + std::copy(Exprs, Exprs + NumExprs, this->Exprs); + + C.Deallocate(this->Constraints); + this->Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(Constraints, Constraints + NumExprs, this->Constraints); + + C.Deallocate(this->Clobbers); + this->Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(Clobbers, Clobbers + NumClobbers, this->Clobbers); +} + +/// 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(llvm::StringRef 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; +} + +/// 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 { + llvm::StringRef Str = getAsmString()->getString(); + const char *StrStart = Str.begin(); + const char *StrEnd = Str.end(); + 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; + + bool HasVariants = !C.Target.hasNoAsmVariants(); + + while (1) { + // Done with the string? + if (CurPtr == StrEnd) { + if (!CurStringPiece.empty()) + Pieces.push_back(AsmStringPiece(CurStringPiece)); + return 0; + } + + char CurChar = *CurPtr++; + switch (CurChar) { + case '$': CurStringPiece += "$$"; continue; + case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; + case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; + case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; + case '%': + break; + default: + 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; + + llvm::StringRef SymbolicName(CurPtr, NameEnd - CurPtr); + + 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; + } +} + +QualType CXXCatchStmt::getCaughtType() const { + if (ExceptionDecl) + return ExceptionDecl->getType(); + return QualType(); +} + +//===----------------------------------------------------------------------===// +// Constructors +//===----------------------------------------------------------------------===// + +AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, bool msasm, + unsigned numoutputs, unsigned numinputs, + IdentifierInfo **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), MSAsm(msasm) + , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { + + unsigned NumExprs = NumOutputs +NumInputs; + + Names = new (C) IdentifierInfo*[NumExprs]; + std::copy(names, names + NumExprs, Names); + + Exprs = new (C) Stmt*[NumExprs]; + std::copy(exprs, exprs + NumExprs, Exprs); + + Constraints = new (C) StringLiteral*[NumExprs]; + std::copy(constraints, constraints + NumExprs, Constraints); + + Clobbers = new (C) StringLiteral*[NumClobbers]; + std::copy(clobbers, clobbers + NumClobbers, Clobbers); +} + +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; +} + +ObjCAtTryStmt::ObjCAtTryStmt(SourceLocation atTryLoc, Stmt *atTryStmt, + Stmt **CatchStmts, unsigned NumCatchStmts, + Stmt *atFinallyStmt) + : Stmt(ObjCAtTryStmtClass), AtTryLoc(atTryLoc), + NumCatchStmts(NumCatchStmts), HasFinally(atFinallyStmt != 0) +{ + Stmt **Stmts = getStmts(); + Stmts[0] = atTryStmt; + for (unsigned I = 0; I != NumCatchStmts; ++I) + Stmts[I + 1] = CatchStmts[I]; + + if (HasFinally) + Stmts[NumCatchStmts + 1] = atFinallyStmt; +} + +ObjCAtTryStmt *ObjCAtTryStmt::Create(ASTContext &Context, + SourceLocation atTryLoc, + Stmt *atTryStmt, + Stmt **CatchStmts, + unsigned NumCatchStmts, + Stmt *atFinallyStmt) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + (atFinallyStmt != 0)) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>()); + return new (Mem) ObjCAtTryStmt(atTryLoc, atTryStmt, CatchStmts, NumCatchStmts, + atFinallyStmt); +} + +ObjCAtTryStmt *ObjCAtTryStmt::CreateEmpty(ASTContext &Context, + unsigned NumCatchStmts, + bool HasFinally) { + unsigned Size = sizeof(ObjCAtTryStmt) + + (1 + NumCatchStmts + HasFinally) * sizeof(Stmt *); + void *Mem = Context.Allocate(Size, llvm::alignOf<ObjCAtTryStmt>()); + return new (Mem) ObjCAtTryStmt(EmptyShell(), NumCatchStmts, HasFinally); +} + +SourceRange ObjCAtTryStmt::getSourceRange() const { + SourceLocation EndLoc; + if (HasFinally) + EndLoc = getFinallyStmt()->getLocEnd(); + else if (NumCatchStmts) + EndLoc = getCatchStmt(NumCatchStmts - 1)->getLocEnd(); + else + EndLoc = getTryBody()->getLocEnd(); + + return SourceRange(AtTryLoc, EndLoc); +} + +CXXTryStmt *CXXTryStmt::Create(ASTContext &C, SourceLocation tryLoc, + Stmt *tryBlock, Stmt **handlers, + unsigned numHandlers) { + std::size_t Size = sizeof(CXXTryStmt); + Size += ((numHandlers + 1) * sizeof(Stmt)); + + void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>()); + return new (Mem) CXXTryStmt(tryLoc, tryBlock, handlers, numHandlers); +} + +CXXTryStmt *CXXTryStmt::Create(ASTContext &C, EmptyShell Empty, + unsigned numHandlers) { + std::size_t Size = sizeof(CXXTryStmt); + Size += ((numHandlers + 1) * sizeof(Stmt)); + + void *Mem = C.Allocate(Size, llvm::alignOf<CXXTryStmt>()); + return new (Mem) CXXTryStmt(Empty, numHandlers); +} + +CXXTryStmt::CXXTryStmt(SourceLocation tryLoc, Stmt *tryBlock, + Stmt **handlers, unsigned numHandlers) + : Stmt(CXXTryStmtClass), TryLoc(tryLoc), NumHandlers(numHandlers) { + Stmt **Stmts = reinterpret_cast<Stmt **>(this + 1); + Stmts[0] = tryBlock; + std::copy(handlers, handlers + NumHandlers, Stmts + 1); +} + +CXXForRangeStmt::CXXForRangeStmt(DeclStmt *Range, DeclStmt *BeginEndStmt, + Expr *Cond, Expr *Inc, DeclStmt *LoopVar, + Stmt *Body, SourceLocation FL, + SourceLocation CL, SourceLocation RPL) + : Stmt(CXXForRangeStmtClass), ForLoc(FL), ColonLoc(CL), RParenLoc(RPL) { + SubExprs[RANGE] = Range; + SubExprs[BEGINEND] = BeginEndStmt; + SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); + SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[LOOPVAR] = LoopVar; + SubExprs[BODY] = Body; +} + +Expr *CXXForRangeStmt::getRangeInit() { + DeclStmt *RangeStmt = getRangeStmt(); + VarDecl *RangeDecl = dyn_cast_or_null<VarDecl>(RangeStmt->getSingleDecl()); + assert(RangeDecl &&& "for-range should have a single var decl"); + return RangeDecl->getInit(); +} + +const Expr *CXXForRangeStmt::getRangeInit() const { + return const_cast<CXXForRangeStmt*>(this)->getRangeInit(); +} + +VarDecl *CXXForRangeStmt::getLoopVariable() { + Decl *LV = cast<DeclStmt>(getLoopVarStmt())->getSingleDecl(); + assert(LV && "No loop variable in CXXForRangeStmt"); + return cast<VarDecl>(LV); +} + +const VarDecl *CXXForRangeStmt::getLoopVariable() const { + return const_cast<CXXForRangeStmt*>(this)->getLoopVariable(); +} + +IfStmt::IfStmt(ASTContext &C, SourceLocation IL, VarDecl *var, Expr *cond, + Stmt *then, SourceLocation EL, Stmt *elsev) + : Stmt(IfStmtClass), IfLoc(IL), ElseLoc(EL) +{ + setConditionVariable(C, var); + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[THEN] = then; + SubExprs[ELSE] = elsev; +} + +VarDecl *IfStmt::getConditionVariable() const { + if (!SubExprs[VAR]) + return 0; + + DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + return cast<VarDecl>(DS->getSingleDecl()); +} + +void IfStmt::setConditionVariable(ASTContext &C, VarDecl *V) { + if (!V) { + SubExprs[VAR] = 0; + return; + } + + SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), + V->getSourceRange().getBegin(), + V->getSourceRange().getEnd()); +} + +ForStmt::ForStmt(ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, + Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, + SourceLocation RP) + : Stmt(ForStmtClass), ForLoc(FL), LParenLoc(LP), RParenLoc(RP) +{ + SubExprs[INIT] = Init; + setConditionVariable(C, condVar); + SubExprs[COND] = reinterpret_cast<Stmt*>(Cond); + SubExprs[INC] = reinterpret_cast<Stmt*>(Inc); + SubExprs[BODY] = Body; +} + +VarDecl *ForStmt::getConditionVariable() const { + if (!SubExprs[CONDVAR]) + return 0; + + DeclStmt *DS = cast<DeclStmt>(SubExprs[CONDVAR]); + return cast<VarDecl>(DS->getSingleDecl()); +} + +void ForStmt::setConditionVariable(ASTContext &C, VarDecl *V) { + if (!V) { + SubExprs[CONDVAR] = 0; + return; + } + + SubExprs[CONDVAR] = new (C) DeclStmt(DeclGroupRef(V), + V->getSourceRange().getBegin(), + V->getSourceRange().getEnd()); +} + +SwitchStmt::SwitchStmt(ASTContext &C, VarDecl *Var, Expr *cond) + : Stmt(SwitchStmtClass), FirstCase(0), AllEnumCasesCovered(0) +{ + setConditionVariable(C, Var); + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = NULL; +} + +VarDecl *SwitchStmt::getConditionVariable() const { + if (!SubExprs[VAR]) + return 0; + + DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + return cast<VarDecl>(DS->getSingleDecl()); +} + +void SwitchStmt::setConditionVariable(ASTContext &C, VarDecl *V) { + if (!V) { + SubExprs[VAR] = 0; + return; + } + + SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), + V->getSourceRange().getBegin(), + V->getSourceRange().getEnd()); +} + +Stmt *SwitchCase::getSubStmt() { + if (isa<CaseStmt>(this)) + return cast<CaseStmt>(this)->getSubStmt(); + return cast<DefaultStmt>(this)->getSubStmt(); +} + +WhileStmt::WhileStmt(ASTContext &C, VarDecl *Var, Expr *cond, Stmt *body, + SourceLocation WL) + : Stmt(WhileStmtClass) { + setConditionVariable(C, Var); + SubExprs[COND] = reinterpret_cast<Stmt*>(cond); + SubExprs[BODY] = body; + WhileLoc = WL; +} + +VarDecl *WhileStmt::getConditionVariable() const { + if (!SubExprs[VAR]) + return 0; + + DeclStmt *DS = cast<DeclStmt>(SubExprs[VAR]); + return cast<VarDecl>(DS->getSingleDecl()); +} + +void WhileStmt::setConditionVariable(ASTContext &C, VarDecl *V) { + if (!V) { + SubExprs[VAR] = 0; + return; + } + + SubExprs[VAR] = new (C) DeclStmt(DeclGroupRef(V), + V->getSourceRange().getBegin(), + V->getSourceRange().getEnd()); +} + +// IndirectGotoStmt +LabelDecl *IndirectGotoStmt::getConstantTarget() { + if (AddrLabelExpr *E = + dyn_cast<AddrLabelExpr>(getTarget()->IgnoreParenImpCasts())) + return E->getLabel(); + return 0; +} + +// ReturnStmt +const Expr* ReturnStmt::getRetValue() const { + return cast_or_null<Expr>(RetExpr); +} +Expr* ReturnStmt::getRetValue() { + return cast_or_null<Expr>(RetExpr); +} + +SEHTryStmt::SEHTryStmt(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) + : Stmt(SEHTryStmtClass), + IsCXXTry(IsCXXTry), + TryLoc(TryLoc) +{ + Children[TRY] = TryBlock; + Children[HANDLER] = Handler; +} + +SEHTryStmt* SEHTryStmt::Create(ASTContext &C, + bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) { + return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler); +} + +SEHExceptStmt* SEHTryStmt::getExceptHandler() const { + return dyn_cast<SEHExceptStmt>(getHandler()); +} + +SEHFinallyStmt* SEHTryStmt::getFinallyHandler() const { + return dyn_cast<SEHFinallyStmt>(getHandler()); +} + +SEHExceptStmt::SEHExceptStmt(SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) + : Stmt(SEHExceptStmtClass), + Loc(Loc) +{ + Children[FILTER_EXPR] = reinterpret_cast<Stmt*>(FilterExpr); + Children[BLOCK] = Block; +} + +SEHExceptStmt* SEHExceptStmt::Create(ASTContext &C, + SourceLocation Loc, + Expr *FilterExpr, + Stmt *Block) { + return new(C) SEHExceptStmt(Loc,FilterExpr,Block); +} + +SEHFinallyStmt::SEHFinallyStmt(SourceLocation Loc, + Stmt *Block) + : Stmt(SEHFinallyStmtClass), + Loc(Loc), + Block(Block) +{} + +SEHFinallyStmt* SEHFinallyStmt::Create(ASTContext &C, + SourceLocation Loc, + Stmt *Block) { + return new(C)SEHFinallyStmt(Loc,Block); +} diff --git a/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp new file mode 100644 index 000000000000..fb024f33ab30 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/StmtDumper.cpp @@ -0,0 +1,704 @@ +//===--- 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/raw_ostream.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtDumper Visitor +//===----------------------------------------------------------------------===// + +namespace { + class StmtDumper : public StmtVisitor<StmtDumper> { + SourceManager *SM; + llvm::raw_ostream &OS; + unsigned IndentLevel; + + /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump + /// the first few levels of an AST. This keeps track of how many ast levels + /// are left. + unsigned MaxDepth; + + /// LastLocFilename/LastLocLine - Keep track of the last location we print + /// out so that we can print out deltas from then on out. + const char *LastLocFilename; + unsigned LastLocLine; + + public: + StmtDumper(SourceManager *sm, llvm::raw_ostream &os, unsigned maxDepth) + : SM(sm), OS(os), 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_range CI = S->children(); + if (CI) { + while (CI) { + OS << '\n'; + DumpSubTree(*CI++); + } + } + } + OS << ')'; + } else { + Indent(); + OS << "<<<NULL>>>"; + } + --IndentLevel; + } + + void DumpDeclarator(Decl *D); + + void Indent() const { + for (int i = 0, e = IndentLevel; i < e; ++i) + OS << " "; + } + + void DumpType(QualType T) { + SplitQualType T_split = T.split(); + OS << "'" << QualType::getAsString(T_split) << "'"; + + if (!T.isNull()) { + // If the type is sugared, also dump a (shallow) desugared type. + SplitQualType D_split = T.getSplitDesugaredType(); + if (T_split != D_split) + OS << ":'" << QualType::getAsString(D_split) << "'"; + } + } + void DumpDeclRef(Decl *node); + void DumpStmt(const Stmt *Node) { + Indent(); + OS << "(" << Node->getStmtClassName() + << " " << (void*)Node; + DumpSourceRange(Node); + } + void DumpValueKind(ExprValueKind K) { + switch (K) { + case VK_RValue: break; + case VK_LValue: OS << " lvalue"; break; + case VK_XValue: OS << " xvalue"; break; + } + } + void DumpObjectKind(ExprObjectKind K) { + switch (K) { + case OK_Ordinary: break; + case OK_BitField: OS << " bitfield"; break; + case OK_ObjCProperty: OS << " objcproperty"; break; + case OK_VectorComponent: OS << " vectorcomponent"; break; + } + } + void DumpExpr(const Expr *Node) { + DumpStmt(Node); + OS << ' '; + DumpType(Node->getType()); + DumpValueKind(Node->getValueKind()); + DumpObjectKind(Node->getObjectKind()); + } + 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 VisitCastExpr(CastExpr *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 VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node); + void VisitMemberExpr(MemberExpr *Node); + void VisitExtVectorElementExpr(ExtVectorElementExpr *Node); + void VisitBinaryOperator(BinaryOperator *Node); + void VisitCompoundAssignOperator(CompoundAssignOperator *Node); + void VisitAddrLabelExpr(AddrLabelExpr *Node); + void VisitBlockExpr(BlockExpr *Node); + + // C++ + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); + void VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node); + void VisitCXXThisExpr(CXXThisExpr *Node); + void VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node); + void VisitCXXConstructExpr(CXXConstructExpr *Node); + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node); + void VisitExprWithCleanups(ExprWithCleanups *Node); + void VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node); + void DumpCXXTemporary(CXXTemporary *Temporary); + + // ObjC + void VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node); + void VisitObjCEncodeExpr(ObjCEncodeExpr *Node); + void VisitObjCMessageExpr(ObjCMessageExpr* Node); + void VisitObjCSelectorExpr(ObjCSelectorExpr *Node); + void VisitObjCProtocolExpr(ObjCProtocolExpr *Node); + void VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node); + void VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node); + }; +} + +//===----------------------------------------------------------------------===// +// Utilities +//===----------------------------------------------------------------------===// + +void StmtDumper::DumpLocation(SourceLocation Loc) { + SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); + + // 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 (PLoc.isInvalid()) { + OS << "<invalid sloc>"; + return; + } + + if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) { + OS << PLoc.getFilename() << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + LastLocFilename = PLoc.getFilename(); + LastLocLine = PLoc.getLine(); + } else if (PLoc.getLine() != LastLocLine) { + OS << "line" << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + LastLocLine = PLoc.getLine(); + } else { + OS << "col" << ':' << 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(); + + OS << " <"; + DumpLocation(R.getBegin()); + if (R.getBegin() != R.getEnd()) { + OS << ", "; + DumpLocation(R.getEnd()); + } + OS << ">"; + + // <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)) { + OS << "\"typedef " << localType->getUnderlyingType().getAsString() + << ' ' << localType << '"'; + } else if (TypeAliasDecl *localType = dyn_cast<TypeAliasDecl>(D)) { + OS << "\"using " << localType << " = " + << localType->getUnderlyingType().getAsString() << '"'; + } else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + OS << "\""; + // Emit storage class for vardecls. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getStorageClass() != SC_None) + OS << VarDecl::getStorageClassSpecifierString(V->getStorageClass()) + << " "; + } + + std::string Name = VD->getNameAsString(); + VD->getType().getAsStringInternal(Name, + PrintingPolicy(VD->getASTContext().getLangOptions())); + OS << Name; + + // If this is a vardecl with an initializer, emit it. + if (VarDecl *V = dyn_cast<VarDecl>(VD)) { + if (V->getInit()) { + OS << " =\n"; + DumpSubTree(V->getInit()); + } + } + OS << '"'; + } 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->getNameStart(); + else + tagname = "<anonymous>"; + OS << '"' << 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->getNameStart(); + else + ns = "<anonymous>"; + OS << '"' << UD->getDeclKindName() << ns << ";\""; + } else if (UsingDecl *UD = dyn_cast<UsingDecl>(D)) { + // print using decl (e.g. "using std::string;") + const char *tn = UD->isTypeName() ? "typename " : ""; + OS << '"' << UD->getDeclKindName() << tn; + UD->getQualifier()->print(OS, + PrintingPolicy(UD->getASTContext().getLangOptions())); + OS << ";\""; + } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) { + OS << "label " << LD->getNameAsString(); + } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) { + OS << "\"static_assert(\n"; + DumpSubTree(SAD->getAssertExpr()); + OS << ",\n"; + DumpSubTree(SAD->getMessage()); + OS << ");\""; + } else { + assert(0 && "Unexpected decl"); + } +} + +void StmtDumper::VisitDeclStmt(DeclStmt *Node) { + DumpStmt(Node); + OS << "\n"; + for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); + DI != DE; ++DI) { + Decl* D = *DI; + ++IndentLevel; + Indent(); + OS << (void*) D << " "; + DumpDeclarator(D); + if (DI+1 != DE) + OS << "\n"; + --IndentLevel; + } +} + +void StmtDumper::VisitLabelStmt(LabelStmt *Node) { + DumpStmt(Node); + OS << " '" << Node->getName() << "'"; +} + +void StmtDumper::VisitGotoStmt(GotoStmt *Node) { + DumpStmt(Node); + OS << " '" << Node->getLabel()->getName() + << "':" << (void*)Node->getLabel(); +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitExpr(Expr *Node) { + DumpExpr(Node); +} + +static void DumpBasePath(llvm::raw_ostream &OS, CastExpr *Node) { + if (Node->path_empty()) + return; + + OS << " ("; + bool First = true; + for (CastExpr::path_iterator + I = Node->path_begin(), E = Node->path_end(); I != E; ++I) { + const CXXBaseSpecifier *Base = *I; + if (!First) + OS << " -> "; + + const CXXRecordDecl *RD = + cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); + + if (Base->isVirtual()) + OS << "virtual "; + OS << RD->getName(); + First = false; + } + + OS << ')'; +} + +void StmtDumper::VisitCastExpr(CastExpr *Node) { + DumpExpr(Node); + OS << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; +} + +void StmtDumper::VisitDeclRefExpr(DeclRefExpr *Node) { + DumpExpr(Node); + + OS << " "; + DumpDeclRef(Node->getDecl()); + if (Node->getDecl() != Node->getFoundDecl()) { + OS << " ("; + DumpDeclRef(Node->getFoundDecl()); + OS << ")"; + } +} + +void StmtDumper::DumpDeclRef(Decl *d) { + OS << d->getDeclKindName() << ' ' << (void*) d; + + if (NamedDecl *nd = dyn_cast<NamedDecl>(d)) { + OS << " '"; + nd->getDeclName().printName(OS); + OS << "'"; + } + + if (ValueDecl *vd = dyn_cast<ValueDecl>(d)) { + OS << ' '; DumpType(vd->getType()); + } +} + +void StmtDumper::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { + DumpExpr(Node); + OS << " ("; + if (!Node->requiresADL()) OS << "no "; + OS << "ADL) = '" << Node->getName() << '\''; + + UnresolvedLookupExpr::decls_iterator + I = Node->decls_begin(), E = Node->decls_end(); + if (I == E) OS << " empty"; + for (; I != E; ++I) + OS << " " << (void*) *I; +} + +void StmtDumper::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + DumpExpr(Node); + + OS << " " << Node->getDecl()->getDeclKindName() + << "Decl='" << Node->getDecl() + << "' " << (void*)Node->getDecl(); + if (Node->isFreeIvar()) + OS << " isFreeIvar"; +} + +void StmtDumper::VisitPredefinedExpr(PredefinedExpr *Node) { + DumpExpr(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 StmtDumper::VisitCharacterLiteral(CharacterLiteral *Node) { + DumpExpr(Node); + OS << Node->getValue(); +} + +void StmtDumper::VisitIntegerLiteral(IntegerLiteral *Node) { + DumpExpr(Node); + + bool isSigned = Node->getType()->isSignedIntegerType(); + OS << " " << Node->getValue().toString(10, isSigned); +} +void StmtDumper::VisitFloatingLiteral(FloatingLiteral *Node) { + DumpExpr(Node); + OS << " " << Node->getValueAsApproximateDouble(); +} + +void StmtDumper::VisitStringLiteral(StringLiteral *Str) { + DumpExpr(Str); + // FIXME: this doesn't print wstrings right. + OS << " "; + if (Str->isWide()) + OS << "L"; + OS << '"'; + OS.write_escaped(Str->getString()); + OS << '"'; +} + +void StmtDumper::VisitUnaryOperator(UnaryOperator *Node) { + DumpExpr(Node); + OS << " " << (Node->isPostfix() ? "postfix" : "prefix") + << " '" << UnaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; +} +void StmtDumper::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node) { + DumpExpr(Node); + switch(Node->getKind()) { + case UETT_SizeOf: + OS << " sizeof "; + break; + case UETT_AlignOf: + OS << " __alignof "; + break; + case UETT_VecStep: + OS << " vec_step "; + break; + } + if (Node->isArgumentType()) + DumpType(Node->getArgumentType()); +} + +void StmtDumper::VisitMemberExpr(MemberExpr *Node) { + DumpExpr(Node); + OS << " " << (Node->isArrow() ? "->" : ".") + << Node->getMemberDecl() << ' ' + << (void*)Node->getMemberDecl(); +} +void StmtDumper::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { + DumpExpr(Node); + OS << " " << Node->getAccessor().getNameStart(); +} +void StmtDumper::VisitBinaryOperator(BinaryOperator *Node) { + DumpExpr(Node); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) << "'"; +} +void StmtDumper::VisitCompoundAssignOperator(CompoundAssignOperator *Node) { + DumpExpr(Node); + OS << " '" << BinaryOperator::getOpcodeStr(Node->getOpcode()) + << "' ComputeLHSTy="; + DumpType(Node->getComputationLHSType()); + OS << " ComputeResultTy="; + DumpType(Node->getComputationResultType()); +} + +void StmtDumper::VisitBlockExpr(BlockExpr *Node) { + DumpExpr(Node); + + IndentLevel++; + BlockDecl *block = Node->getBlockDecl(); + if (block->capturesCXXThis()) { + OS << '\n'; Indent(); OS << "(capture this)"; + } + for (BlockDecl::capture_iterator + i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { + OS << '\n'; + Indent(); + OS << "(capture "; + if (i->isByRef()) OS << "byref "; + if (i->isNested()) OS << "nested "; + DumpDeclRef(i->getVariable()); + if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr()); + OS << ")"; + } + IndentLevel--; + + DumpSubTree(block->getBody()); +} + +// GNU extensions. + +void StmtDumper::VisitAddrLabelExpr(AddrLabelExpr *Node) { + DumpExpr(Node); + OS << " " << Node->getLabel()->getName() + << " " << (void*)Node->getLabel(); +} + +//===----------------------------------------------------------------------===// +// C++ Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { + DumpExpr(Node); + OS << " " << Node->getCastName() + << "<" << Node->getTypeAsWritten().getAsString() << ">" + << " <" << Node->getCastKindName(); + DumpBasePath(OS, Node); + OS << ">"; +} + +void StmtDumper::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *Node) { + DumpExpr(Node); + OS << " " << (Node->getValue() ? "true" : "false"); +} + +void StmtDumper::VisitCXXThisExpr(CXXThisExpr *Node) { + DumpExpr(Node); + OS << " this"; +} + +void StmtDumper::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { + DumpExpr(Node); + OS << " functional cast to " << Node->getTypeAsWritten().getAsString(); +} + +void StmtDumper::VisitCXXConstructExpr(CXXConstructExpr *Node) { + DumpExpr(Node); + CXXConstructorDecl *Ctor = Node->getConstructor(); + DumpType(Ctor->getType()); + if (Node->isElidable()) + OS << " elidable"; + if (Node->requiresZeroInitialization()) + OS << " zeroing"; +} + +void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { + DumpExpr(Node); + OS << " "; + DumpCXXTemporary(Node->getTemporary()); +} + +void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) { + DumpExpr(Node); + ++IndentLevel; + for (unsigned i = 0, e = Node->getNumTemporaries(); i != e; ++i) { + OS << "\n"; + Indent(); + DumpCXXTemporary(Node->getTemporary(i)); + } + --IndentLevel; +} + +void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { + OS << "(CXXTemporary " << (void *)Temporary << ")"; +} + +//===----------------------------------------------------------------------===// +// Obj-C Expressions +//===----------------------------------------------------------------------===// + +void StmtDumper::VisitObjCMessageExpr(ObjCMessageExpr* Node) { + DumpExpr(Node); + OS << " selector=" << Node->getSelector().getAsString(); + switch (Node->getReceiverKind()) { + case ObjCMessageExpr::Instance: + break; + + case ObjCMessageExpr::Class: + OS << " class="; + DumpType(Node->getClassReceiver()); + break; + + case ObjCMessageExpr::SuperInstance: + OS << " super (instance)"; + break; + + case ObjCMessageExpr::SuperClass: + OS << " super (class)"; + break; + } +} + +void StmtDumper::VisitObjCAtCatchStmt(ObjCAtCatchStmt *Node) { + DumpStmt(Node); + if (VarDecl *CatchParam = Node->getCatchParamDecl()) { + OS << " catch parm = "; + DumpDeclarator(CatchParam); + } else { + OS << " catch all"; + } +} + +void StmtDumper::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + DumpExpr(Node); + OS << " "; + DumpType(Node->getEncodedType()); +} + +void StmtDumper::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + DumpExpr(Node); + + OS << " " << Node->getSelector().getAsString(); +} + +void StmtDumper::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + DumpExpr(Node); + + OS << ' ' << Node->getProtocol(); +} + +void StmtDumper::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + DumpExpr(Node); + if (Node->isImplicitProperty()) { + OS << " Kind=MethodRef Getter=\""; + if (Node->getImplicitPropertyGetter()) + OS << Node->getImplicitPropertyGetter()->getSelector().getAsString(); + else + OS << "(null)"; + + OS << "\" Setter=\""; + if (ObjCMethodDecl *Setter = Node->getImplicitPropertySetter()) + OS << Setter->getSelector().getAsString(); + else + OS << "(null)"; + OS << "\""; + } else { + OS << " Kind=PropertyRef Property=\"" << Node->getExplicitProperty() << '"'; + } + + if (Node->isSuperReceiver()) + OS << " 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 { + dump(llvm::errs(), SM); +} + +void Stmt::dump(llvm::raw_ostream &OS, SourceManager &SM) const { + StmtDumper P(&SM, OS, 4); + P.DumpSubTree(const_cast<Stmt*>(this)); + OS << "\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, llvm::errs(), 4); + P.DumpSubTree(const_cast<Stmt*>(this)); + llvm::errs() << "\n"; +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll(SourceManager &SM) const { + StmtDumper P(&SM, llvm::errs(), ~0U); + P.DumpSubTree(const_cast<Stmt*>(this)); + llvm::errs() << "\n"; +} + +/// dumpAll - This does a dump of the specified AST fragment and all subtrees. +void Stmt::dumpAll() const { + StmtDumper P(0, llvm::errs(), ~0U); + P.DumpSubTree(const_cast<Stmt*>(this)); + llvm::errs() << "\n"; +} diff --git a/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp b/contrib/llvm/tools/clang/lib/AST/StmtIterator.cpp new file mode 100644 index 000000000000..9bf4aeaae83e --- /dev/null +++ b/contrib/llvm/tools/clang/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 const VariableArrayType *FindVA(const Type* t) { + while (const ArrayType *vt = dyn_cast<ArrayType>(t)) { + if (const VariableArrayType *vat = dyn_cast<VariableArrayType>(vt)) + if (vat->getSizeExpr()) + return vat; + + t = vt->getElementType().getTypePtr(); + } + + return NULL; +} + +void StmtIteratorBase::NextVA() { + assert (getVAPtr()); + + const 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 (const VariableArrayType* VAPtr = FindVA(VD->getType().getTypePtr())) { + setVAPtr(VAPtr); + return true; + } + + if (VD->getInit()) + return true; + } + else if (TypedefNameDecl* TD = dyn_cast<TypedefNameDecl>(D)) { + if (const 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, Stmt **s) + : stmt(s), decl(d), RawVAPtr(d ? DeclMode : 0) { + if (decl) + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(Decl** dgi, Decl** dge) + : stmt(0), DGI(dgi), RawVAPtr(DeclGroupMode), DGE(dge) { + NextDecl(false); +} + +StmtIteratorBase::StmtIteratorBase(const VariableArrayType* t) + : stmt(0), decl(0), RawVAPtr(SizeOfTypeVAMode) { + RawVAPtr |= reinterpret_cast<uintptr_t>(t); +} + +Stmt*& StmtIteratorBase::GetDeclExpr() const { + + if (const VariableArrayType* VAPtr = getVAPtr()) { + assert (VAPtr->SizeExpr); + return const_cast<Stmt*&>(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/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp new file mode 100644 index 000000000000..87588e451884 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/StmtPrinter.cpp @@ -0,0 +1,1541 @@ +//===--- 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/DeclTemplate.h" +#include "clang/AST/PrettyPrinter.h" +#include "llvm/Support/Format.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// StmtPrinter Visitor +//===----------------------------------------------------------------------===// + +namespace { + class 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, + 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 PrintCallArgs(CallExpr *E); + void PrintRawSEHExceptHandler(SEHExceptStmt *S); + void PrintRawSEHFinallyStmt(SEHFinallyStmt *S); + + 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; + } + + void Visit(Stmt* S) { + if (Helper && Helper->handledStmt(S,OS)) + return; + else StmtVisitor<StmtPrinter>::Visit(S); + } + + void VisitStmt(Stmt *Node) LLVM_ATTRIBUTE_UNUSED { + Indent() << "<<unknown stmt type>>\n"; + } + void VisitExpr(Expr *Node) LLVM_ATTRIBUTE_UNUSED { + OS << "<<unknown expr type>>"; + } + void VisitCXXNamedCastExpr(CXXNamedCastExpr *Node); + +#define ABSTRACT_STMT(CLASS) +#define STMT(CLASS, PARENT) \ + void Visit##CLASS(CLASS *Node); +#include "clang/AST/StmtNodes.inc" + }; +} + +//===----------------------------------------------------------------------===// +// Stmt printing methods. +//===----------------------------------------------------------------------===// + +/// 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, 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, 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::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::VisitCXXForRangeStmt(CXXForRangeStmt *Node) { + Indent() << "for ("; + PrintingPolicy SubPolicy(Policy); + SubPolicy.SuppressInitializers = true; + Node->getLoopVariable()->print(OS, SubPolicy, IndentLevel); + OS << " : "; + PrintExpr(Node->getRangeInit()); + OS << ") {\n"; + PrintStmt(Node->getBody()); + Indent() << "}\n"; +} + +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 (unsigned I = 0, N = Node->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *catchStmt = Node->getCatchStmt(I); + 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"; +} + +void StmtPrinter::VisitSEHTryStmt(SEHTryStmt *Node) { + Indent() << (Node->getIsCXXTry() ? "try " : "__try "); + PrintRawCompoundStmt(Node->getTryBlock()); + SEHExceptStmt *E = Node->getExceptHandler(); + SEHFinallyStmt *F = Node->getFinallyHandler(); + if(E) + PrintRawSEHExceptHandler(E); + else { + assert(F && "Must have a finally block..."); + PrintRawSEHFinallyStmt(F); + } + OS << "\n"; +} + +void StmtPrinter::PrintRawSEHFinallyStmt(SEHFinallyStmt *Node) { + OS << "__finally "; + PrintRawCompoundStmt(Node->getBlock()); + OS << "\n"; +} + +void StmtPrinter::PrintRawSEHExceptHandler(SEHExceptStmt *Node) { + OS << "__except ("; + VisitExpr(Node->getFilterExpr()); + OS << ")\n"; + PrintRawCompoundStmt(Node->getBlock()); + OS << "\n"; +} + +void StmtPrinter::VisitSEHExceptStmt(SEHExceptStmt *Node) { + Indent(); + PrintRawSEHExceptHandler(Node); + OS << "\n"; +} + +void StmtPrinter::VisitSEHFinallyStmt(SEHFinallyStmt *Node) { + Indent(); + PrintRawSEHFinallyStmt(Node); + OS << "\n"; +} + +//===----------------------------------------------------------------------===// +// Expr printing methods. +//===----------------------------------------------------------------------===// + +void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + OS << Node->getNameInfo(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); +} + +void StmtPrinter::VisitDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *Node) { + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + OS << Node->getNameInfo(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); +} + +void StmtPrinter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *Node) { + if (Node->getQualifier()) + Node->getQualifier()->print(OS, Policy); + OS << Node->getNameInfo(); + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); +} + +void StmtPrinter::VisitObjCIvarRefExpr(ObjCIvarRefExpr *Node) { + if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + OS << Node->getDecl(); +} + +void StmtPrinter::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *Node) { + if (Node->isSuperReceiver()) + OS << "super."; + else if (Node->getBase()) { + PrintExpr(Node->getBase()); + OS << "."; + } + + if (Node->isImplicitProperty()) + OS << Node->getImplicitPropertyGetter()->getSelector().getAsString(); + else + OS << Node->getExplicitProperty()->getName(); +} + +void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { + switch (Node->getIdentType()) { + default: + assert(0 && "unknown case"); + case PredefinedExpr::Func: + OS << "__func__"; + break; + case PredefinedExpr::Function: + OS << "__FUNCTION__"; + break; + case PredefinedExpr::PrettyFunction: + OS << "__PRETTY_FUNCTION__"; + break; + } +} + +void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { + 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()->getAs<BuiltinType>()->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. + llvm::StringRef StrData = Str->getString(); + for (llvm::StringRef::iterator I = StrData.begin(), E = StrData.end(); + I != E; ++I) { + unsigned char Char = *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, or if + // it might be concatenated incorrectly like '+'. + switch (Node->getOpcode()) { + default: break; + case UO_Real: + case UO_Imag: + case UO_Extension: + OS << ' '; + break; + case UO_Plus: + case UO_Minus: + if (isa<UnaryOperator>(Node->getSubExpr())) + OS << ' '; + break; + } + } + PrintExpr(Node->getSubExpr()); + + if (Node->isPostfix()) + OS << UnaryOperator::getOpcodeStr(Node->getOpcode()); +} + +void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { + OS << "__builtin_offsetof("; + OS << Node->getTypeSourceInfo()->getType().getAsString(Policy) << ", "; + bool PrintedSomething = false; + for (unsigned i = 0, n = Node->getNumComponents(); i < n; ++i) { + OffsetOfExpr::OffsetOfNode ON = Node->getComponent(i); + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Array) { + // Array node + OS << "["; + PrintExpr(Node->getIndexExpr(ON.getArrayExprIndex())); + OS << "]"; + PrintedSomething = true; + continue; + } + + // Skip implicit base indirections. + if (ON.getKind() == OffsetOfExpr::OffsetOfNode::Base) + continue; + + // Field or identifier node. + IdentifierInfo *Id = ON.getFieldName(); + if (!Id) + continue; + + if (PrintedSomething) + OS << "."; + else + PrintedSomething = true; + OS << Id->getName(); + } + OS << ")"; +} + +void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ + switch(Node->getKind()) { + case UETT_SizeOf: + OS << "sizeof"; + break; + case UETT_AlignOf: + OS << "__alignof"; + break; + case UETT_VecStep: + OS << "vec_step"; + break; + } + if (Node->isArgumentType()) + OS << "(" << Node->getArgumentType().getAsString(Policy) << ")"; + else { + OS << " "; + PrintExpr(Node->getArgumentExpr()); + } +} + +void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { + OS << "_Generic("; + PrintExpr(Node->getControllingExpr()); + for (unsigned i = 0; i != Node->getNumAssocs(); ++i) { + OS << ", "; + QualType T = Node->getAssocType(i); + if (T.isNull()) + OS << "default"; + else + OS << T.getAsString(Policy); + OS << ": "; + PrintExpr(Node->getAssocExpr(i)); + } + OS << ")"; +} + +void StmtPrinter::VisitArraySubscriptExpr(ArraySubscriptExpr *Node) { + PrintExpr(Node->getLHS()); + OS << "["; + PrintExpr(Node->getRHS()); + OS << "]"; +} + +void StmtPrinter::PrintCallArgs(CallExpr *Call) { + 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)); + } +} + +void StmtPrinter::VisitCallExpr(CallExpr *Call) { + PrintExpr(Call->getCallee()); + OS << "("; + PrintCallArgs(Call); + OS << ")"; +} +void StmtPrinter::VisitMemberExpr(MemberExpr *Node) { + // FIXME: Suppress printing implicit bases (like "this") + PrintExpr(Node->getBase()); + if (FieldDecl *FD = dyn_cast<FieldDecl>(Node->getMemberDecl())) + if (FD->isAnonymousStructOrUnion()) + return; + OS << (Node->isArrow() ? "->" : "."); + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + + OS << Node->getMemberNameInfo(); + + if (Node->hasExplicitTemplateArgs()) + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); +} +void StmtPrinter::VisitObjCIsaExpr(ObjCIsaExpr *Node) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->isa" : ".isa"); +} + +void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { + PrintExpr(Node->getBase()); + OS << "."; + OS << Node->getAccessor().getName(); +} +void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { + OS << "(" << Node->getType().getAsString(Policy) << ")"; + PrintExpr(Node->getSubExpr()); +} +void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { + OS << "(" << Node->getType().getAsString(Policy) << ")"; + 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()); + OS << " ? "; + PrintExpr(Node->getLHS()); + OS << " : "; + PrintExpr(Node->getRHS()); +} + +// GNU extensions. + +void +StmtPrinter::VisitBinaryConditionalOperator(BinaryConditionalOperator *Node) { + PrintExpr(Node->getCommon()); + OS << " ?: "; + PrintExpr(Node->getFalseExpr()); +} +void StmtPrinter::VisitAddrLabelExpr(AddrLabelExpr *Node) { + OS << "&&" << Node->getLabel()->getName(); +} + +void StmtPrinter::VisitStmtExpr(StmtExpr *E) { + OS << "("; + PrintRawCompoundStmt(E->getSubStmt()); + OS << ")"; +} + +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::VisitParenListExpr(ParenListExpr* Node) { + OS << "( "; + for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + 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.LangOpts.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(Policy); + 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::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *Node) { + PrintExpr(Node->getCallee()); + OS << "<<<"; + PrintCallArgs(Node->getConfig()); + OS << ">>>("; + PrintCallArgs(Node); + OS << ")"; +} + +void StmtPrinter::VisitCXXNamedCastExpr(CXXNamedCastExpr *Node) { + OS << Node->getCastName() << '<'; + OS << Node->getTypeAsWritten().getAsString(Policy) << ">("; + 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(Policy); + } else { + PrintExpr(Node->getExprOperand()); + } + OS << ")"; +} + +void StmtPrinter::VisitCXXUuidofExpr(CXXUuidofExpr *Node) { + OS << "__uuidof("; + if (Node->isTypeOperand()) { + OS << Node->getTypeOperand().getAsString(Policy); + } 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(Policy); + OS << "("; + PrintExpr(Node->getSubExpr()); + OS << ")"; +} + +void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { + PrintExpr(Node->getSubExpr()); +} + +void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { + OS << Node->getType().getAsString(Policy); + 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::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *Node) { + if (TypeSourceInfo *TSInfo = Node->getTypeSourceInfo()) + OS << TSInfo->getType().getAsString(Policy) << "()"; + else + OS << Node->getType().getAsString(Policy) << "()"; +} + +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::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { + PrintExpr(E->getBase()); + if (E->isArrow()) + OS << "->"; + else + OS << '.'; + if (E->getQualifier()) + E->getQualifier()->print(OS, Policy); + + std::string TypeS; + if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) + OS << II->getName(); + else + E->getDestroyedType().getAsStringInternal(TypeS, Policy); + OS << TypeS; +} + +void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { + for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { + if (isa<CXXDefaultArgExpr>(E->getArg(i))) { + // Don't print any defaulted arguments + break; + } + + if (i) OS << ", "; + PrintExpr(E->getArg(i)); + } +} + +void StmtPrinter::VisitExprWithCleanups(ExprWithCleanups *E) { + // Just forward to the sub expression. + PrintExpr(E->getSubExpr()); +} + +void +StmtPrinter::VisitCXXUnresolvedConstructExpr( + CXXUnresolvedConstructExpr *Node) { + OS << Node->getTypeAsWritten().getAsString(Policy); + 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::VisitCXXDependentScopeMemberExpr( + CXXDependentScopeMemberExpr *Node) { + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + else if (Node->hasExplicitTemplateArgs()) + // FIXME: Track use of "template" keyword explicitly? + OS << "template "; + + OS << Node->getMemberNameInfo(); + + if (Node->hasExplicitTemplateArgs()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } +} + +void StmtPrinter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *Node) { + if (!Node->isImplicitAccess()) { + PrintExpr(Node->getBase()); + OS << (Node->isArrow() ? "->" : "."); + } + if (NestedNameSpecifier *Qualifier = Node->getQualifier()) + Qualifier->print(OS, Policy); + + // FIXME: this might originally have been written with 'template' + + OS << Node->getMemberNameInfo(); + + if (Node->hasExplicitTemplateArgs()) { + OS << TemplateSpecializationType::PrintTemplateArgumentList( + Node->getTemplateArgs(), + Node->getNumTemplateArgs(), + Policy); + } +} + +static const char *getTypeTraitName(UnaryTypeTrait UTT) { + switch (UTT) { + case UTT_HasNothrowAssign: return "__has_nothrow_assign"; + case UTT_HasNothrowConstructor: return "__has_nothrow_constructor"; + case UTT_HasNothrowCopy: return "__has_nothrow_copy"; + case UTT_HasTrivialAssign: return "__has_trivial_assign"; + case UTT_HasTrivialDefaultConstructor: return "__has_trivial_constructor"; + case UTT_HasTrivialCopy: return "__has_trivial_copy"; + case UTT_HasTrivialDestructor: return "__has_trivial_destructor"; + case UTT_HasVirtualDestructor: return "__has_virtual_destructor"; + case UTT_IsAbstract: return "__is_abstract"; + case UTT_IsArithmetic: return "__is_arithmetic"; + case UTT_IsArray: return "__is_array"; + case UTT_IsClass: return "__is_class"; + case UTT_IsCompleteType: return "__is_complete_type"; + case UTT_IsCompound: return "__is_compound"; + case UTT_IsConst: return "__is_const"; + case UTT_IsEmpty: return "__is_empty"; + case UTT_IsEnum: return "__is_enum"; + case UTT_IsFloatingPoint: return "__is_floating_point"; + case UTT_IsFunction: return "__is_function"; + case UTT_IsFundamental: return "__is_fundamental"; + case UTT_IsIntegral: return "__is_integral"; + case UTT_IsLiteral: return "__is_literal"; + case UTT_IsLvalueReference: return "__is_lvalue_reference"; + case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer"; + case UTT_IsMemberObjectPointer: return "__is_member_object_pointer"; + case UTT_IsMemberPointer: return "__is_member_pointer"; + case UTT_IsObject: return "__is_object"; + case UTT_IsPOD: return "__is_pod"; + case UTT_IsPointer: return "__is_pointer"; + case UTT_IsPolymorphic: return "__is_polymorphic"; + case UTT_IsReference: return "__is_reference"; + case UTT_IsRvalueReference: return "__is_rvalue_reference"; + case UTT_IsScalar: return "__is_scalar"; + case UTT_IsSigned: return "__is_signed"; + case UTT_IsStandardLayout: return "__is_standard_layout"; + case UTT_IsTrivial: return "__is_trivial"; + case UTT_IsTriviallyCopyable: return "__is_trivially_copyable"; + case UTT_IsUnion: return "__is_union"; + case UTT_IsUnsigned: return "__is_unsigned"; + case UTT_IsVoid: return "__is_void"; + case UTT_IsVolatile: return "__is_volatile"; + } + llvm_unreachable("Type trait not covered by switch statement"); +} + +static const char *getTypeTraitName(BinaryTypeTrait BTT) { + switch (BTT) { + case BTT_IsBaseOf: return "__is_base_of"; + case BTT_IsConvertible: return "__is_convertible"; + case BTT_IsSame: return "__is_same"; + case BTT_TypeCompatible: return "__builtin_types_compatible_p"; + case BTT_IsConvertibleTo: return "__is_convertible_to"; + } + llvm_unreachable("Binary type trait not covered by switch"); +} + +static const char *getTypeTraitName(ArrayTypeTrait ATT) { + switch (ATT) { + case ATT_ArrayRank: return "__array_rank"; + case ATT_ArrayExtent: return "__array_extent"; + } + llvm_unreachable("Array type trait not covered by switch"); +} + +static const char *getExpressionTraitName(ExpressionTrait ET) { + switch (ET) { + case ET_IsLValueExpr: return "__is_lvalue_expr"; + case ET_IsRValueExpr: return "__is_rvalue_expr"; + } + llvm_unreachable("Expression type trait not covered by switch"); +} + +void StmtPrinter::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getQueriedType().getAsString(Policy) << ")"; +} + +void StmtPrinter::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getLhsType().getAsString(Policy) << "," + << E->getRhsType().getAsString(Policy) << ")"; +} + +void StmtPrinter::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { + OS << getTypeTraitName(E->getTrait()) << "(" + << E->getQueriedType().getAsString(Policy) << ")"; +} + +void StmtPrinter::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { + OS << getExpressionTraitName(E->getTrait()) << "("; + PrintExpr(E->getQueriedExpression()); + OS << ")"; +} + +void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { + OS << "noexcept("; + PrintExpr(E->getOperand()); + OS << ")"; +} + +void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) { + PrintExpr(E->getPattern()); + OS << "..."; +} + +void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) { + OS << "sizeof...(" << E->getPack()->getNameAsString() << ")"; +} + +void StmtPrinter::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *Node) { + OS << Node->getParameterPack()->getNameAsString(); +} + +// Obj-C + +void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { + OS << "@"; + VisitStringLiteral(Node->getString()); +} + +void StmtPrinter::VisitObjCEncodeExpr(ObjCEncodeExpr *Node) { + OS << "@encode(" << Node->getEncodedType().getAsString(Policy) << ')'; +} + +void StmtPrinter::VisitObjCSelectorExpr(ObjCSelectorExpr *Node) { + OS << "@selector(" << Node->getSelector().getAsString() << ')'; +} + +void StmtPrinter::VisitObjCProtocolExpr(ObjCProtocolExpr *Node) { + OS << "@protocol(" << Node->getProtocol() << ')'; +} + +void StmtPrinter::VisitObjCMessageExpr(ObjCMessageExpr *Mess) { + OS << "["; + switch (Mess->getReceiverKind()) { + case ObjCMessageExpr::Instance: + PrintExpr(Mess->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: + OS << Mess->getClassReceiver().getAsString(Policy); + break; + + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + OS << "Super"; + break; + } + + OS << ' '; + Selector selector = Mess->getSelector(); + if (selector.isUnarySelector()) { + OS << selector.getNameForSlot(0); + } 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::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(); +} + +void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {} + +void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { + OS << "__builtin_astype("; + PrintExpr(Node->getSrcExpr()); + OS << ", " << Node->getType().getAsString(); + OS << ")"; +} + +//===----------------------------------------------------------------------===// +// Stmt method implementations +//===----------------------------------------------------------------------===// + +void Stmt::dumpPretty(ASTContext& Context) const { + printPretty(llvm::errs(), Context, 0, + PrintingPolicy(Context.getLangOptions())); +} + +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 && &Context) { + dump(OS, Context.getSourceManager()); + return; + } + + StmtPrinter P(OS, Context, Helper, Policy, Indentation); + P.Visit(const_cast<Stmt*>(this)); +} + +//===----------------------------------------------------------------------===// +// PrinterHelper +//===----------------------------------------------------------------------===// + +// Implement virtual destructor. +PrinterHelper::~PrinterHelper() {} diff --git a/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp new file mode 100644 index 000000000000..b117cd9a525f --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/StmtProfile.cpp @@ -0,0 +1,1064 @@ +//===---- StmtProfile.cpp - Profile 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::Profile method, which builds a unique bit +// representation that identifies a statement/expression. +// +//===----------------------------------------------------------------------===// +#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/ExprCXX.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/FoldingSet.h" +using namespace clang; + +namespace { + class StmtProfiler : public StmtVisitor<StmtProfiler> { + llvm::FoldingSetNodeID &ID; + const ASTContext &Context; + bool Canonical; + + public: + StmtProfiler(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) + : ID(ID), Context(Context), Canonical(Canonical) { } + + void VisitStmt(Stmt *S); + +#define STMT(Node, Base) void Visit##Node(Node *S); +#include "clang/AST/StmtNodes.inc" + + /// \brief Visit a declaration that is referenced within an expression + /// or statement. + void VisitDecl(Decl *D); + + /// \brief Visit a type that is referenced within an expression or + /// statement. + void VisitType(QualType T); + + /// \brief Visit a name that occurs within an expression or statement. + void VisitName(DeclarationName Name); + + /// \brief Visit a nested-name-specifier that occurs within an expression + /// or statement. + void VisitNestedNameSpecifier(NestedNameSpecifier *NNS); + + /// \brief Visit a template name that occurs within an expression or + /// statement. + void VisitTemplateName(TemplateName Name); + + /// \brief Visit template arguments that occur within an expression or + /// statement. + void VisitTemplateArguments(const TemplateArgumentLoc *Args, unsigned NumArgs); + + /// \brief Visit a single template argument. + void VisitTemplateArgument(const TemplateArgument &Arg); + }; +} + +void StmtProfiler::VisitStmt(Stmt *S) { + ID.AddInteger(S->getStmtClass()); + for (Stmt::child_range C = S->children(); C; ++C) + Visit(*C); +} + +void StmtProfiler::VisitDeclStmt(DeclStmt *S) { + VisitStmt(S); + for (DeclStmt::decl_iterator D = S->decl_begin(), DEnd = S->decl_end(); + D != DEnd; ++D) + VisitDecl(*D); +} + +void StmtProfiler::VisitNullStmt(NullStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCompoundStmt(CompoundStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSwitchCase(SwitchCase *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCaseStmt(CaseStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDefaultStmt(DefaultStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitLabelStmt(LabelStmt *S) { + VisitStmt(S); + VisitDecl(S->getDecl()); +} + +void StmtProfiler::VisitIfStmt(IfStmt *S) { + VisitStmt(S); + VisitDecl(S->getConditionVariable()); +} + +void StmtProfiler::VisitSwitchStmt(SwitchStmt *S) { + VisitStmt(S); + VisitDecl(S->getConditionVariable()); +} + +void StmtProfiler::VisitWhileStmt(WhileStmt *S) { + VisitStmt(S); + VisitDecl(S->getConditionVariable()); +} + +void StmtProfiler::VisitDoStmt(DoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitForStmt(ForStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitGotoStmt(GotoStmt *S) { + VisitStmt(S); + VisitDecl(S->getLabel()); +} + +void StmtProfiler::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitContinueStmt(ContinueStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitBreakStmt(BreakStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitReturnStmt(ReturnStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitAsmStmt(AsmStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->isVolatile()); + ID.AddBoolean(S->isSimple()); + VisitStringLiteral(S->getAsmString()); + ID.AddInteger(S->getNumOutputs()); + for (unsigned I = 0, N = S->getNumOutputs(); I != N; ++I) { + ID.AddString(S->getOutputName(I)); + VisitStringLiteral(S->getOutputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumInputs()); + for (unsigned I = 0, N = S->getNumInputs(); I != N; ++I) { + ID.AddString(S->getInputName(I)); + VisitStringLiteral(S->getInputConstraintLiteral(I)); + } + ID.AddInteger(S->getNumClobbers()); + for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) + VisitStringLiteral(S->getClobber(I)); +} + +void StmtProfiler::VisitCXXCatchStmt(CXXCatchStmt *S) { + VisitStmt(S); + VisitType(S->getCaughtType()); +} + +void StmtProfiler::VisitCXXTryStmt(CXXTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHTryStmt(SEHTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHFinallyStmt(SEHFinallyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitSEHExceptStmt(SEHExceptStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + VisitStmt(S); + ID.AddBoolean(S->hasEllipsis()); + if (S->getCatchParamDecl()) + VisitType(S->getCatchParamDecl()->getType()); +} + +void StmtProfiler::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitExpr(Expr *S) { + VisitStmt(S); +} + +void StmtProfiler::VisitDeclRefExpr(DeclRefExpr *S) { + VisitExpr(S); + if (!Canonical) + VisitNestedNameSpecifier(S->getQualifier()); + VisitDecl(S->getDecl()); + if (!Canonical) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitPredefinedExpr(PredefinedExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getIdentType()); +} + +void StmtProfiler::VisitIntegerLiteral(IntegerLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); +} + +void StmtProfiler::VisitCharacterLiteral(CharacterLiteral *S) { + VisitExpr(S); + ID.AddBoolean(S->isWide()); + ID.AddInteger(S->getValue()); +} + +void StmtProfiler::VisitFloatingLiteral(FloatingLiteral *S) { + VisitExpr(S); + S->getValue().Profile(ID); + ID.AddBoolean(S->isExact()); +} + +void StmtProfiler::VisitImaginaryLiteral(ImaginaryLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitStringLiteral(StringLiteral *S) { + VisitExpr(S); + ID.AddString(S->getString()); + ID.AddBoolean(S->isWide()); +} + +void StmtProfiler::VisitParenExpr(ParenExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitParenListExpr(ParenListExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitUnaryOperator(UnaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitOffsetOfExpr(OffsetOfExpr *S) { + VisitType(S->getTypeSourceInfo()->getType()); + unsigned n = S->getNumComponents(); + for (unsigned i = 0; i < n; ++i) { + const OffsetOfExpr::OffsetOfNode& ON = S->getComponent(i); + ID.AddInteger(ON.getKind()); + switch (ON.getKind()) { + case OffsetOfExpr::OffsetOfNode::Array: + // Expressions handled below. + break; + + case OffsetOfExpr::OffsetOfNode::Field: + VisitDecl(ON.getField()); + break; + + case OffsetOfExpr::OffsetOfNode::Identifier: + ID.AddPointer(ON.getFieldName()); + break; + + case OffsetOfExpr::OffsetOfNode::Base: + // These nodes are implicit, and therefore don't need profiling. + break; + } + } + + VisitExpr(S); +} + +void StmtProfiler::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getKind()); + if (S->isArgumentType()) + VisitType(S->getArgumentType()); +} + +void StmtProfiler::VisitArraySubscriptExpr(ArraySubscriptExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCallExpr(CallExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitMemberExpr(MemberExpr *S) { + VisitExpr(S); + VisitDecl(S->getMemberDecl()); + if (!Canonical) + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitCompoundLiteralExpr(CompoundLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isFileScope()); +} + +void StmtProfiler::VisitCastExpr(CastExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitImplicitCastExpr(ImplicitCastExpr *S) { + VisitCastExpr(S); + ID.AddInteger(S->getValueKind()); +} + +void StmtProfiler::VisitExplicitCastExpr(ExplicitCastExpr *S) { + VisitCastExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void StmtProfiler::VisitCStyleCastExpr(CStyleCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitBinaryOperator(BinaryOperator *S) { + VisitExpr(S); + ID.AddInteger(S->getOpcode()); +} + +void StmtProfiler::VisitCompoundAssignOperator(CompoundAssignOperator *S) { + VisitBinaryOperator(S); +} + +void StmtProfiler::VisitConditionalOperator(ConditionalOperator *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitBinaryConditionalOperator(BinaryConditionalOperator *S){ + VisitExpr(S); +} + +void StmtProfiler::VisitAddrLabelExpr(AddrLabelExpr *S) { + VisitExpr(S); + VisitDecl(S->getLabel()); +} + +void StmtProfiler::VisitStmtExpr(StmtExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitShuffleVectorExpr(ShuffleVectorExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitChooseExpr(ChooseExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitGNUNullExpr(GNUNullExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitVAArgExpr(VAArgExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitInitListExpr(InitListExpr *S) { + if (S->getSyntacticForm()) { + VisitInitListExpr(S->getSyntacticForm()); + return; + } + + VisitExpr(S); +} + +void StmtProfiler::VisitDesignatedInitExpr(DesignatedInitExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->usesGNUSyntax()); + for (DesignatedInitExpr::designators_iterator D = S->designators_begin(), + DEnd = S->designators_end(); + D != DEnd; ++D) { + if (D->isFieldDesignator()) { + ID.AddInteger(0); + VisitName(D->getFieldName()); + continue; + } + + if (D->isArrayDesignator()) { + ID.AddInteger(1); + } else { + assert(D->isArrayRangeDesignator()); + ID.AddInteger(2); + } + ID.AddInteger(D->getFirstExprIndex()); + } +} + +void StmtProfiler::VisitImplicitValueInitExpr(ImplicitValueInitExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitExtVectorElementExpr(ExtVectorElementExpr *S) { + VisitExpr(S); + VisitName(&S->getAccessor()); +} + +void StmtProfiler::VisitBlockExpr(BlockExpr *S) { + VisitExpr(S); + VisitDecl(S->getBlockDecl()); +} + +void StmtProfiler::VisitBlockDeclRefExpr(BlockDeclRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isByRef()); + ID.AddBoolean(S->isConstQualAdded()); +} + +void StmtProfiler::VisitGenericSelectionExpr(GenericSelectionExpr *S) { + VisitExpr(S); + for (unsigned i = 0; i != S->getNumAssocs(); ++i) { + QualType T = S->getAssocType(i); + if (T.isNull()) + ID.AddPointer(0); + else + VisitType(T); + VisitExpr(S->getAssocExpr(i)); + } +} + +static Stmt::StmtClass DecodeOperatorCall(CXXOperatorCallExpr *S, + UnaryOperatorKind &UnaryOp, + BinaryOperatorKind &BinaryOp) { + switch (S->getOperator()) { + case OO_None: + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Arrow: + case OO_Call: + case OO_Conditional: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Invalid operator call kind"); + return Stmt::ArraySubscriptExprClass; + + case OO_Plus: + if (S->getNumArgs() == 1) { + UnaryOp = UO_Plus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BO_Add; + return Stmt::BinaryOperatorClass; + + case OO_Minus: + if (S->getNumArgs() == 1) { + UnaryOp = UO_Minus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BO_Sub; + return Stmt::BinaryOperatorClass; + + case OO_Star: + if (S->getNumArgs() == 1) { + UnaryOp = UO_Minus; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BO_Sub; + return Stmt::BinaryOperatorClass; + + case OO_Slash: + BinaryOp = BO_Div; + return Stmt::BinaryOperatorClass; + + case OO_Percent: + BinaryOp = BO_Rem; + return Stmt::BinaryOperatorClass; + + case OO_Caret: + BinaryOp = BO_Xor; + return Stmt::BinaryOperatorClass; + + case OO_Amp: + if (S->getNumArgs() == 1) { + UnaryOp = UO_AddrOf; + return Stmt::UnaryOperatorClass; + } + + BinaryOp = BO_And; + return Stmt::BinaryOperatorClass; + + case OO_Pipe: + BinaryOp = BO_Or; + return Stmt::BinaryOperatorClass; + + case OO_Tilde: + UnaryOp = UO_Not; + return Stmt::UnaryOperatorClass; + + case OO_Exclaim: + UnaryOp = UO_LNot; + return Stmt::UnaryOperatorClass; + + case OO_Equal: + BinaryOp = BO_Assign; + return Stmt::BinaryOperatorClass; + + case OO_Less: + BinaryOp = BO_LT; + return Stmt::BinaryOperatorClass; + + case OO_Greater: + BinaryOp = BO_GT; + return Stmt::BinaryOperatorClass; + + case OO_PlusEqual: + BinaryOp = BO_AddAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_MinusEqual: + BinaryOp = BO_SubAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_StarEqual: + BinaryOp = BO_MulAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_SlashEqual: + BinaryOp = BO_DivAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_PercentEqual: + BinaryOp = BO_RemAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_CaretEqual: + BinaryOp = BO_XorAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_AmpEqual: + BinaryOp = BO_AndAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_PipeEqual: + BinaryOp = BO_OrAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_LessLess: + BinaryOp = BO_Shl; + return Stmt::BinaryOperatorClass; + + case OO_GreaterGreater: + BinaryOp = BO_Shr; + return Stmt::BinaryOperatorClass; + + case OO_LessLessEqual: + BinaryOp = BO_ShlAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_GreaterGreaterEqual: + BinaryOp = BO_ShrAssign; + return Stmt::CompoundAssignOperatorClass; + + case OO_EqualEqual: + BinaryOp = BO_EQ; + return Stmt::BinaryOperatorClass; + + case OO_ExclaimEqual: + BinaryOp = BO_NE; + return Stmt::BinaryOperatorClass; + + case OO_LessEqual: + BinaryOp = BO_LE; + return Stmt::BinaryOperatorClass; + + case OO_GreaterEqual: + BinaryOp = BO_GE; + return Stmt::BinaryOperatorClass; + + case OO_AmpAmp: + BinaryOp = BO_LAnd; + return Stmt::BinaryOperatorClass; + + case OO_PipePipe: + BinaryOp = BO_LOr; + return Stmt::BinaryOperatorClass; + + case OO_PlusPlus: + UnaryOp = S->getNumArgs() == 1? UO_PreInc + : UO_PostInc; + return Stmt::UnaryOperatorClass; + + case OO_MinusMinus: + UnaryOp = S->getNumArgs() == 1? UO_PreDec + : UO_PostDec; + return Stmt::UnaryOperatorClass; + + case OO_Comma: + BinaryOp = BO_Comma; + return Stmt::BinaryOperatorClass; + + + case OO_ArrowStar: + BinaryOp = BO_PtrMemI; + return Stmt::BinaryOperatorClass; + + case OO_Subscript: + return Stmt::ArraySubscriptExprClass; + } + + llvm_unreachable("Invalid overloaded operator expression"); +} + + +void StmtProfiler::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *S) { + if (S->isTypeDependent()) { + // Type-dependent operator calls are profiled like their underlying + // syntactic operator. + UnaryOperatorKind UnaryOp = UO_Extension; + BinaryOperatorKind BinaryOp = BO_Comma; + Stmt::StmtClass SC = DecodeOperatorCall(S, UnaryOp, BinaryOp); + + ID.AddInteger(SC); + for (unsigned I = 0, N = S->getNumArgs(); I != N; ++I) + Visit(S->getArg(I)); + if (SC == Stmt::UnaryOperatorClass) + ID.AddInteger(UnaryOp); + else if (SC == Stmt::BinaryOperatorClass || + SC == Stmt::CompoundAssignOperatorClass) + ID.AddInteger(BinaryOp); + else + assert(SC == Stmt::ArraySubscriptExprClass); + + return; + } + + VisitCallExpr(S); + ID.AddInteger(S->getOperator()); +} + +void StmtProfiler::VisitCXXMemberCallExpr(CXXMemberCallExpr *S) { + VisitCallExpr(S); +} + +void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) { + VisitCallExpr(S); +} + +void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXStaticCastExpr(CXXStaticCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXDynamicCastExpr(CXXDynamicCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXReinterpretCastExpr(CXXReinterpretCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXConstCastExpr(CXXConstCastExpr *S) { + VisitCXXNamedCastExpr(S); +} + +void StmtProfiler::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->getValue()); +} + +void StmtProfiler::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXTypeidExpr(CXXTypeidExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + +void StmtProfiler::VisitCXXUuidofExpr(CXXUuidofExpr *S) { + VisitExpr(S); + if (S->isTypeOperand()) + VisitType(S->getTypeOperand()); +} + +void StmtProfiler::VisitCXXThisExpr(CXXThisExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXThrowExpr(CXXThrowExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *S) { + VisitExpr(S); + VisitDecl(S->getParam()); +} + +void StmtProfiler::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *S) { + VisitExpr(S); + VisitDecl( + const_cast<CXXDestructorDecl *>(S->getTemporary()->getDestructor())); +} + +void StmtProfiler::VisitCXXConstructExpr(CXXConstructExpr *S) { + VisitExpr(S); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isElidable()); +} + +void StmtProfiler::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *S) { + VisitExplicitCastExpr(S); +} + +void StmtProfiler::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *S) { + VisitCXXConstructExpr(S); +} + +void StmtProfiler::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitCXXDeleteExpr(CXXDeleteExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isGlobalDelete()); + ID.AddBoolean(S->isArrayForm()); + VisitDecl(S->getOperatorDelete()); +} + + +void StmtProfiler::VisitCXXNewExpr(CXXNewExpr *S) { + VisitExpr(S); + VisitType(S->getAllocatedType()); + VisitDecl(S->getOperatorNew()); + VisitDecl(S->getOperatorDelete()); + VisitDecl(S->getConstructor()); + ID.AddBoolean(S->isArray()); + ID.AddInteger(S->getNumPlacementArgs()); + ID.AddBoolean(S->isGlobalNew()); + ID.AddBoolean(S->isParenTypeId()); + ID.AddBoolean(S->hasInitializer()); + ID.AddInteger(S->getNumConstructorArgs()); +} + +void StmtProfiler::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + VisitNestedNameSpecifier(S->getQualifier()); + VisitType(S->getDestroyedType()); +} + +void StmtProfiler::VisitOverloadExpr(OverloadExpr *S) { + VisitExpr(S); + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getExplicitTemplateArgs().getTemplateArgs(), + S->getExplicitTemplateArgs().NumTemplateArgs); +} + +void +StmtProfiler::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *S) { + VisitOverloadExpr(S); +} + +void StmtProfiler::VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getQueriedType()); +} + +void StmtProfiler::VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getLhsType()); + VisitType(S->getRhsType()); +} + +void StmtProfiler::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitType(S->getQueriedType()); +} + +void StmtProfiler::VisitExpressionTraitExpr(ExpressionTraitExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getTrait()); + VisitExpr(S->getQueriedExpression()); +} + +void +StmtProfiler::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *S) { + VisitExpr(S); + VisitName(S->getDeclName()); + VisitNestedNameSpecifier(S->getQualifier()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitExprWithCleanups(ExprWithCleanups *S) { + VisitExpr(S); +} + +void +StmtProfiler::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *S) { + VisitExpr(S); + VisitType(S->getTypeAsWritten()); +} + +void +StmtProfiler::VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *S) { + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMember()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *S) { + ID.AddBoolean(S->isImplicitAccess()); + if (!S->isImplicitAccess()) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); + } + VisitNestedNameSpecifier(S->getQualifier()); + VisitName(S->getMemberName()); + ID.AddBoolean(S->hasExplicitTemplateArgs()); + if (S->hasExplicitTemplateArgs()) + VisitTemplateArguments(S->getTemplateArgs(), S->getNumTemplateArgs()); +} + +void StmtProfiler::VisitCXXNoexceptExpr(CXXNoexceptExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getPack()); +} + +void StmtProfiler::VisitSubstNonTypeTemplateParmPackExpr( + SubstNonTypeTemplateParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + VisitTemplateArgument(S->getArgumentPack()); +} + +void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) { + VisitExpr(E); +} + +void StmtProfiler::VisitObjCStringLiteral(ObjCStringLiteral *S) { + VisitExpr(S); +} + +void StmtProfiler::VisitObjCEncodeExpr(ObjCEncodeExpr *S) { + VisitExpr(S); + VisitType(S->getEncodedType()); +} + +void StmtProfiler::VisitObjCSelectorExpr(ObjCSelectorExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); +} + +void StmtProfiler::VisitObjCProtocolExpr(ObjCProtocolExpr *S) { + VisitExpr(S); + VisitDecl(S->getProtocol()); +} + +void StmtProfiler::VisitObjCIvarRefExpr(ObjCIvarRefExpr *S) { + VisitExpr(S); + VisitDecl(S->getDecl()); + ID.AddBoolean(S->isArrow()); + ID.AddBoolean(S->isFreeIvar()); +} + +void StmtProfiler::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *S) { + VisitExpr(S); + if (S->isImplicitProperty()) { + VisitDecl(S->getImplicitPropertyGetter()); + VisitDecl(S->getImplicitPropertySetter()); + } else { + VisitDecl(S->getExplicitProperty()); + } + if (S->isSuperReceiver()) { + ID.AddBoolean(S->isSuperReceiver()); + VisitType(S->getSuperReceiverType()); + } +} + +void StmtProfiler::VisitObjCMessageExpr(ObjCMessageExpr *S) { + VisitExpr(S); + VisitName(S->getSelector()); + VisitDecl(S->getMethodDecl()); +} + +void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) { + VisitExpr(S); + ID.AddBoolean(S->isArrow()); +} + +void StmtProfiler::VisitDecl(Decl *D) { + ID.AddInteger(D? D->getKind() : 0); + + if (Canonical && D) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + ID.AddInteger(NTTP->getDepth()); + ID.AddInteger(NTTP->getIndex()); + ID.AddBoolean(NTTP->isParameterPack()); + VisitType(NTTP->getType()); + return; + } + + if (ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { + // The Itanium C++ ABI uses the type, scope depth, and scope + // index of a parameter when mangling expressions that involve + // function parameters, so we will use the parameter's type for + // establishing function parameter identity. That way, our + // definition of "equivalent" (per C++ [temp.over.link]) is at + // least as strong as the definition of "equivalent" used for + // name mangling. + VisitType(Parm->getType()); + ID.AddInteger(Parm->getFunctionScopeDepth()); + ID.AddInteger(Parm->getFunctionScopeIndex()); + return; + } + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(D)) { + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getIndex()); + ID.AddBoolean(TTP->isParameterPack()); + return; + } + } + + ID.AddPointer(D? D->getCanonicalDecl() : 0); +} + +void StmtProfiler::VisitType(QualType T) { + if (Canonical) + T = Context.getCanonicalType(T); + + ID.AddPointer(T.getAsOpaquePtr()); +} + +void StmtProfiler::VisitName(DeclarationName Name) { + ID.AddPointer(Name.getAsOpaquePtr()); +} + +void StmtProfiler::VisitNestedNameSpecifier(NestedNameSpecifier *NNS) { + if (Canonical) + NNS = Context.getCanonicalNestedNameSpecifier(NNS); + ID.AddPointer(NNS); +} + +void StmtProfiler::VisitTemplateName(TemplateName Name) { + if (Canonical) + Name = Context.getCanonicalTemplateName(Name); + + Name.Profile(ID); +} + +void StmtProfiler::VisitTemplateArguments(const TemplateArgumentLoc *Args, + unsigned NumArgs) { + ID.AddInteger(NumArgs); + for (unsigned I = 0; I != NumArgs; ++I) + VisitTemplateArgument(Args[I].getArgument()); +} + +void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { + // Mostly repetitive with TemplateArgument::Profile! + ID.AddInteger(Arg.getKind()); + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + VisitTemplateName(Arg.getAsTemplateOrTemplatePattern()); + break; + + case TemplateArgument::Declaration: + VisitDecl(Arg.getAsDecl()); + break; + + case TemplateArgument::Integral: + Arg.getAsIntegral()->Profile(ID); + VisitType(Arg.getIntegralType()); + break; + + case TemplateArgument::Expression: + Visit(Arg.getAsExpr()); + break; + + case TemplateArgument::Pack: + const TemplateArgument *Pack = Arg.pack_begin(); + for (unsigned i = 0, e = Arg.pack_size(); i != e; ++i) + VisitTemplateArgument(Pack[i]); + break; + } +} + +void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, + bool Canonical) { + StmtProfiler Profiler(ID, Context, Canonical); + Profiler.Visit(this); +} diff --git a/contrib/llvm/tools/clang/lib/AST/StmtViz.cpp b/contrib/llvm/tools/clang/lib/AST/StmtViz.cpp new file mode 100644 index 000000000000..8be287e7cb21 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/StmtViz.cpp @@ -0,0 +1,62 @@ +//===--- 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" + +using namespace clang; + +void Stmt::viewAST() const { +#ifndef NDEBUG + llvm::ViewGraph(this,"AST"); +#else + llvm::errs() << "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 { + DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {} + + 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/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp new file mode 100644 index 000000000000..6114a5a051be --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/TemplateBase.cpp @@ -0,0 +1,491 @@ +//===--- TemplateBase.cpp - Common template AST class 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 common classes used throughout C++ template +// representations. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/TemplateBase.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Basic/Diagnostic.h" +#include "llvm/ADT/FoldingSet.h" +#include <algorithm> +#include <cctype> + +using namespace clang; + +/// \brief Print a template integral argument value. +/// +/// \param TemplArg the TemplateArgument instance to print. +/// +/// \param Out the raw_ostream instance to use for printing. +static void printIntegral(const TemplateArgument &TemplArg, + llvm::raw_ostream &Out) { + const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); + const llvm::APSInt *Val = TemplArg.getAsIntegral(); + + if (T->isBooleanType()) { + Out << (Val->getBoolValue() ? "true" : "false"); + } else if (T->isCharType()) { + const unsigned char Ch = Val->getZExtValue(); + const std::string Str(1, Ch); + Out << ((Ch == '\'') ? "'\\" : "'"); + Out.write_escaped(Str, /*UseHexEscapes=*/ true); + Out << "'"; + } else { + Out << Val->toString(10); + } +} + +//===----------------------------------------------------------------------===// +// TemplateArgument Implementation +//===----------------------------------------------------------------------===// + +TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, + const TemplateArgument *Args, + unsigned NumArgs) { + if (NumArgs == 0) + return TemplateArgument(0, 0); + + TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs]; + std::copy(Args, Args + NumArgs, Storage); + return TemplateArgument(Storage, NumArgs); +} + +bool TemplateArgument::isDependent() const { + switch (getKind()) { + case Null: + assert(false && "Should not have a NULL template argument"); + return false; + + case Type: + return getAsType()->isDependentType(); + + case Template: + return getAsTemplate().isDependent(); + + case TemplateExpansion: + return true; + + case Declaration: + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case Integral: + // Never dependent + return false; + + case Expression: + return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent()); + + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) { + if (P->isDependent()) + return true; + } + + return false; + } + + return false; +} + +bool TemplateArgument::isPackExpansion() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case Pack: + case Template: + return false; + + case TemplateExpansion: + return true; + + case Type: + return isa<PackExpansionType>(getAsType()); + + case Expression: + return isa<PackExpansionExpr>(getAsExpr()); + } + + return false; +} + +bool TemplateArgument::containsUnexpandedParameterPack() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case TemplateExpansion: + break; + + case Type: + if (getAsType()->containsUnexpandedParameterPack()) + return true; + break; + + case Template: + if (getAsTemplate().containsUnexpandedParameterPack()) + return true; + break; + + case Expression: + if (getAsExpr()->containsUnexpandedParameterPack()) + return true; + break; + + case Pack: + for (pack_iterator P = pack_begin(), PEnd = pack_end(); P != PEnd; ++P) + if (P->containsUnexpandedParameterPack()) + return true; + + break; + } + + return false; +} + +llvm::Optional<unsigned> TemplateArgument::getNumTemplateExpansions() const { + assert(Kind == TemplateExpansion); + if (TemplateArg.NumExpansions) + return TemplateArg.NumExpansions - 1; + + return llvm::Optional<unsigned>(); +} + +void TemplateArgument::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context) const { + ID.AddInteger(Kind); + switch (Kind) { + case Null: + break; + + case Type: + getAsType().Profile(ID); + break; + + case Declaration: + ID.AddPointer(getAsDecl()? getAsDecl()->getCanonicalDecl() : 0); + break; + + case Template: + case TemplateExpansion: { + TemplateName Template = getAsTemplateOrTemplatePattern(); + if (TemplateTemplateParmDecl *TTP + = dyn_cast_or_null<TemplateTemplateParmDecl>( + Template.getAsTemplateDecl())) { + ID.AddBoolean(true); + ID.AddInteger(TTP->getDepth()); + ID.AddInteger(TTP->getPosition()); + ID.AddBoolean(TTP->isParameterPack()); + } else { + ID.AddBoolean(false); + ID.AddPointer(Context.getCanonicalTemplateName(Template) + .getAsVoidPointer()); + } + break; + } + + case Integral: + getAsIntegral()->Profile(ID); + getIntegralType().Profile(ID); + break; + + case Expression: + getAsExpr()->Profile(ID, Context, true); + break; + + case Pack: + ID.AddInteger(Args.NumArgs); + for (unsigned I = 0; I != Args.NumArgs; ++I) + Args.Args[I].Profile(ID, Context); + } +} + +bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { + if (getKind() != Other.getKind()) return false; + + switch (getKind()) { + case Null: + case Type: + case Declaration: + case Expression: + case Template: + case TemplateExpansion: + return TypeOrValue == Other.TypeOrValue; + + case Integral: + return getIntegralType() == Other.getIntegralType() && + *getAsIntegral() == *Other.getAsIntegral(); + + case Pack: + if (Args.NumArgs != Other.Args.NumArgs) return false; + for (unsigned I = 0, E = Args.NumArgs; I != E; ++I) + if (!Args.Args[I].structurallyEquals(Other.Args.Args[I])) + return false; + return true; + } + + // Suppress warnings. + return false; +} + +TemplateArgument TemplateArgument::getPackExpansionPattern() const { + assert(isPackExpansion()); + + switch (getKind()) { + case Type: + return getAsType()->getAs<PackExpansionType>()->getPattern(); + + case Expression: + return cast<PackExpansionExpr>(getAsExpr())->getPattern(); + + case TemplateExpansion: + return TemplateArgument(getAsTemplateOrTemplatePattern()); + + case Declaration: + case Integral: + case Pack: + case Null: + case Template: + return TemplateArgument(); + } + + return TemplateArgument(); +} + +void TemplateArgument::print(const PrintingPolicy &Policy, + llvm::raw_ostream &Out) const { + switch (getKind()) { + case Null: + Out << "<no value>"; + break; + + case Type: { + std::string TypeStr; + getAsType().getAsStringInternal(TypeStr, Policy); + Out << TypeStr; + break; + } + + case Declaration: { + bool Unnamed = true; + if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) { + if (ND->getDeclName()) { + Unnamed = false; + Out << ND->getNameAsString(); + } + } + + if (Unnamed) { + Out << "<anonymous>"; + } + break; + } + + case Template: + getAsTemplate().print(Out, Policy); + break; + + case TemplateExpansion: + getAsTemplateOrTemplatePattern().print(Out, Policy); + Out << "..."; + break; + + case Integral: { + printIntegral(*this, Out); + break; + } + + case Expression: + getAsExpr()->printPretty(Out, 0, Policy); + break; + + case Pack: + Out << "<"; + bool First = true; + for (TemplateArgument::pack_iterator P = pack_begin(), PEnd = pack_end(); + P != PEnd; ++P) { + if (First) + First = false; + else + Out << ", "; + + P->print(Policy, Out); + } + Out << ">"; + break; + } +} + +//===----------------------------------------------------------------------===// +// TemplateArgumentLoc Implementation +//===----------------------------------------------------------------------===// + +TemplateArgumentLocInfo::TemplateArgumentLocInfo() { + memset((void*)this, 0, sizeof(TemplateArgumentLocInfo)); +} + +SourceRange TemplateArgumentLoc::getSourceRange() const { + switch (Argument.getKind()) { + case TemplateArgument::Expression: + return getSourceExpression()->getSourceRange(); + + case TemplateArgument::Declaration: + return getSourceDeclExpression()->getSourceRange(); + + case TemplateArgument::Type: + if (TypeSourceInfo *TSI = getTypeSourceInfo()) + return TSI->getTypeLoc().getSourceRange(); + else + return SourceRange(); + + case TemplateArgument::Template: + if (getTemplateQualifierLoc()) + return SourceRange(getTemplateQualifierLoc().getBeginLoc(), + getTemplateNameLoc()); + return SourceRange(getTemplateNameLoc()); + + case TemplateArgument::TemplateExpansion: + if (getTemplateQualifierLoc()) + return SourceRange(getTemplateQualifierLoc().getBeginLoc(), + getTemplateEllipsisLoc()); + return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); + + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return SourceRange(); + } + + // Silence bonus gcc warning. + return SourceRange(); +} + +TemplateArgumentLoc +TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, + llvm::Optional<unsigned> &NumExpansions, + ASTContext &Context) const { + assert(Argument.isPackExpansion()); + + switch (Argument.getKind()) { + case TemplateArgument::Type: { + // FIXME: We shouldn't ever have to worry about missing + // type-source info! + TypeSourceInfo *ExpansionTSInfo = getTypeSourceInfo(); + if (!ExpansionTSInfo) + ExpansionTSInfo = Context.getTrivialTypeSourceInfo( + getArgument().getAsType(), + Ellipsis); + PackExpansionTypeLoc Expansion + = cast<PackExpansionTypeLoc>(ExpansionTSInfo->getTypeLoc()); + Ellipsis = Expansion.getEllipsisLoc(); + + TypeLoc Pattern = Expansion.getPatternLoc(); + NumExpansions = Expansion.getTypePtr()->getNumExpansions(); + + // FIXME: This is horrible. We know where the source location data is for + // the pattern, and we have the pattern's type, but we are forced to copy + // them into an ASTContext because TypeSourceInfo bundles them together + // and TemplateArgumentLoc traffics in TypeSourceInfo pointers. + TypeSourceInfo *PatternTSInfo + = Context.CreateTypeSourceInfo(Pattern.getType(), + Pattern.getFullDataSize()); + memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(), + Pattern.getOpaqueData(), Pattern.getFullDataSize()); + return TemplateArgumentLoc(TemplateArgument(Pattern.getType()), + PatternTSInfo); + } + + case TemplateArgument::Expression: { + PackExpansionExpr *Expansion + = cast<PackExpansionExpr>(Argument.getAsExpr()); + Expr *Pattern = Expansion->getPattern(); + Ellipsis = Expansion->getEllipsisLoc(); + NumExpansions = Expansion->getNumExpansions(); + return TemplateArgumentLoc(Pattern, Pattern); + } + + case TemplateArgument::TemplateExpansion: + Ellipsis = getTemplateEllipsisLoc(); + NumExpansions = Argument.getNumTemplateExpansions(); + return TemplateArgumentLoc(Argument.getPackExpansionPattern(), + getTemplateQualifierLoc(), + getTemplateNameLoc()); + + case TemplateArgument::Declaration: + case TemplateArgument::Template: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return TemplateArgumentLoc(); + } + + return TemplateArgumentLoc(); +} + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + // This is bad, but not as bad as crashing because of argument + // count mismatches. + return DB << "(null template argument)"; + + case TemplateArgument::Type: + return DB << Arg.getAsType(); + + case TemplateArgument::Declaration: + return DB << Arg.getAsDecl(); + + case TemplateArgument::Integral: + return DB << Arg.getAsIntegral()->toString(10); + + case TemplateArgument::Template: + return DB << Arg.getAsTemplate(); + + case TemplateArgument::TemplateExpansion: + return DB << Arg.getAsTemplateOrTemplatePattern() << "..."; + + case TemplateArgument::Expression: { + // This shouldn't actually ever happen, so it's okay that we're + // regurgitating an expression here. + // FIXME: We're guessing at LangOptions! + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + LangOptions LangOpts; + LangOpts.CPlusPlus = true; + PrintingPolicy Policy(LangOpts); + Arg.getAsExpr()->printPretty(OS, 0, Policy); + return DB << OS.str(); + } + + case TemplateArgument::Pack: { + // FIXME: We're guessing at LangOptions! + llvm::SmallString<32> Str; + llvm::raw_svector_ostream OS(Str); + LangOptions LangOpts; + LangOpts.CPlusPlus = true; + PrintingPolicy Policy(LangOpts); + Arg.print(Policy, OS); + return DB << OS.str(); + } + } + + return DB; +} diff --git a/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp new file mode 100644 index 000000000000..ebd07f486783 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/TemplateName.cpp @@ -0,0 +1,144 @@ +//===--- 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/TemplateBase.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; +using namespace llvm; + +TemplateArgument +SubstTemplateTemplateParmPackStorage::getArgumentPack() const { + return TemplateArgument(Arguments, size()); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, Context, Parameter, TemplateArgument(Arguments, size())); +} + +void SubstTemplateTemplateParmPackStorage::Profile(llvm::FoldingSetNodeID &ID, + ASTContext &Context, + TemplateTemplateParmDecl *Parameter, + const TemplateArgument &ArgPack) { + ID.AddPointer(Parameter); + ArgPack.Profile(ID, Context); +} + +TemplateName::NameKind TemplateName::getKind() const { + if (Storage.is<TemplateDecl *>()) + return Template; + if (Storage.is<DependentTemplateName *>()) + return DependentTemplate; + if (Storage.is<QualifiedTemplateName *>()) + return QualifiedTemplate; + + return getAsOverloadedTemplate()? OverloadedTemplate + : SubstTemplateTemplateParmPack; +} + +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()) { + if (isa<TemplateTemplateParmDecl>(Template)) + return true; + // FIXME: Hack, getDeclContext() can be null if Template is still + // initializing due to PCH reading, so we check it before using it. + // Should probably modify TemplateSpecializationType to allow constructing + // it without the isDependent() checking. + return Template->getDeclContext() && + Template->getDeclContext()->isDependentContext(); + } + + assert(!getAsOverloadedTemplate() && + "overloaded templates shouldn't survive to here"); + + return true; +} + +bool TemplateName::containsUnexpandedParameterPack() const { + if (TemplateDecl *Template = getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Template)) + return TTP->isParameterPack(); + + return false; + } + + if (DependentTemplateName *DTN = getAsDependentTemplateName()) + return DTN->getQualifier() && + DTN->getQualifier()->containsUnexpandedParameterPack(); + + return getAsSubstTemplateTemplateParmPack() != 0; +} + +void +TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy, + bool SuppressNNS) const { + if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>()) + OS << Template; + else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) { + if (!SuppressNNS) + QTN->getQualifier()->print(OS, Policy); + if (QTN->hasTemplateKeyword()) + OS << "template "; + OS << QTN->getDecl(); + } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) { + if (!SuppressNNS && DTN->getQualifier()) + DTN->getQualifier()->print(OS, Policy); + OS << "template "; + + if (DTN->isIdentifier()) + OS << DTN->getIdentifier()->getName(); + else + OS << "operator " << getOperatorSpelling(DTN->getOperator()); + } else if (SubstTemplateTemplateParmPackStorage *SubstPack + = getAsSubstTemplateTemplateParmPack()) + OS << SubstPack->getParameterPack()->getNameAsString(); + else { + OverloadedTemplateStorage *OTS = getAsOverloadedTemplate(); + (*OTS->begin())->printName(OS); + } +} + +const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, + TemplateName N) { + std::string NameStr; + raw_string_ostream OS(NameStr); + LangOptions LO; + LO.CPlusPlus = true; + LO.Bool = true; + N.print(OS, PrintingPolicy(LO)); + OS.flush(); + return DB << NameStr; +} + +void TemplateName::dump() const { + LangOptions LO; // FIXME! + LO.CPlusPlus = true; + LO.Bool = true; + print(llvm::errs(), PrintingPolicy(LO)); +} diff --git a/contrib/llvm/tools/clang/lib/AST/Type.cpp b/contrib/llvm/tools/clang/lib/AST/Type.cpp new file mode 100644 index 000000000000..d28755284477 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/Type.cpp @@ -0,0 +1,1930 @@ +//===--- 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/CharUnits.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 "clang/AST/TypeVisitor.h" +#include "clang/Basic/Specifiers.h" +#include "llvm/ADT/APSInt.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +using namespace clang; + +bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { + return (*this != Other) && + // CVR qualifiers superset + (((Mask & CVRMask) | (Other.Mask & CVRMask)) == (Mask & CVRMask)) && + // ObjC GC qualifiers superset + ((getObjCGCAttr() == Other.getObjCGCAttr()) || + (hasObjCGCAttr() && !Other.hasObjCGCAttr())) && + // Address space superset. + ((getAddressSpace() == Other.getAddressSpace()) || + (hasAddressSpace()&& !Other.hasAddressSpace())); +} + +bool QualType::isConstant(QualType T, ASTContext &Ctx) { + if (T.isConstQualified()) + return true; + + if (const ArrayType *AT = Ctx.getAsArrayType(T)) + return AT->getElementType().isConstant(Ctx); + + return false; +} + +unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, + QualType ElementType, + const llvm::APInt &NumElements) { + llvm::APSInt SizeExtended(NumElements, true); + unsigned SizeTypeBits = Context.getTypeSize(Context.getSizeType()); + SizeExtended = SizeExtended.extend(std::max(SizeTypeBits, + SizeExtended.getBitWidth()) * 2); + + uint64_t ElementSize + = Context.getTypeSizeInChars(ElementType).getQuantity(); + llvm::APSInt TotalSize(llvm::APInt(SizeExtended.getBitWidth(), ElementSize)); + TotalSize *= SizeExtended; + + return TotalSize.getActiveBits(); +} + +unsigned ConstantArrayType::getMaxSizeBits(ASTContext &Context) { + unsigned Bits = Context.getTypeSize(Context.getSizeType()); + + // GCC appears to only allow 63 bits worth of address space when compiling + // for 64-bit, so we do the same. + if (Bits == 64) + --Bits; + + return Bits; +} + +DependentSizedArrayType::DependentSizedArrayType(const ASTContext &Context, + QualType et, QualType can, + Expr *e, ArraySizeModifier sm, + unsigned tq, + SourceRange brackets) + : ArrayType(DependentSizedArray, et, can, sm, tq, + (et->containsUnexpandedParameterPack() || + (e && e->containsUnexpandedParameterPack()))), + Context(Context), SizeExpr((Stmt*) e), Brackets(brackets) +{ +} + +void DependentSizedArrayType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + QualType ET, + ArraySizeModifier SizeMod, + unsigned TypeQuals, + Expr *E) { + ID.AddPointer(ET.getAsOpaquePtr()); + ID.AddInteger(SizeMod); + ID.AddInteger(TypeQuals); + E->Profile(ID, Context, true); +} + +DependentSizedExtVectorType::DependentSizedExtVectorType(const + ASTContext &Context, + QualType ElementType, + QualType can, + Expr *SizeExpr, + SourceLocation loc) + : Type(DependentSizedExtVector, can, /*Dependent=*/true, + ElementType->isVariablyModifiedType(), + (ElementType->containsUnexpandedParameterPack() || + (SizeExpr && SizeExpr->containsUnexpandedParameterPack()))), + Context(Context), SizeExpr(SizeExpr), ElementType(ElementType), + loc(loc) +{ +} + +void +DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + QualType ElementType, Expr *SizeExpr) { + ID.AddPointer(ElementType.getAsOpaquePtr()); + SizeExpr->Profile(ID, Context, true); +} + +VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, + VectorKind vecKind) + : Type(Vector, canonType, vecType->isDependentType(), + vecType->isVariablyModifiedType(), + vecType->containsUnexpandedParameterPack()), + ElementType(vecType) +{ + VectorTypeBits.VecKind = vecKind; + VectorTypeBits.NumElements = nElements; +} + +VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, + QualType canonType, VectorKind vecKind) + : Type(tc, canonType, vecType->isDependentType(), + vecType->isVariablyModifiedType(), + vecType->containsUnexpandedParameterPack()), + ElementType(vecType) +{ + VectorTypeBits.VecKind = vecKind; + VectorTypeBits.NumElements = nElements; +} + +/// 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)) + return 0; + + // If this is a typedef for an array type, strip the typedef off without + // losing all typedef information. + return cast<ArrayType>(getUnqualifiedDesugaredType()) + ->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. +QualType QualType::getDesugaredType(QualType T, const ASTContext &Context) { + SplitQualType split = getSplitDesugaredType(T); + return Context.getQualifiedType(split.first, split.second); +} + +SplitQualType QualType::getSplitDesugaredType(QualType T) { + QualifierCollector Qs; + + QualType Cur = T; + while (true) { + const Type *CurTy = Qs.strip(Cur); + switch (CurTy->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *Ty = cast<Class##Type>(CurTy); \ + if (!Ty->isSugared()) \ + return SplitQualType(Ty, Qs); \ + Cur = Ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } +} + +SplitQualType QualType::getSplitUnqualifiedTypeImpl(QualType type) { + SplitQualType split = type.split(); + + // All the qualifiers we've seen so far. + Qualifiers quals = split.second; + + // The last type node we saw with any nodes inside it. + const Type *lastTypeWithQuals = split.first; + + while (true) { + QualType next; + + // Do a single-step desugar, aborting the loop if the type isn't + // sugared. + switch (split.first->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Type::Class: { \ + const Class##Type *ty = cast<Class##Type>(split.first); \ + if (!ty->isSugared()) goto done; \ + next = ty->desugar(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + + // Otherwise, split the underlying type. If that yields qualifiers, + // update the information. + split = next.split(); + if (!split.second.empty()) { + lastTypeWithQuals = split.first; + quals.addConsistentQualifiers(split.second); + } + } + + done: + return SplitQualType(lastTypeWithQuals, quals); +} + +QualType QualType::IgnoreParens(QualType T) { + // FIXME: this seems inherently un-qualifiers-safe. + while (const ParenType *PT = T->getAs<ParenType>()) + T = PT->getInnerType(); + return T; +} + +/// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic +/// sugar off the given type. This should produce an object of the +/// same dynamic type as the canonical type. +const Type *Type::getUnqualifiedDesugaredType() const { + const Type *Cur = this; + + while (true) { + switch (Cur->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Parent) +#define TYPE(Class, Parent) \ + case Class: { \ + const Class##Type *Ty = cast<Class##Type>(Cur); \ + if (!Ty->isSugared()) return Cur; \ + Cur = Ty->desugar().getTypePtr(); \ + break; \ + } +#include "clang/AST/TypeNodes.def" + } + } +} + +/// isVoidType - Helper method to determine if this is the 'void' type. +bool Type::isVoidType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Void; + return false; +} + +bool Type::isDerivedType() const { + switch (CanonicalType->getTypeClass()) { + 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 = getAs<RecordType>()) + return RT->getDecl()->isClass(); + return false; +} +bool Type::isStructureType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isStruct(); + return false; +} +bool Type::isStructureOrClassType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return false; +} +bool Type::isVoidPointerType() const { + if (const PointerType *PT = getAs<PointerType>()) + return PT->getPointeeType()->isVoidType(); + return false; +} + +bool Type::isUnionType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isUnion(); + return false; +} + +bool Type::isComplexType() const { + if (const ComplexType *CT = dyn_cast<ComplexType>(CanonicalType)) + return CT->getElementType()->isFloatingType(); + return false; +} + +bool Type::isComplexIntegerType() const { + // Check for GCC complex integer extension. + return getAsComplexIntegerType(); +} + +const ComplexType *Type::getAsComplexIntegerType() const { + if (const ComplexType *Complex = getAs<ComplexType>()) + if (Complex->getElementType()->isIntegerType()) + return Complex; + return 0; +} + +QualType Type::getPointeeType() const { + if (const PointerType *PT = getAs<PointerType>()) + return PT->getPointeeType(); + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) + return OPT->getPointeeType(); + if (const BlockPointerType *BPT = getAs<BlockPointerType>()) + return BPT->getPointeeType(); + if (const ReferenceType *RT = getAs<ReferenceType>()) + return RT->getPointeeType(); + return QualType(); +} + +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>(getUnqualifiedDesugaredType()); + } + 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>(getUnqualifiedDesugaredType()); + } + + return 0; +} + +ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) + : Type(ObjCObject, Canonical, false, false, false), + BaseType(Base) +{ + ObjCObjectTypeBits.NumProtocols = NumProtocols; + assert(getNumProtocols() == NumProtocols && + "bitfield overflow in protocol count"); + if (NumProtocols) + memcpy(getProtocolStorage(), Protocols, + NumProtocols * sizeof(ObjCProtocolDecl*)); +} + +const ObjCObjectType *Type::getAsObjCQualifiedInterfaceType() const { + // There is no sugar for ObjCObjectType'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. + if (const ObjCObjectType *T = getAs<ObjCObjectType>()) + if (T->getNumProtocols() && T->getInterface()) + return T; + return 0; +} + +bool Type::isObjCQualifiedInterfaceType() const { + return getAsObjCQualifiedInterfaceType() != 0; +} + +const ObjCObjectPointerType *Type::getAsObjCQualifiedIdType() const { + // There is no sugar for ObjCQualifiedIdType's, just return the canonical + // type pointer if it is the right class. + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (OPT->isObjCQualifiedIdType()) + return OPT; + } + return 0; +} + +const ObjCObjectPointerType *Type::getAsObjCQualifiedClassType() const { + // There is no sugar for ObjCQualifiedClassType's, just return the canonical + // type pointer if it is the right class. + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (OPT->isObjCQualifiedClassType()) + return OPT; + } + return 0; +} + +const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { + if (const ObjCObjectPointerType *OPT = getAs<ObjCObjectPointerType>()) { + if (OPT->getInterfaceType()) + return OPT; + } + return 0; +} + +const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { + if (const PointerType *PT = getAs<PointerType>()) + if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + return 0; +} + +CXXRecordDecl *Type::getAsCXXRecordDecl() const { + if (const RecordType *RT = getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + else if (const InjectedClassNameType *Injected + = getAs<InjectedClassNameType>()) + return Injected->getDecl(); + + return 0; +} + +namespace { + class GetContainedAutoVisitor : + public TypeVisitor<GetContainedAutoVisitor, AutoType*> { + public: + using TypeVisitor<GetContainedAutoVisitor, AutoType*>::Visit; + AutoType *Visit(QualType T) { + if (T.isNull()) + return 0; + return Visit(T.getTypePtr()); + } + + // The 'auto' type itself. + AutoType *VisitAutoType(const AutoType *AT) { + return const_cast<AutoType*>(AT); + } + + // Only these types can contain the desired 'auto' type. + AutoType *VisitPointerType(const PointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitBlockPointerType(const BlockPointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitReferenceType(const ReferenceType *T) { + return Visit(T->getPointeeTypeAsWritten()); + } + AutoType *VisitMemberPointerType(const MemberPointerType *T) { + return Visit(T->getPointeeType()); + } + AutoType *VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitVectorType(const VectorType *T) { + return Visit(T->getElementType()); + } + AutoType *VisitFunctionType(const FunctionType *T) { + return Visit(T->getResultType()); + } + AutoType *VisitParenType(const ParenType *T) { + return Visit(T->getInnerType()); + } + AutoType *VisitAttributedType(const AttributedType *T) { + return Visit(T->getModifiedType()); + } + }; +} + +AutoType *Type::getContainedAutoType() const { + return GetContainedAutoVisitor().Visit(this); +} + +bool Type::isIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + return false; +} + +bool Type::hasIntegerRepresentation() const { + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isIntegerType(); + else + return isIntegerType(); +} + +/// \brief Determine whether this type is an integral type. +/// +/// This routine determines whether the given type is an integral type per +/// C++ [basic.fundamental]p7. Although the C standard does not define the +/// term "integral type", it has a similar term "integer type", and in C++ +/// the two terms are equivalent. However, C's "integer type" includes +/// enumeration types, while C++'s "integer type" does not. The \c ASTContext +/// parameter is used to determine whether we should be following the C or +/// C++ rules when determining whether this type is an integral/integer type. +/// +/// For cases where C permits "an integer type" and C++ permits "an integral +/// type", use this routine. +/// +/// For cases where C permits "an integer type" and C++ permits "an integral +/// or enumeration type", use \c isIntegralOrEnumerationType() instead. +/// +/// \param Ctx The context in which this type occurs. +/// +/// \returns true if the type is considered an integral type, false otherwise. +bool Type::isIntegralType(ASTContext &Ctx) const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + if (!Ctx.getLangOptions().CPlusPlus) + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete(); // Complete enum types are integral in C. + + return false; +} + +bool Type::isIntegralOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete(); + + return false; +} + +bool Type::isIntegralOrUnscopedEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::Int128; + + // Check for a complete enum type; incomplete enum types are not properly an + // enumeration type in the sense required here. + // C++0x: However, if the underlying type of the enum is fixed, it is + // considered complete. + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + + return false; +} + + +bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + 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; + return false; +} + +bool Type::isWideCharType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() == BuiltinType::WChar_S || + BT->getKind() == BuiltinType::WChar_U; + return false; +} + +/// \brief Determine whether this type is any of the built-in character +/// types. +bool Type::isAnyCharacterType() const { + const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType); + if (BT == 0) return false; + switch (BT->getKind()) { + default: return false; + case BuiltinType::Char_U: + case BuiltinType::UChar: + case BuiltinType::WChar_U: + case BuiltinType::Char16: + case BuiltinType::Char32: + case BuiltinType::Char_S: + case BuiltinType::SChar: + case BuiltinType::WChar_S: + return true; + } +} + +/// 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 +bool Type::isSignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::Int128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) + return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + } + + return false; +} + +bool Type::isSignedIntegerOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Char_S && + BT->getKind() <= BuiltinType::Int128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isSignedIntegerType(); + } + + return false; +} + +bool Type::hasSignedIntegerRepresentation() const { + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isSignedIntegerType(); + else + return isSignedIntegerType(); +} + +/// 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 +bool Type::isUnsignedIntegerType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::UInt128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + // Incomplete enum types are not treated as integer types. + // FIXME: In C++, enum types are never integer types. + if (ET->getDecl()->isComplete() && !ET->getDecl()->isScoped()) + return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + } + + return false; +} + +bool Type::isUnsignedIntegerOrEnumerationType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { + return BT->getKind() >= BuiltinType::Bool && + BT->getKind() <= BuiltinType::UInt128; + } + + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { + if (ET->getDecl()->isComplete()) + return ET->getDecl()->getIntegerType()->isUnsignedIntegerType(); + } + + return false; +} + +bool Type::hasUnsignedIntegerRepresentation() const { + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isUnsignedIntegerType(); + else + return isUnsignedIntegerType(); +} + +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(); + return false; +} + +bool Type::hasFloatingRepresentation() const { + if (const VectorType *VT = dyn_cast<VectorType>(CanonicalType)) + return VT->getElementType()->isFloatingType(); + else + return isFloatingType(); +} + +bool Type::isRealFloatingType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->isFloatingPoint(); + 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 EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + 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. + // + // C++0x: Enumerations are not arithmetic types. For now, just return + // false for scoped enumerations since that will disable any + // unwanted implicit conversions. + return !ET->getDecl()->isScoped() && ET->getDecl()->isComplete(); + return isa<ComplexType>(CanonicalType); +} + +bool Type::isScalarType() const { + if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) + return BT->getKind() > BuiltinType::Void && + BT->getKind() <= BuiltinType::NullPtr; + if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) + // Enums are scalar types, but only if they are defined. Incomplete enums + // are not treated as scalar types. + return ET->getDecl()->isComplete(); + return isa<PointerType>(CanonicalType) || + isa<BlockPointerType>(CanonicalType) || + isa<MemberPointerType>(CanonicalType) || + isa<ComplexType>(CanonicalType) || + isa<ObjCObjectPointerType>(CanonicalType); +} + +Type::ScalarTypeKind Type::getScalarTypeKind() const { + assert(isScalarType()); + + const Type *T = CanonicalType.getTypePtr(); + if (const BuiltinType *BT = dyn_cast<BuiltinType>(T)) { + if (BT->getKind() == BuiltinType::Bool) return STK_Bool; + if (BT->getKind() == BuiltinType::NullPtr) return STK_Pointer; + if (BT->isInteger()) return STK_Integral; + if (BT->isFloatingPoint()) return STK_Floating; + llvm_unreachable("unknown scalar builtin type"); + } else if (isa<PointerType>(T) || + isa<BlockPointerType>(T) || + isa<ObjCObjectPointerType>(T)) { + return STK_Pointer; + } else if (isa<MemberPointerType>(T)) { + return STK_MemberPointer; + } else if (isa<EnumType>(T)) { + assert(cast<EnumType>(T)->getDecl()->isComplete()); + return STK_Integral; + } else if (const ComplexType *CT = dyn_cast<ComplexType>(T)) { + if (CT->getElementType()->isRealFloatingType()) + return STK_FloatingComplex; + return STK_IntegralComplex; + } + + llvm_unreachable("unknown scalar type"); + return STK_Pointer; +} + +/// \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; + } + + 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 { + 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 Builtin: + // Void is the only incomplete builtin type. Per C99 6.2.5p19, it can never + // be completed. + return isVoidType(); + case Enum: + // An enumeration with fixed underlying type is complete (C++0x 7.2p3). + if (cast<EnumType>(CanonicalType)->getDecl()->isFixed()) + return false; + // Fall through. + case Record: + // 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 ConstantArray: + // An array is incomplete if its element type is incomplete + // (C++ [dcl.array]p1). + // We don't handle variable arrays (they're not allowed in C++) or + // dependent-sized arrays (dependent types are never treated as incomplete). + return cast<ArrayType>(CanonicalType)->getElementType()->isIncompleteType(); + case IncompleteArray: + // An array of unknown size is an incomplete type (C99 6.2.5p22). + return true; + case ObjCObject: + return cast<ObjCObjectType>(CanonicalType)->getBaseType() + ->isIncompleteType(); + case ObjCInterface: + // ObjC interfaces are incomplete if they are @class, not @interface. + return cast<ObjCInterfaceType>(CanonicalType)->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. Except for incomplete arrays of PODs, which + // are PODs according to the standard. + if (isIncompleteArrayType() && + cast<ArrayType>(CanonicalType)->getElementType()->isPODType()) + return true; + if (isIncompleteType()) + return false; + + switch (CanonicalType->getTypeClass()) { + // Everything not explicitly mentioned is not POD. + default: return false; + case VariableArray: + case ConstantArray: + // IncompleteArray is handled above. + return cast<ArrayType>(CanonicalType)->getElementType()->isPODType(); + + case Builtin: + case Complex: + case Pointer: + case MemberPointer: + case Vector: + case ExtVector: + case ObjCObjectPointer: + case BlockPointer: + 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::isLiteralType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p10: + // A type is a literal type if it is: + // [...] + // -- an array of literal type + // Extension: variable arrays cannot be literal types, since they're + // runtime-sized. + if (isVariableArrayType()) + return false; + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types; those are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // C++0x [basic.types]p10: + // A type is a literal type if it is: + // -- a scalar type; or + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + // -- a reference type; or + if (BaseTy->isReferenceType()) return true; + // -- a class type that has all of the following properties: + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // -- a trivial destructor, + if (!ClassDecl->hasTrivialDestructor()) return false; + // -- every constructor call and full-expression in the + // brace-or-equal-initializers for non-static data members (if any) + // is a constant expression, + // FIXME: C++0x: Clang doesn't yet support non-static data member + // declarations with initializers, or constexprs. + // -- it is an aggregate type or has at least one constexpr + // constructor or constructor template that is not a copy or move + // constructor, and + if (!ClassDecl->isAggregate() && + !ClassDecl->hasConstExprNonCopyMoveConstructor()) + return false; + // -- all non-static data members and base classes of literal types + if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false; + } + + return true; + } + return false; +} + +bool Type::isTrivialType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p9: + // Scalar types, trivial class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (!ClassDecl->isTrivial()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + +bool Type::isTriviallyCopyableType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p9 + // Scalar types, trivially copyable class types, arrays of such types, and + // cv-qualified versions of these types are collectively called trivial + // types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array types + // which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + if (!ClassDecl->isTriviallyCopyable()) return false; + } + + return true; + } + + // No other types can match. + return false; +} + +bool Type::isStandardLayoutType() const { + if (isDependentType()) + return false; + + // C++0x [basic.types]p9: + // Scalar types, standard-layout class types, arrays of such types, and + // cv-qualified versions of these types are collectively called + // standard-layout types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) + if (!ClassDecl->isStandardLayout()) + return false; + + // Default to 'true' for non-C++ class types. + // FIXME: This is a bit dubious, but plain C structs should trivially meet + // all the requirements of standard layout classes. + return true; + } + + // No other types can match. + return false; +} + +// This is effectively the intersection of isTrivialType and +// isStandardLayoutType. We implement it dircetly to avoid redundant +// conversions from a type to a CXXRecordDecl. +bool Type::isCXX11PODType() const { + if (isDependentType()) + return false; + + // C++11 [basic.types]p9: + // Scalar types, POD classes, arrays of such types, and cv-qualified + // versions of these types are collectively called trivial types. + const Type *BaseTy = getBaseElementTypeUnsafe(); + assert(BaseTy && "NULL element type"); + + // Return false for incomplete types after skipping any incomplete array + // types which are expressly allowed by the standard and thus our API. + if (BaseTy->isIncompleteType()) + return false; + + // As an extension, Clang treats vector types as Scalar types. + if (BaseTy->isScalarType() || BaseTy->isVectorType()) return true; + if (const RecordType *RT = BaseTy->getAs<RecordType>()) { + if (const CXXRecordDecl *ClassDecl = + dyn_cast<CXXRecordDecl>(RT->getDecl())) { + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class [...] + if (!ClassDecl->isTrivial()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class [...] + if (!ClassDecl->isStandardLayout()) return false; + + // C++11 [class]p10: + // A POD struct is a non-union class that is both a trivial class and + // a standard-layout class, and has no non-static data members of type + // non-POD struct, non-POD union (or array of such types). [...] + // + // We don't directly query the recursive aspect as the requiremets for + // both standard-layout classes and trivial classes apply recursively + // already. + } + + return true; + } + + // No other types can match. + return false; +} + +bool Type::isPromotableIntegerType() const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + 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; + } + + // Enumerated types are promotable to their compatible integer types + // (C99 6.3.1.1) a.k.a. its underlying type (C++ [conv.prom]p2). + if (const EnumType *ET = getAs<EnumType>()){ + if (this->isDependentType() || ET->getDecl()->getPromotionType().isNull() + || ET->getDecl()->isScoped()) + return false; + + const BuiltinType *BT + = ET->getDecl()->getPromotionType()->getAs<BuiltinType>(); + return BT->getKind() == BuiltinType::Int + || BT->getKind() == BuiltinType::UInt; + } + + return false; +} + +bool Type::isNullPtrType() const { + if (const BuiltinType *BT = getAs<BuiltinType>()) + 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 SubstTemplateTypeParm: + case TemplateSpecialization: + case Elaborated: + case DependentName: + case DependentTemplateSpecialization: + case ObjCInterface: + case ObjCObject: + case ObjCObjectPointer: // FIXME: object pointers aren't really specifiers + return true; + default: + return false; + } +} + +ElaboratedTypeKeyword +TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { + switch (TypeSpec) { + default: return ETK_None; + case TST_typename: return ETK_Typename; + case TST_class: return ETK_Class; + case TST_struct: return ETK_Struct; + case TST_union: return ETK_Union; + case TST_enum: return ETK_Enum; + } +} + +TagTypeKind +TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { + switch(TypeSpec) { + case TST_class: return TTK_Class; + case TST_struct: return TTK_Struct; + case TST_union: return TTK_Union; + case TST_enum: return TTK_Enum; + } + + llvm_unreachable("Type specifier is not a tag type kind."); + return TTK_Union; +} + +ElaboratedTypeKeyword +TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { + switch (Kind) { + case TTK_Class: return ETK_Class; + case TTK_Struct: return ETK_Struct; + case TTK_Union: return ETK_Union; + case TTK_Enum: return ETK_Enum; + } + llvm_unreachable("Unknown tag type kind."); +} + +TagTypeKind +TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + case ETK_Class: return TTK_Class; + case ETK_Struct: return TTK_Struct; + case ETK_Union: return TTK_Union; + case ETK_Enum: return TTK_Enum; + case ETK_None: // Fall through. + case ETK_Typename: + llvm_unreachable("Elaborated type keyword is not a tag type kind."); + } + llvm_unreachable("Unknown elaborated type keyword."); +} + +bool +TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + case ETK_None: + case ETK_Typename: + return false; + case ETK_Class: + case ETK_Struct: + case ETK_Union: + case ETK_Enum: + return true; + } + llvm_unreachable("Unknown elaborated type keyword."); +} + +const char* +TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { + switch (Keyword) { + case ETK_None: return ""; + case ETK_Typename: return "typename"; + case ETK_Class: return "class"; + case ETK_Struct: return "struct"; + case ETK_Union: return "union"; + case ETK_Enum: return "enum"; + } + + llvm_unreachable("Unknown elaborated type keyword."); + return ""; +} + +DependentTemplateSpecializationType::DependentTemplateSpecializationType( + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *NNS, const IdentifierInfo *Name, + unsigned NumArgs, const TemplateArgument *Args, + QualType Canon) + : TypeWithKeyword(Keyword, DependentTemplateSpecialization, Canon, true, + /*VariablyModified=*/false, + NNS && NNS->containsUnexpandedParameterPack()), + NNS(NNS), Name(Name), NumArgs(NumArgs) { + assert((!NNS || NNS->isDependent()) && + "DependentTemplateSpecializatonType requires dependent qualifier"); + for (unsigned I = 0; I != NumArgs; ++I) { + if (Args[I].containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + new (&getArgBuffer()[I]) TemplateArgument(Args[I]); + } +} + +void +DependentTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, + ElaboratedTypeKeyword Keyword, + NestedNameSpecifier *Qualifier, + const IdentifierInfo *Name, + unsigned NumArgs, + const TemplateArgument *Args) { + ID.AddInteger(Keyword); + ID.AddPointer(Qualifier); + ID.AddPointer(Name); + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + Args[Idx].Profile(ID, Context); +} + +bool Type::isElaboratedTypeSpecifier() const { + ElaboratedTypeKeyword Keyword; + if (const ElaboratedType *Elab = dyn_cast<ElaboratedType>(this)) + Keyword = Elab->getKeyword(); + else if (const DependentNameType *DepName = dyn_cast<DependentNameType>(this)) + Keyword = DepName->getKeyword(); + else if (const DependentTemplateSpecializationType *DepTST = + dyn_cast<DependentTemplateSpecializationType>(this)) + Keyword = DepTST->getKeyword(); + else + return false; + + return TypeWithKeyword::KeywordIsTagTypeKind(Keyword); +} + +const char *Type::getTypeClassName() const { + switch (TypeBits.TC) { +#define ABSTRACT_TYPE(Derived, Base) +#define TYPE(Derived, Base) case Derived: return #Derived; +#include "clang/AST/TypeNodes.def" + } + + llvm_unreachable("Invalid type class."); + return 0; +} + +const char *BuiltinType::getName(const LangOptions &LO) const { + switch (getKind()) { + case Void: return "void"; + case Bool: return LO.Bool ? "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_S: + case WChar_U: return "wchar_t"; + case Char16: return "char16_t"; + case Char32: return "char32_t"; + case NullPtr: return "nullptr_t"; + case Overload: return "<overloaded function type>"; + case BoundMember: return "<bound member function type>"; + case Dependent: return "<dependent type>"; + case UnknownAny: return "<unknown type>"; + case ObjCId: return "id"; + case ObjCClass: return "Class"; + case ObjCSel: return "SEL"; + } + + llvm_unreachable("Invalid builtin type."); + return 0; +} + +QualType QualType::getNonLValueExprType(ASTContext &Context) const { + if (const ReferenceType *RefType = getTypePtr()->getAs<ReferenceType>()) + return RefType->getPointeeType(); + + // C++0x [basic.lval]: + // Class prvalues can have cv-qualified types; non-class prvalues always + // have cv-unqualified types. + // + // See also C99 6.3.2.1p2. + if (!Context.getLangOptions().CPlusPlus || + (!getTypePtr()->isDependentType() && !getTypePtr()->isRecordType())) + return getUnqualifiedType(); + + return *this; +} + +llvm::StringRef FunctionType::getNameForCallConv(CallingConv CC) { + switch (CC) { + case CC_Default: + llvm_unreachable("no name for default cc"); + return ""; + + case CC_C: return "cdecl"; + case CC_X86StdCall: return "stdcall"; + case CC_X86FastCall: return "fastcall"; + case CC_X86ThisCall: return "thiscall"; + case CC_X86Pascal: return "pascal"; + case CC_AAPCS: return "aapcs"; + case CC_AAPCS_VFP: return "aapcs-vfp"; + } + + llvm_unreachable("Invalid calling convention."); + return ""; +} + +FunctionProtoType::FunctionProtoType(QualType result, const QualType *args, + unsigned numArgs, QualType canonical, + const ExtProtoInfo &epi) + : FunctionType(FunctionProto, result, epi.Variadic, epi.TypeQuals, + epi.RefQualifier, canonical, + result->isDependentType(), + result->isVariablyModifiedType(), + result->containsUnexpandedParameterPack(), + epi.ExtInfo), + NumArgs(numArgs), NumExceptions(epi.NumExceptions), + ExceptionSpecType(epi.ExceptionSpecType) +{ + // Fill in the trailing argument array. + QualType *argSlot = reinterpret_cast<QualType*>(this+1); + for (unsigned i = 0; i != numArgs; ++i) { + if (args[i]->isDependentType()) + setDependent(); + + if (args[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + argSlot[i] = args[i]; + } + + if (getExceptionSpecType() == EST_Dynamic) { + // Fill in the exception array. + QualType *exnSlot = argSlot + numArgs; + for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { + if (epi.Exceptions[i]->isDependentType()) + setDependent(); + + if (epi.Exceptions[i]->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + exnSlot[i] = epi.Exceptions[i]; + } + } else if (getExceptionSpecType() == EST_ComputedNoexcept) { + // Store the noexcept expression and context. + Expr **noexSlot = reinterpret_cast<Expr**>(argSlot + numArgs); + *noexSlot = epi.NoexceptExpr; + } +} + +FunctionProtoType::NoexceptResult +FunctionProtoType::getNoexceptSpec(ASTContext &ctx) const { + ExceptionSpecificationType est = getExceptionSpecType(); + if (est == EST_BasicNoexcept) + return NR_Nothrow; + + if (est != EST_ComputedNoexcept) + return NR_NoNoexcept; + + Expr *noexceptExpr = getNoexceptExpr(); + if (!noexceptExpr) + return NR_BadNoexcept; + if (noexceptExpr->isValueDependent()) + return NR_Dependent; + + llvm::APSInt value; + bool isICE = noexceptExpr->isIntegerConstantExpr(value, ctx, 0, + /*evaluated*/false); + (void)isICE; + assert(isICE && "AST should not contain bad noexcept expressions."); + + return value.getBoolValue() ? NR_Nothrow : NR_Throw; +} + +bool FunctionProtoType::isTemplateVariadic() const { + for (unsigned ArgIdx = getNumArgs(); ArgIdx; --ArgIdx) + if (isa<PackExpansionType>(getArgType(ArgIdx - 1))) + return true; + + return false; +} + +void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, + const QualType *ArgTys, unsigned NumArgs, + const ExtProtoInfo &epi, + const ASTContext &Context) { + ID.AddPointer(Result.getAsOpaquePtr()); + for (unsigned i = 0; i != NumArgs; ++i) + ID.AddPointer(ArgTys[i].getAsOpaquePtr()); + ID.AddBoolean(epi.Variadic); + ID.AddInteger(epi.TypeQuals); + ID.AddInteger(epi.RefQualifier); + ID.AddInteger(epi.ExceptionSpecType); + if (epi.ExceptionSpecType == EST_Dynamic) { + for (unsigned i = 0; i != epi.NumExceptions; ++i) + ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); + } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ + epi.NoexceptExpr->Profile(ID, Context, true); + } + epi.ExtInfo.Profile(ID); +} + +void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Ctx) { + Profile(ID, getResultType(), arg_type_begin(), NumArgs, getExtProtoInfo(), + Ctx); +} + +QualType TypedefType::desugar() const { + return getDecl()->getUnderlyingType(); +} + +TypeOfExprType::TypeOfExprType(Expr *E, QualType can) + : Type(TypeOfExpr, can, E->isTypeDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + TOExpr(E) { +} + +QualType TypeOfExprType::desugar() const { + return getUnderlyingExpr()->getType(); +} + +void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); +} + +DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can) + : Type(Decltype, can, E->isTypeDependent(), + E->getType()->isVariablyModifiedType(), + E->containsUnexpandedParameterPack()), + E(E), + UnderlyingType(underlyingType) { +} + +DependentDecltypeType::DependentDecltypeType(const ASTContext &Context, Expr *E) + : DecltypeType(E, Context.DependentTy), Context(Context) { } + +void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &Context, Expr *E) { + E->Profile(ID, Context, true); +} + +TagType::TagType(TypeClass TC, const TagDecl *D, QualType can) + : Type(TC, can, D->isDependentType(), /*VariablyModified=*/false, + /*ContainsUnexpandedParameterPack=*/false), + decl(const_cast<TagDecl*>(D)) {} + +static TagDecl *getInterestingTagDecl(TagDecl *decl) { + for (TagDecl::redecl_iterator I = decl->redecls_begin(), + E = decl->redecls_end(); + I != E; ++I) { + if (I->isDefinition() || I->isBeingDefined()) + return *I; + } + // If there's no definition (not even in progress), return what we have. + return decl; +} + +UnaryTransformType::UnaryTransformType(QualType BaseType, + QualType UnderlyingType, + UTTKind UKind, + QualType CanonicalType) + : Type(UnaryTransform, CanonicalType, UnderlyingType->isDependentType(), + UnderlyingType->isVariablyModifiedType(), + BaseType->containsUnexpandedParameterPack()) + , BaseType(BaseType), UnderlyingType(UnderlyingType), UKind(UKind) +{} + +TagDecl *TagType::getDecl() const { + return getInterestingTagDecl(decl); +} + +bool TagType::isBeingDefined() const { + return getDecl()->isBeingDefined(); +} + +CXXRecordDecl *InjectedClassNameType::getDecl() const { + return cast<CXXRecordDecl>(getInterestingTagDecl(Decl)); +} + +bool RecordType::classof(const TagType *TT) { + return isa<RecordDecl>(TT->getDecl()); +} + +bool EnumType::classof(const TagType *TT) { + return isa<EnumDecl>(TT->getDecl()); +} + +IdentifierInfo *TemplateTypeParmType::getIdentifier() const { + return isCanonicalUnqualified() ? 0 : getDecl()->getIdentifier(); +} + +SubstTemplateTypeParmPackType:: +SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack) + : Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param), + Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()) +{ +} + +TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); +} + +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getArgumentPack()); +} + +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack) { + ID.AddPointer(Replaced); + ID.AddInteger(ArgPack.pack_size()); + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) + ID.AddPointer(P->getAsType().getAsOpaquePtr()); +} + +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) { + return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size()); +} + +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (Args[i].getArgument().isDependent()) + return true; + return false; +} + +bool TemplateSpecializationType:: +anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { + for (unsigned i = 0; i != N; ++i) + if (Args[i].isDependent()) + return true; + return false; +} + +TemplateSpecializationType:: +TemplateSpecializationType(TemplateName T, + const TemplateArgument *Args, unsigned NumArgs, + QualType Canon, QualType AliasedType) + : Type(TemplateSpecialization, + Canon.isNull()? QualType(this, 0) : Canon, + Canon.isNull()? T.isDependent() : Canon->isDependentType(), + false, T.containsUnexpandedParameterPack()), + Template(T), NumArgs(NumArgs) { + assert(!T.getAsDependentTemplateName() && + "Use DependentTemplateSpecializationType for dependent template-name"); + 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) { + // Update dependent and variably-modified bits. + // If the canonical type exists and is non-dependent, the template + // specialization type can be non-dependent even if one of the type + // arguments is. Given: + // template<typename T> using U = int; + // U<T> is always non-dependent, irrespective of the type T. + if (Canon.isNull() && Args[Arg].isDependent()) + setDependent(); + if (Args[Arg].getKind() == TemplateArgument::Type && + Args[Arg].getAsType()->isVariablyModifiedType()) + setVariablyModified(); + if (Args[Arg].containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); + + new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); + } + + // Store the aliased type if this is a type alias template specialization. + bool IsTypeAlias = !AliasedType.isNull(); + assert(IsTypeAlias == isTypeAlias() && + "allocated wrong size for type alias"); + if (IsTypeAlias) { + TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1); + *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType; + } +} + +void +TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateName T, + const TemplateArgument *Args, + unsigned NumArgs, + const ASTContext &Context) { + T.Profile(ID); + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + Args[Idx].Profile(ID, Context); +} + +bool TemplateSpecializationType::isTypeAlias() const { + TemplateDecl *D = Template.getAsTemplateDecl(); + return D && isa<TypeAliasTemplateDecl>(D); +} + +QualType +QualifierCollector::apply(const ASTContext &Context, QualType QT) const { + if (!hasNonFastQualifiers()) + return QT.withFastQualifiers(getFastQualifiers()); + + return Context.getQualifiedType(QT, *this); +} + +QualType +QualifierCollector::apply(const ASTContext &Context, const Type *T) const { + if (!hasNonFastQualifiers()) + return QualType(T, getFastQualifiers()); + + return Context.getQualifiedType(T, *this); +} + +void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID, + QualType BaseType, + ObjCProtocolDecl * const *Protocols, + unsigned NumProtocols) { + ID.AddPointer(BaseType.getAsOpaquePtr()); + for (unsigned i = 0; i != NumProtocols; i++) + ID.AddPointer(Protocols[i]); +} + +void ObjCObjectTypeImpl::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getBaseType(), qual_begin(), getNumProtocols()); +} + +namespace { + +/// \brief The cached properties of a type. +class CachedProperties { + char linkage; + char visibility; + bool local; + +public: + CachedProperties(Linkage linkage, Visibility visibility, bool local) + : linkage(linkage), visibility(visibility), local(local) {} + + Linkage getLinkage() const { return (Linkage) linkage; } + Visibility getVisibility() const { return (Visibility) visibility; } + bool hasLocalOrUnnamedType() const { return local; } + + friend CachedProperties merge(CachedProperties L, CachedProperties R) { + return CachedProperties(minLinkage(L.getLinkage(), R.getLinkage()), + minVisibility(L.getVisibility(), R.getVisibility()), + L.hasLocalOrUnnamedType() | R.hasLocalOrUnnamedType()); + } +}; +} + +static CachedProperties computeCachedProperties(const Type *T); + +namespace clang { +/// The type-property cache. This is templated so as to be +/// instantiated at an internal type to prevent unnecessary symbol +/// leakage. +template <class Private> class TypePropertyCache { +public: + static CachedProperties get(QualType T) { + return get(T.getTypePtr()); + } + + static CachedProperties get(const Type *T) { + ensure(T); + return CachedProperties(T->TypeBits.getLinkage(), + T->TypeBits.getVisibility(), + T->TypeBits.hasLocalOrUnnamedType()); + } + + static void ensure(const Type *T) { + // If the cache is valid, we're okay. + if (T->TypeBits.isCacheValid()) return; + + // If this type is non-canonical, ask its canonical type for the + // relevant information. + if (!T->isCanonicalUnqualified()) { + const Type *CT = T->getCanonicalTypeInternal().getTypePtr(); + ensure(CT); + T->TypeBits.CacheValidAndVisibility = + CT->TypeBits.CacheValidAndVisibility; + T->TypeBits.CachedLinkage = CT->TypeBits.CachedLinkage; + T->TypeBits.CachedLocalOrUnnamed = CT->TypeBits.CachedLocalOrUnnamed; + return; + } + + // Compute the cached properties and then set the cache. + CachedProperties Result = computeCachedProperties(T); + T->TypeBits.CacheValidAndVisibility = Result.getVisibility() + 1U; + assert(T->TypeBits.isCacheValid() && + T->TypeBits.getVisibility() == Result.getVisibility()); + T->TypeBits.CachedLinkage = Result.getLinkage(); + T->TypeBits.CachedLocalOrUnnamed = Result.hasLocalOrUnnamedType(); + } +}; +} + +// Instantiate the friend template at a private class. In a +// reasonable implementation, these symbols will be internal. +// It is terrible that this is the best way to accomplish this. +namespace { class Private {}; } +typedef TypePropertyCache<Private> Cache; + +static CachedProperties computeCachedProperties(const Type *T) { + switch (T->getTypeClass()) { +#define TYPE(Class,Base) +#define NON_CANONICAL_TYPE(Class,Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + llvm_unreachable("didn't expect a non-canonical type here"); + +#define TYPE(Class,Base) +#define DEPENDENT_TYPE(Class,Base) case Type::Class: +#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class,Base) case Type::Class: +#include "clang/AST/TypeNodes.def" + // Treat dependent types as external. + assert(T->isDependentType()); + return CachedProperties(ExternalLinkage, DefaultVisibility, false); + + case Type::Builtin: + // C++ [basic.link]p8: + // A type is said to have linkage if and only if: + // - it is a fundamental type (3.9.1); or + return CachedProperties(ExternalLinkage, DefaultVisibility, false); + + case Type::Record: + case Type::Enum: { + const TagDecl *Tag = cast<TagType>(T)->getDecl(); + + // C++ [basic.link]p8: + // - it is a class or enumeration type that is named (or has a name + // for linkage purposes (7.1.3)) and the name has linkage; or + // - it is a specialization of a class template (14); or + NamedDecl::LinkageInfo LV = Tag->getLinkageAndVisibility(); + bool IsLocalOrUnnamed = + Tag->getDeclContext()->isFunctionOrMethod() || + (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()); + return CachedProperties(LV.linkage(), LV.visibility(), IsLocalOrUnnamed); + } + + // C++ [basic.link]p8: + // - it is a compound type (3.9.2) other than a class or enumeration, + // compounded exclusively from types that have linkage; or + case Type::Complex: + return Cache::get(cast<ComplexType>(T)->getElementType()); + case Type::Pointer: + return Cache::get(cast<PointerType>(T)->getPointeeType()); + case Type::BlockPointer: + return Cache::get(cast<BlockPointerType>(T)->getPointeeType()); + case Type::LValueReference: + case Type::RValueReference: + return Cache::get(cast<ReferenceType>(T)->getPointeeType()); + case Type::MemberPointer: { + const MemberPointerType *MPT = cast<MemberPointerType>(T); + return merge(Cache::get(MPT->getClass()), + Cache::get(MPT->getPointeeType())); + } + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + return Cache::get(cast<ArrayType>(T)->getElementType()); + case Type::Vector: + case Type::ExtVector: + return Cache::get(cast<VectorType>(T)->getElementType()); + case Type::FunctionNoProto: + return Cache::get(cast<FunctionType>(T)->getResultType()); + case Type::FunctionProto: { + const FunctionProtoType *FPT = cast<FunctionProtoType>(T); + CachedProperties result = Cache::get(FPT->getResultType()); + for (FunctionProtoType::arg_type_iterator ai = FPT->arg_type_begin(), + ae = FPT->arg_type_end(); ai != ae; ++ai) + result = merge(result, Cache::get(*ai)); + return result; + } + case Type::ObjCInterface: { + NamedDecl::LinkageInfo LV = + cast<ObjCInterfaceType>(T)->getDecl()->getLinkageAndVisibility(); + return CachedProperties(LV.linkage(), LV.visibility(), false); + } + case Type::ObjCObject: + return Cache::get(cast<ObjCObjectType>(T)->getBaseType()); + case Type::ObjCObjectPointer: + return Cache::get(cast<ObjCObjectPointerType>(T)->getPointeeType()); + } + + llvm_unreachable("unhandled type class"); + + // C++ [basic.link]p8: + // Names not covered by these rules have no linkage. + return CachedProperties(NoLinkage, DefaultVisibility, false); +} + +/// \brief Determine the linkage of this type. +Linkage Type::getLinkage() const { + Cache::ensure(this); + return TypeBits.getLinkage(); +} + +/// \brief Determine the linkage of this type. +Visibility Type::getVisibility() const { + Cache::ensure(this); + return TypeBits.getVisibility(); +} + +bool Type::hasUnnamedOrLocalType() const { + Cache::ensure(this); + return TypeBits.hasLocalOrUnnamedType(); +} + +std::pair<Linkage,Visibility> Type::getLinkageAndVisibility() const { + Cache::ensure(this); + return std::make_pair(TypeBits.getLinkage(), TypeBits.getVisibility()); +} + +void Type::ClearLinkageCache() { + TypeBits.CacheValidAndVisibility = 0; + if (QualType(this, 0) != CanonicalType) + CanonicalType->TypeBits.CacheValidAndVisibility = 0; +} + +bool Type::hasSizedVLAType() const { + if (!isVariablyModifiedType()) return false; + + if (const PointerType *ptr = getAs<PointerType>()) + return ptr->getPointeeType()->hasSizedVLAType(); + if (const ReferenceType *ref = getAs<ReferenceType>()) + return ref->getPointeeType()->hasSizedVLAType(); + if (const ArrayType *arr = getAsArrayTypeUnsafe()) { + if (isa<VariableArrayType>(arr) && + cast<VariableArrayType>(arr)->getSizeExpr()) + return true; + + return arr->getElementType()->hasSizedVLAType(); + } + + return false; +} + +QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) { + /// Currently, the only destruction kind we recognize is C++ objects + /// with non-trivial destructors. + const CXXRecordDecl *record = + type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (record && !record->hasTrivialDestructor()) + return DK_cxx_destructor; + + return DK_none; +} diff --git a/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp new file mode 100644 index 000000000000..34e7693e3075 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/TypeLoc.cpp @@ -0,0 +1,334 @@ +//===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- 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 TypeLoc subclasses implementations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/raw_ostream.h" +#include "clang/AST/TypeLocVisitor.h" +#include "clang/AST/Expr.h" +#include "llvm/Support/ErrorHandling.h" +using namespace clang; + +//===----------------------------------------------------------------------===// +// TypeLoc Implementation +//===----------------------------------------------------------------------===// + +namespace { + class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getLocalSourceRange(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { + if (TL.isNull()) return SourceRange(); + return TypeLocRanger().Visit(TL); +} + +namespace { + class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getFullDataSize(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +/// \brief Returns the size of the type source info data block. +unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { + if (Ty.isNull()) return 0; + return TypeSizer().Visit(TypeLoc(Ty, 0)); +} + +namespace { + class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { + public: +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return TyLoc.getNextTypeLoc(); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + +/// \brief Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the +/// TypeLoc is a PointerLoc and next TypeLoc is for "int". +TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { + return NextLoc().Visit(TL); +} + +/// \brief Initializes a type location, and all of its children +/// recursively, as if the entire tree had been written in the +/// given location. +void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, + SourceLocation Loc) { + while (true) { + switch (TL.getTypeLocClass()) { +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + case CLASS: { \ + CLASS##TypeLoc TLCasted = cast<CLASS##TypeLoc>(TL); \ + TLCasted.initializeLocal(Context, Loc); \ + TL = TLCasted.getNextTypeLoc(); \ + if (!TL) return; \ + continue; \ + } +#include "clang/AST/TypeLocNodes.def" + } + } +} + +SourceLocation TypeLoc::getBeginLoc() const { + TypeLoc Cur = *this; + while (true) { + switch (Cur.getTypeLocClass()) { + // FIXME: Currently QualifiedTypeLoc does not have a source range + // case Qualified: + case Elaborated: + case DependentName: + case DependentTemplateSpecialization: + break; + default: + TypeLoc Next = Cur.getNextTypeLoc(); + if (Next.isNull()) break; + Cur = Next; + continue; + } + break; + } + return Cur.getLocalSourceRange().getBegin(); +} + +SourceLocation TypeLoc::getEndLoc() const { + TypeLoc Cur = *this; + TypeLoc Last; + while (true) { + switch (Cur.getTypeLocClass()) { + default: + if (!Last) + Last = Cur; + return Last.getLocalSourceRange().getEnd(); + case Paren: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + case FunctionProto: + case FunctionNoProto: + Last = Cur; + break; + case Pointer: + case BlockPointer: + case MemberPointer: + case LValueReference: + case RValueReference: + case PackExpansion: + if (!Last) + Last = Cur; + break; + case Qualified: + case Elaborated: + break; + } + Cur = Cur.getNextTypeLoc(); + } +} + + +namespace { + struct TSTChecker : public TypeLocVisitor<TSTChecker, bool> { + // Overload resolution does the real work for us. + static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } + static bool isTypeSpec(TypeLoc _) { return false; } + +#define ABSTRACT_TYPELOC(CLASS, PARENT) +#define TYPELOC(CLASS, PARENT) \ + bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ + return isTypeSpec(TyLoc); \ + } +#include "clang/AST/TypeLocNodes.def" + }; +} + + +/// \brief Determines if the given type loc corresponds to a +/// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in +/// the type hierarchy, this is made somewhat complicated. +/// +/// There are a lot of types that currently use TypeSpecTypeLoc +/// because it's a convenient base class. Ideally we would not accept +/// those here, but ideally we would have better implementations for +/// them. +bool TypeSpecTypeLoc::classof(const TypeLoc *TL) { + if (TL->getType().hasLocalQualifiers()) return false; + return TSTChecker().Visit(*TL); +} + +// Reimplemented to account for GNU/C++ extension +// typeof unary-expression +// where there are no parentheses. +SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const { + if (getRParenLoc().isValid()) + return SourceRange(getTypeofLoc(), getRParenLoc()); + else + return SourceRange(getTypeofLoc(), + getUnderlyingExpr()->getSourceRange().getEnd()); +} + + +TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { + if (needsExtraLocalData()) + return static_cast<TypeSpecifierType>(getWrittenBuiltinSpecs().Type); + else { + switch (getTypePtr()->getKind()) { + case BuiltinType::Void: + return TST_void; + case BuiltinType::Bool: + return TST_bool; + case BuiltinType::Char_U: + case BuiltinType::Char_S: + return TST_char; + case BuiltinType::Char16: + return TST_char16; + case BuiltinType::Char32: + return TST_char32; + case BuiltinType::WChar_S: + case BuiltinType::WChar_U: + return TST_wchar; + + case BuiltinType::UChar: + case BuiltinType::UShort: + case BuiltinType::UInt: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + case BuiltinType::UInt128: + case BuiltinType::SChar: + case BuiltinType::Short: + case BuiltinType::Int: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::Int128: + case BuiltinType::Float: + case BuiltinType::Double: + case BuiltinType::LongDouble: + llvm_unreachable("Builtin type needs extra local data!"); + // Fall through, if the impossible happens. + + case BuiltinType::NullPtr: + case BuiltinType::Overload: + case BuiltinType::Dependent: + case BuiltinType::BoundMember: + case BuiltinType::UnknownAny: + case BuiltinType::ObjCId: + case BuiltinType::ObjCClass: + case BuiltinType::ObjCSel: + return TST_unspecified; + } + } + + return TST_unspecified; +} + +TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { + while (ParenTypeLoc* PTL = dyn_cast<ParenTypeLoc>(&TL)) + TL = PTL->getInnerLoc(); + return TL; +} + +void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); +} + +void DependentNameTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + setNameLoc(Loc); +} + +void +DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + setKeywordLoc(Loc); + if (getTypePtr()->getQualifier()) { + NestedNameSpecifierLocBuilder Builder; + Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); + setQualifierLoc(Builder.getWithLocInContext(Context)); + } else { + setQualifierLoc(NestedNameSpecifierLoc()); + } + + setNameLoc(Loc); + setLAngleLoc(Loc); + setRAngleLoc(Loc); + TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), + getTypePtr()->getArgs(), + getArgInfos(), Loc); +} + +void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, + unsigned NumArgs, + const TemplateArgument *Args, + TemplateArgumentLocInfo *ArgInfos, + SourceLocation Loc) { + for (unsigned i = 0, e = NumArgs; i != e; ++i) { + switch (Args[i].getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Expression: + // FIXME: Can we do better for declarations and integral values? + ArgInfos[i] = TemplateArgumentLocInfo(); + break; + + case TemplateArgument::Type: + ArgInfos[i] = TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(Args[i].getAsType(), + Loc)); + break; + + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: { + NestedNameSpecifierLocBuilder Builder; + TemplateName Template = Args[i].getAsTemplate(); + if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) + Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); + else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) + Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); + + ArgInfos[i] = TemplateArgumentLocInfo( + Builder.getWithLocInContext(Context), + Loc, + Args[i].getKind() == TemplateArgument::Template + ? SourceLocation() + : Loc); + break; + } + } + } +} + diff --git a/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp new file mode 100644 index 000000000000..4519606f6e82 --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/TypePrinter.cpp @@ -0,0 +1,1111 @@ +//===--- TypePrinter.cpp - Pretty-Print Clang Types -----------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This contains code to print types from Clang's type system. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" +#include "clang/AST/PrettyPrinter.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/raw_ostream.h" +using namespace clang; + +namespace { + class TypePrinter { + PrintingPolicy Policy; + + public: + explicit TypePrinter(const PrintingPolicy &Policy) : Policy(Policy) { } + + void print(const Type *ty, Qualifiers qs, std::string &buffer); + void print(QualType T, std::string &S); + void AppendScope(DeclContext *DC, std::string &S); + void printTag(TagDecl *T, std::string &S); +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) \ + void print##CLASS(const CLASS##Type *T, std::string &S); +#include "clang/AST/TypeNodes.def" + }; +} + +static void AppendTypeQualList(std::string &S, unsigned TypeQuals) { + if (TypeQuals & Qualifiers::Const) { + if (!S.empty()) S += ' '; + S += "const"; + } + if (TypeQuals & Qualifiers::Volatile) { + if (!S.empty()) S += ' '; + S += "volatile"; + } + if (TypeQuals & Qualifiers::Restrict) { + if (!S.empty()) S += ' '; + S += "restrict"; + } +} + +void TypePrinter::print(QualType t, std::string &buffer) { + SplitQualType split = t.split(); + print(split.first, split.second, buffer); +} + +void TypePrinter::print(const Type *T, Qualifiers Quals, std::string &buffer) { + if (!T) { + buffer += "NULL TYPE"; + return; + } + + if (Policy.SuppressSpecifiers && T->isSpecifierType()) + return; + + // Print qualifiers as appropriate. + + // CanPrefixQualifiers - We prefer to print type qualifiers before the type, + // so that we get "const int" instead of "int const", but we can't do this if + // the type is complex. For example if the type is "int*", we *must* print + // "int * const", printing "const int *" is different. Only do this when the + // type expands to a simple string. + bool CanPrefixQualifiers = false; + + Type::TypeClass TC = T->getTypeClass(); + if (const AutoType *AT = dyn_cast<AutoType>(T)) + TC = AT->desugar()->getTypeClass(); + if (const SubstTemplateTypeParmType *Subst + = dyn_cast<SubstTemplateTypeParmType>(T)) + TC = Subst->getReplacementType()->getTypeClass(); + + switch (TC) { + case Type::Builtin: + case Type::Complex: + case Type::UnresolvedUsing: + case Type::Typedef: + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::UnaryTransform: + case Type::Record: + case Type::Enum: + case Type::Elaborated: + case Type::TemplateTypeParm: + case Type::SubstTemplateTypeParmPack: + case Type::TemplateSpecialization: + case Type::InjectedClassName: + case Type::DependentName: + case Type::DependentTemplateSpecialization: + case Type::ObjCObject: + case Type::ObjCInterface: + CanPrefixQualifiers = true; + break; + + case Type::ObjCObjectPointer: + CanPrefixQualifiers = T->isObjCIdType() || T->isObjCClassType() || + T->isObjCQualifiedIdType() || T->isObjCQualifiedClassType(); + break; + + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Paren: + case Type::Attributed: + case Type::PackExpansion: + case Type::SubstTemplateTypeParm: + case Type::Auto: + CanPrefixQualifiers = false; + break; + } + + if (!CanPrefixQualifiers && !Quals.empty()) { + std::string qualsBuffer; + Quals.getAsStringInternal(qualsBuffer, Policy); + + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; + } + std::swap(buffer, qualsBuffer); + } + + switch (T->getTypeClass()) { +#define ABSTRACT_TYPE(CLASS, PARENT) +#define TYPE(CLASS, PARENT) case Type::CLASS: \ + print##CLASS(cast<CLASS##Type>(T), buffer); \ + break; +#include "clang/AST/TypeNodes.def" + } + + // If we're adding the qualifiers as a prefix, do it now. + if (CanPrefixQualifiers && !Quals.empty()) { + std::string qualsBuffer; + Quals.getAsStringInternal(qualsBuffer, Policy); + + if (!buffer.empty()) { + qualsBuffer += ' '; + qualsBuffer += buffer; + } + std::swap(buffer, qualsBuffer); + } +} + +void TypePrinter::printBuiltin(const BuiltinType *T, std::string &S) { + if (S.empty()) { + S = T->getName(Policy.LangOpts); + } else { + // Prefix the basic type, e.g. 'int X'. + S = ' ' + S; + S = T->getName(Policy.LangOpts) + S; + } +} + +void TypePrinter::printComplex(const ComplexType *T, std::string &S) { + print(T->getElementType(), S); + S = "_Complex " + S; +} + +void TypePrinter::printPointer(const PointerType *T, std::string &S) { + S = '*' + S; + + // Handle things like 'int (*A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeType())) + S = '(' + S + ')'; + + print(T->getPointeeType(), S); +} + +void TypePrinter::printBlockPointer(const BlockPointerType *T, std::string &S) { + S = '^' + S; + print(T->getPointeeType(), S); +} + +void TypePrinter::printLValueReference(const LValueReferenceType *T, + std::string &S) { + S = '&' + S; + + // Handle things like 'int (&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + S = '(' + S + ')'; + + print(T->getPointeeTypeAsWritten(), S); +} + +void TypePrinter::printRValueReference(const RValueReferenceType *T, + std::string &S) { + S = "&&" + S; + + // Handle things like 'int (&&A)[4];' correctly. + // FIXME: this should include vectors, but vectors use attributes I guess. + if (isa<ArrayType>(T->getPointeeTypeAsWritten())) + S = '(' + S + ')'; + + print(T->getPointeeTypeAsWritten(), S); +} + +void TypePrinter::printMemberPointer(const MemberPointerType *T, + std::string &S) { + std::string C; + print(QualType(T->getClass(), 0), C); + 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>(T->getPointeeType())) + S = '(' + S + ')'; + + print(T->getPointeeType(), S); +} + +void TypePrinter::printConstantArray(const ConstantArrayType *T, + std::string &S) { + S += '['; + S += llvm::utostr(T->getSize().getZExtValue()); + S += ']'; + + print(T->getElementType(), S); +} + +void TypePrinter::printIncompleteArray(const IncompleteArrayType *T, + std::string &S) { + S += "[]"; + print(T->getElementType(), S); +} + +void TypePrinter::printVariableArray(const VariableArrayType *T, + std::string &S) { + S += '['; + + if (T->getIndexTypeQualifiers().hasQualifiers()) { + AppendTypeQualList(S, T->getIndexTypeCVRQualifiers()); + S += ' '; + } + + if (T->getSizeModifier() == VariableArrayType::Static) + S += "static"; + else if (T->getSizeModifier() == VariableArrayType::Star) + S += '*'; + + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + print(T->getElementType(), S); +} + +void TypePrinter::printDependentSizedArray(const DependentSizedArrayType *T, + std::string &S) { + S += '['; + + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ']'; + + print(T->getElementType(), S); +} + +void TypePrinter::printDependentSizedExtVector( + const DependentSizedExtVectorType *T, + std::string &S) { + print(T->getElementType(), S); + + S += " __attribute__((ext_vector_type("; + if (T->getSizeExpr()) { + std::string SStr; + llvm::raw_string_ostream s(SStr); + T->getSizeExpr()->printPretty(s, 0, Policy); + S += s.str(); + } + S += ")))"; +} + +void TypePrinter::printVector(const VectorType *T, std::string &S) { + switch (T->getVectorKind()) { + case VectorType::AltiVecPixel: + S = "__vector __pixel " + S; + break; + case VectorType::AltiVecBool: + print(T->getElementType(), S); + S = "__vector __bool " + S; + break; + case VectorType::AltiVecVector: + print(T->getElementType(), S); + S = "__vector " + S; + break; + case VectorType::NeonVector: + print(T->getElementType(), S); + S = ("__attribute__((neon_vector_type(" + + llvm::utostr_32(T->getNumElements()) + "))) " + S); + break; + case VectorType::NeonPolyVector: + print(T->getElementType(), S); + S = ("__attribute__((neon_polyvector_type(" + + llvm::utostr_32(T->getNumElements()) + "))) " + S); + break; + case VectorType::GenericVector: { + // FIXME: We prefer to print the size directly here, but have no way + // to get the size of the type. + print(T->getElementType(), S); + std::string V = "__attribute__((__vector_size__("; + V += llvm::utostr_32(T->getNumElements()); // convert back to bytes. + std::string ET; + print(T->getElementType(), ET); + V += " * sizeof(" + ET + ")))) "; + S = V + S; + break; + } + } +} + +void TypePrinter::printExtVector(const ExtVectorType *T, std::string &S) { + S += " __attribute__((ext_vector_type("; + S += llvm::utostr_32(T->getNumElements()); + S += ")))"; + print(T->getElementType(), S); +} + +void TypePrinter::printFunctionProto(const FunctionProtoType *T, + std::string &S) { + // 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 = T->getNumArgs(); i != e; ++i) { + if (i) S += ", "; + print(T->getArgType(i), Tmp); + S += Tmp; + Tmp.clear(); + } + + if (T->isVariadic()) { + if (T->getNumArgs()) + S += ", "; + S += "..."; + } else if (T->getNumArgs() == 0 && !Policy.LangOpts.CPlusPlus) { + // Do not emit int() if we have a proto, emit 'int(void)'. + S += "void"; + } + + S += ")"; + + FunctionType::ExtInfo Info = T->getExtInfo(); + switch(Info.getCC()) { + case CC_Default: + default: break; + case CC_C: + S += " __attribute__((cdecl))"; + break; + case CC_X86StdCall: + S += " __attribute__((stdcall))"; + break; + case CC_X86FastCall: + S += " __attribute__((fastcall))"; + break; + case CC_X86ThisCall: + S += " __attribute__((thiscall))"; + break; + case CC_X86Pascal: + S += " __attribute__((pascal))"; + break; + case CC_AAPCS: + S += " __attribute__((pcs(\"aapcs\")))"; + break; + case CC_AAPCS_VFP: + S += " __attribute__((pcs(\"aapcs-vfp\")))"; + break; + } + if (Info.getNoReturn()) + S += " __attribute__((noreturn))"; + if (Info.getRegParm()) + S += " __attribute__((regparm (" + + llvm::utostr_32(Info.getRegParm()) + ")))"; + + AppendTypeQualList(S, T->getTypeQuals()); + + switch (T->getRefQualifier()) { + case RQ_None: + break; + + case RQ_LValue: + S += " &"; + break; + + case RQ_RValue: + S += " &&"; + break; + } + + if (T->hasDynamicExceptionSpec()) { + S += " throw("; + if (T->getExceptionSpecType() == EST_MSAny) + S += "..."; + else + for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) { + if (I) + S += ", "; + + std::string ExceptionType; + print(T->getExceptionType(I), ExceptionType); + S += ExceptionType; + } + S += ")"; + } else if (isNoexceptExceptionSpec(T->getExceptionSpecType())) { + S += " noexcept"; + if (T->getExceptionSpecType() == EST_ComputedNoexcept) { + S += "("; + llvm::raw_string_ostream EOut(S); + T->getNoexceptExpr()->printPretty(EOut, 0, Policy); + EOut.flush(); + S += EOut.str(); + S += ")"; + } + } + + print(T->getResultType(), S); +} + +void TypePrinter::printFunctionNoProto(const FunctionNoProtoType *T, + std::string &S) { + // If needed for precedence reasons, wrap the inner part in grouping parens. + if (!S.empty()) + S = "(" + S + ")"; + + S += "()"; + if (T->getNoReturnAttr()) + S += " __attribute__((noreturn))"; + print(T->getResultType(), S); +} + +static void printTypeSpec(const NamedDecl *D, std::string &S) { + IdentifierInfo *II = D->getIdentifier(); + if (S.empty()) + S = II->getName().str(); + else + S = II->getName().str() + ' ' + S; +} + +void TypePrinter::printUnresolvedUsing(const UnresolvedUsingType *T, + std::string &S) { + printTypeSpec(T->getDecl(), S); +} + +void TypePrinter::printTypedef(const TypedefType *T, std::string &S) { + printTypeSpec(T->getDecl(), S); +} + +void TypePrinter::printTypeOfExpr(const TypeOfExprType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typeof(e) X'. + S = ' ' + S; + std::string Str; + llvm::raw_string_ostream s(Str); + T->getUnderlyingExpr()->printPretty(s, 0, Policy); + S = "typeof " + s.str() + S; +} + +void TypePrinter::printTypeOf(const TypeOfType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typeof(t) X'. + S = ' ' + S; + std::string Tmp; + print(T->getUnderlyingType(), Tmp); + S = "typeof(" + Tmp + ")" + S; +} + +void TypePrinter::printDecltype(const DecltypeType *T, std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'decltype(t) X'. + S = ' ' + S; + std::string Str; + llvm::raw_string_ostream s(Str); + T->getUnderlyingExpr()->printPretty(s, 0, Policy); + S = "decltype(" + s.str() + ")" + S; +} + +void TypePrinter::printUnaryTransform(const UnaryTransformType *T, + std::string &S) { + if (!S.empty()) + S = ' ' + S; + std::string Str; + print(T->getBaseType(), Str); + + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + S = "__underlying_type(" + Str + ")" + S; + break; + } +} + +void TypePrinter::printAuto(const AutoType *T, std::string &S) { + // If the type has been deduced, do not print 'auto'. + if (T->isDeduced()) { + print(T->getDeducedType(), S); + } else { + if (!S.empty()) // Prefix the basic type, e.g. 'auto X'. + S = ' ' + S; + S = "auto" + S; + } +} + +/// Appends the given scope to the end of a string. +void TypePrinter::AppendScope(DeclContext *DC, std::string &Buffer) { + if (DC->isTranslationUnit()) return; + AppendScope(DC->getParent(), Buffer); + + unsigned OldSize = Buffer.size(); + + if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { + if (NS->getIdentifier()) + Buffer += NS->getNameAsString(); + else + Buffer += "<anonymous>"; + } else if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + std::string TemplateArgsStr + = TemplateSpecializationType::PrintTemplateArgumentList( + TemplateArgs.data(), + TemplateArgs.size(), + Policy); + Buffer += Spec->getIdentifier()->getName(); + Buffer += TemplateArgsStr; + } else if (TagDecl *Tag = dyn_cast<TagDecl>(DC)) { + if (TypedefNameDecl *Typedef = Tag->getTypedefNameForAnonDecl()) + Buffer += Typedef->getIdentifier()->getName(); + else if (Tag->getIdentifier()) + Buffer += Tag->getIdentifier()->getName(); + } + + if (Buffer.size() != OldSize) + Buffer += "::"; +} + +void TypePrinter::printTag(TagDecl *D, std::string &InnerString) { + if (Policy.SuppressTag) + return; + + std::string Buffer; + bool HasKindDecoration = false; + + // bool SuppressTagKeyword + // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword; + + // We don't print tags unless this is an elaborated type. + // In C, we just assume every RecordType is an elaborated type. + if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword || + D->getTypedefNameForAnonDecl())) { + HasKindDecoration = true; + Buffer += D->getKindName(); + Buffer += ' '; + } + + // Compute the full nested-name-specifier for this type. + // In C, this will always be empty except when the type + // being printed is anonymous within other Record. + if (!Policy.SuppressScope) + AppendScope(D->getDeclContext(), Buffer); + + if (const IdentifierInfo *II = D->getIdentifier()) + Buffer += II->getNameStart(); + else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { + assert(Typedef->getIdentifier() && "Typedef without identifier?"); + Buffer += Typedef->getIdentifier()->getNameStart(); + } else { + // Make an unambiguous representation for anonymous types, e.g. + // <anonymous enum at /usr/include/string.h:120:9> + llvm::raw_string_ostream OS(Buffer); + OS << "<anonymous"; + + if (Policy.AnonymousTagLocations) { + // Suppress the redundant tag keyword if we just printed one. + // We don't have to worry about ElaboratedTypes here because you can't + // refer to an anonymous type with one. + if (!HasKindDecoration) + OS << " " << D->getKindName(); + + PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( + D->getLocation()); + if (PLoc.isValid()) { + OS << " at " << PLoc.getFilename() + << ':' << PLoc.getLine() + << ':' << PLoc.getColumn(); + } + } + + OS << '>'; + } + + // If this is a class template specialization, print the template + // arguments. + if (ClassTemplateSpecializationDecl *Spec + = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + const TemplateArgument *Args; + unsigned NumArgs; + if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { + const TemplateSpecializationType *TST = + cast<TemplateSpecializationType>(TAW->getType()); + Args = TST->getArgs(); + NumArgs = TST->getNumArgs(); + } else { + const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); + Args = TemplateArgs.data(); + NumArgs = TemplateArgs.size(); + } + Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, + NumArgs, + Policy); + } + + if (!InnerString.empty()) { + Buffer += ' '; + Buffer += InnerString; + } + + std::swap(Buffer, InnerString); +} + +void TypePrinter::printRecord(const RecordType *T, std::string &S) { + printTag(T->getDecl(), S); +} + +void TypePrinter::printEnum(const EnumType *T, std::string &S) { + printTag(T->getDecl(), S); +} + +void TypePrinter::printTemplateTypeParm(const TemplateTypeParmType *T, + std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'parmname X'. + S = ' ' + S; + + if (IdentifierInfo *Id = T->getIdentifier()) + S = Id->getName().str() + S; + else + S = "type-parameter-" + llvm::utostr_32(T->getDepth()) + '-' + + llvm::utostr_32(T->getIndex()) + S; +} + +void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, + std::string &S) { + print(T->getReplacementType(), S); +} + +void TypePrinter::printSubstTemplateTypeParmPack( + const SubstTemplateTypeParmPackType *T, + std::string &S) { + printTemplateTypeParm(T->getReplacedParameter(), S); +} + +void TypePrinter::printTemplateSpecialization( + const TemplateSpecializationType *T, + std::string &S) { + std::string SpecString; + + { + llvm::raw_string_ostream OS(SpecString); + T->getTemplateName().print(OS, Policy); + } + + SpecString += TemplateSpecializationType::PrintTemplateArgumentList( + T->getArgs(), + T->getNumArgs(), + Policy); + if (S.empty()) + S.swap(SpecString); + else + S = SpecString + ' ' + S; +} + +void TypePrinter::printInjectedClassName(const InjectedClassNameType *T, + std::string &S) { + printTemplateSpecialization(T->getInjectedTST(), S); +} + +void TypePrinter::printElaborated(const ElaboratedType *T, std::string &S) { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + NestedNameSpecifier* Qualifier = T->getQualifier(); + if (Qualifier) + Qualifier->print(OS, Policy); + } + + std::string TypeStr; + PrintingPolicy InnerPolicy(Policy); + InnerPolicy.SuppressTagKeyword = true; + InnerPolicy.SuppressScope = true; + TypePrinter(InnerPolicy).print(T->getNamedType(), TypeStr); + + MyString += TypeStr; + if (S.empty()) + S.swap(MyString); + else + S = MyString + ' ' + S; +} + +void TypePrinter::printParen(const ParenType *T, std::string &S) { + if (!S.empty() && !isa<FunctionType>(T->getInnerType())) + S = '(' + S + ')'; + print(T->getInnerType(), S); +} + +void TypePrinter::printDependentName(const DependentNameType *T, std::string &S) { + std::string MyString; + + { + llvm::raw_string_ostream OS(MyString); + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + + T->getQualifier()->print(OS, Policy); + + OS << T->getIdentifier()->getName(); + } + + if (S.empty()) + S.swap(MyString); + else + S = MyString + ' ' + S; +} + +void TypePrinter::printDependentTemplateSpecialization( + const DependentTemplateSpecializationType *T, std::string &S) { + std::string MyString; + { + llvm::raw_string_ostream OS(MyString); + + OS << TypeWithKeyword::getKeywordName(T->getKeyword()); + if (T->getKeyword() != ETK_None) + OS << " "; + + if (T->getQualifier()) + T->getQualifier()->print(OS, Policy); + OS << T->getIdentifier()->getName(); + OS << TemplateSpecializationType::PrintTemplateArgumentList( + T->getArgs(), + T->getNumArgs(), + Policy); + } + + if (S.empty()) + S.swap(MyString); + else + S = MyString + ' ' + S; +} + +void TypePrinter::printPackExpansion(const PackExpansionType *T, + std::string &S) { + print(T->getPattern(), S); + S += "..."; +} + +void TypePrinter::printAttributed(const AttributedType *T, + std::string &S) { + // Prefer the macro forms of the GC qualifiers. + if (T->getAttrKind() == AttributedType::attr_objc_gc) + return print(T->getEquivalentType(), S); + + print(T->getModifiedType(), S); + + // TODO: not all attributes are GCC-style attributes. + S += " __attribute__(("; + switch (T->getAttrKind()) { + case AttributedType::attr_address_space: + S += "address_space("; + S += T->getEquivalentType().getAddressSpace(); + S += ")"; + break; + + case AttributedType::attr_vector_size: { + S += "__vector_size__("; + if (const VectorType *vector =T->getEquivalentType()->getAs<VectorType>()) { + S += vector->getNumElements(); + S += " * sizeof("; + + std::string tmp; + print(vector->getElementType(), tmp); + S += tmp; + S += ")"; + } + S += ")"; + break; + } + + case AttributedType::attr_neon_vector_type: + case AttributedType::attr_neon_polyvector_type: { + if (T->getAttrKind() == AttributedType::attr_neon_vector_type) + S += "neon_vector_type("; + else + S += "neon_polyvector_type("; + const VectorType *vector = T->getEquivalentType()->getAs<VectorType>(); + S += llvm::utostr_32(vector->getNumElements()); + S += ")"; + break; + } + + case AttributedType::attr_regparm: { + S += "regparm("; + QualType t = T->getEquivalentType(); + while (!t->isFunctionType()) + t = t->getPointeeType(); + S += t->getAs<FunctionType>()->getRegParmType(); + S += ")"; + break; + } + + case AttributedType::attr_objc_gc: { + S += "objc_gc("; + + QualType tmp = T->getEquivalentType(); + while (tmp.getObjCGCAttr() == Qualifiers::GCNone) { + QualType next = tmp->getPointeeType(); + if (next == tmp) break; + tmp = next; + } + + if (tmp.isObjCGCWeak()) + S += "weak"; + else + S += "strong"; + S += ")"; + break; + } + + case AttributedType::attr_noreturn: S += "noreturn"; break; + case AttributedType::attr_cdecl: S += "cdecl"; break; + case AttributedType::attr_fastcall: S += "fastcall"; break; + case AttributedType::attr_stdcall: S += "stdcall"; break; + case AttributedType::attr_thiscall: S += "thiscall"; break; + case AttributedType::attr_pascal: S += "pascal"; break; + case AttributedType::attr_pcs: { + S += "pcs("; + QualType t = T->getEquivalentType(); + while (!t->isFunctionType()) + t = t->getPointeeType(); + S += (t->getAs<FunctionType>()->getCallConv() == CC_AAPCS ? + "\"aapcs\"" : "\"aapcs-vfp\""); + S += ")"; + break; + } + } + S += "))"; +} + +void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, + std::string &S) { + if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. + S = ' ' + S; + + std::string ObjCQIString = T->getDecl()->getNameAsString(); + S = ObjCQIString + S; +} + +void TypePrinter::printObjCObject(const ObjCObjectType *T, + std::string &S) { + if (T->qual_empty()) + return print(T->getBaseType(), S); + + std::string tmp; + print(T->getBaseType(), tmp); + tmp += '<'; + bool isFirst = true; + for (ObjCObjectType::qual_iterator + I = T->qual_begin(), E = T->qual_end(); I != E; ++I) { + if (isFirst) + isFirst = false; + else + tmp += ','; + tmp += (*I)->getNameAsString(); + } + tmp += '>'; + + if (!S.empty()) { + tmp += ' '; + tmp += S; + } + std::swap(tmp, S); +} + +void TypePrinter::printObjCObjectPointer(const ObjCObjectPointerType *T, + std::string &S) { + std::string ObjCQIString; + + T->getPointeeType().getLocalQualifiers().getAsStringInternal(ObjCQIString, + Policy); + if (!ObjCQIString.empty()) + ObjCQIString += ' '; + + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) + ObjCQIString += "id"; + else if (T->isObjCClassType() || T->isObjCQualifiedClassType()) + ObjCQIString += "Class"; + else if (T->isObjCSelType()) + ObjCQIString += "SEL"; + else + ObjCQIString += T->getInterfaceDecl()->getNameAsString(); + + if (!T->qual_empty()) { + ObjCQIString += '<'; + for (ObjCObjectPointerType::qual_iterator I = T->qual_begin(), + E = T->qual_end(); + I != E; ++I) { + ObjCQIString += (*I)->getNameAsString(); + if (I+1 != E) + ObjCQIString += ','; + } + ObjCQIString += '>'; + } + + if (!T->isObjCIdType() && !T->isObjCQualifiedIdType()) + ObjCQIString += " *"; // Don't forget the implicit pointer. + else if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. + S = ' ' + S; + + S = ObjCQIString + S; +} + +std::string TemplateSpecializationType:: + PrintTemplateArgumentList(const TemplateArgumentListInfo &Args, + const PrintingPolicy &Policy) { + return PrintTemplateArgumentList(Args.getArgumentArray(), + Args.size(), + Policy); +} + +std::string +TemplateSpecializationType::PrintTemplateArgumentList( + const TemplateArgument *Args, + unsigned NumArgs, + const PrintingPolicy &Policy, + bool SkipBrackets) { + std::string SpecString; + if (!SkipBrackets) + SpecString += '<'; + + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (SpecString.size() > unsigned(!SkipBrackets)) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + if (Args[Arg].getKind() == TemplateArgument::Pack) { + ArgString = PrintTemplateArgumentList(Args[Arg].pack_begin(), + Args[Arg].pack_size(), + Policy, true); + } else { + llvm::raw_string_ostream ArgOut(ArgString); + Args[Arg].print(Policy, ArgOut); + } + + // 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.empty() && SpecString[SpecString.size() - 1] == '>') + SpecString += ' '; + + if (!SkipBrackets) + SpecString += '>'; + + return SpecString; +} + +// Sadly, repeat all that with TemplateArgLoc. +std::string TemplateSpecializationType:: +PrintTemplateArgumentList(const TemplateArgumentLoc *Args, unsigned NumArgs, + const PrintingPolicy &Policy) { + std::string SpecString; + SpecString += '<'; + for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { + if (SpecString.size() > 1) + SpecString += ", "; + + // Print the argument into a string. + std::string ArgString; + if (Args[Arg].getArgument().getKind() == TemplateArgument::Pack) { + ArgString = PrintTemplateArgumentList( + Args[Arg].getArgument().pack_begin(), + Args[Arg].getArgument().pack_size(), + Policy, true); + } else { + llvm::raw_string_ostream ArgOut(ArgString); + Args[Arg].getArgument().print(Policy, ArgOut); + } + + // 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 QualType::dump(const char *msg) const { + std::string R = "identifier"; + LangOptions LO; + getAsStringInternal(R, PrintingPolicy(LO)); + if (msg) + llvm::errs() << msg << ": "; + llvm::errs() << R << "\n"; +} +void QualType::dump() const { + dump(""); +} + +void Type::dump() const { + QualType(this, 0).dump(); +} + +std::string Qualifiers::getAsString() const { + LangOptions LO; + return getAsString(PrintingPolicy(LO)); +} + +// Appends qualifiers to the given string, separated by spaces. Will +// prefix a space if the string is non-empty. Will not append a final +// space. +void Qualifiers::getAsStringInternal(std::string &S, + const PrintingPolicy&) const { + AppendTypeQualList(S, getCVRQualifiers()); + if (unsigned addrspace = getAddressSpace()) { + if (!S.empty()) S += ' '; + S += "__attribute__((address_space("; + S += llvm::utostr_32(addrspace); + S += ")))"; + } + if (Qualifiers::GC gc = getObjCGCAttr()) { + if (!S.empty()) S += ' '; + if (gc == Qualifiers::Weak) + S += "__weak"; + else + S += "__strong"; + } +} + +std::string QualType::getAsString(const Type *ty, Qualifiers qs) { + std::string buffer; + LangOptions options; + getAsStringInternal(ty, qs, buffer, PrintingPolicy(options)); + return buffer; +} + +void QualType::getAsStringInternal(const Type *ty, Qualifiers qs, + std::string &buffer, + const PrintingPolicy &policy) { + TypePrinter(policy).print(ty, qs, buffer); +} |