HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Jelly Bean MR1
|
4.2.2_r1
下载
查看原文件
收藏
根目录
external
clang
lib
AST
ASTContext.cpp
//===--- 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/CommentCommandTraits.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 "llvm/Support/Capacity.h" #include "CXXABI.h" #include
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 { HalfRank, FloatRank, DoubleRank, LongDoubleRank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (!CommentsLoaded && ExternalSource) { ExternalSource->ReadComments(); CommentsLoaded = true; } assert(D); // User can not attach documentation to implicit declarations. if (D->isImplicit()) return NULL; // User can not attach documentation to implicit instantiations. if (const FunctionDecl *FD = dyn_cast
(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } if (const VarDecl *VD = dyn_cast
(D)) { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } if (const CXXRecordDecl *CRD = dyn_cast
(D)) { if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } if (const EnumDecl *ED = dyn_cast
(D)) { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return NULL; } // TODO: handle comments for function parameters properly. if (isa
(D)) return NULL; // TODO: we could look up template parameter documentation in the template // documentation. if (isa
(D) || isa
(D) || isa
(D)) return NULL; ArrayRef
RawComments = Comments.getComments(); // If there are no comments anywhere, we won't find anything. if (RawComments.empty()) return NULL; // Find declaration location. // For Objective-C declarations we generally don't expect to have multiple // declarators, thus use declaration starting location as the "declaration // location". // For all other declarations multiple declarators are used quite frequently, // so we use the location of the identifier as the "declaration location". SourceLocation DeclLoc; if (isa
(D) || isa
(D) || isa
(D) || isa
(D) || isa
(D)) DeclLoc = D->getLocStart(); else DeclLoc = D->getLocation(); // If the declaration doesn't map directly to a location in a file, we // can't find the comment. if (DeclLoc.isInvalid() || !DeclLoc.isFileID()) return NULL; // Find the comment that occurs just after this declaration. ArrayRef
::iterator Comment; { // When searching for comments during parsing, the comment we are looking // for is usually among the last two comments we parsed -- check them // first. RawComment CommentAtDeclLoc(SourceMgr, SourceRange(DeclLoc)); BeforeThanCompare
Compare(SourceMgr); ArrayRef
::iterator MaybeBeforeDecl = RawComments.end() - 1; bool Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); if (!Found && RawComments.size() >= 2) { MaybeBeforeDecl--; Found = Compare(*MaybeBeforeDecl, &CommentAtDeclLoc); } if (Found) { Comment = MaybeBeforeDecl + 1; assert(Comment == std::lower_bound(RawComments.begin(), RawComments.end(), &CommentAtDeclLoc, Compare)); } else { // Slow path. Comment = std::lower_bound(RawComments.begin(), RawComments.end(), &CommentAtDeclLoc, Compare); } } // Decompose the location for the declaration and find the beginning of the // file buffer. std::pair
DeclLocDecomp = SourceMgr.getDecomposedLoc(DeclLoc); // First check whether we have a trailing comment. if (Comment != RawComments.end() && (*Comment)->isDocumentation() && (*Comment)->isTrailingComment() && (isa
(D) || isa
(D) || isa
(D))) { std::pair
CommentBeginDecomp = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getBegin()); // Check that Doxygen trailing comment comes after the declaration, starts // on the same line and in the same file as the declaration. if (DeclLocDecomp.first == CommentBeginDecomp.first && SourceMgr.getLineNumber(DeclLocDecomp.first, DeclLocDecomp.second) == SourceMgr.getLineNumber(CommentBeginDecomp.first, CommentBeginDecomp.second)) { return *Comment; } } // The comment just after the declaration was not a trailing comment. // Let's look at the previous comment. if (Comment == RawComments.begin()) return NULL; --Comment; // Check that we actually have a non-member Doxygen comment. if (!(*Comment)->isDocumentation() || (*Comment)->isTrailingComment()) return NULL; // Decompose the end of the comment. std::pair
CommentEndDecomp = SourceMgr.getDecomposedLoc((*Comment)->getSourceRange().getEnd()); // If the comment and the declaration aren't in the same file, then they // aren't related. if (DeclLocDecomp.first != CommentEndDecomp.first) return NULL; // Get the corresponding buffer. bool Invalid = false; const char *Buffer = SourceMgr.getBufferData(DeclLocDecomp.first, &Invalid).data(); if (Invalid) return NULL; // Extract text between the comment and declaration. StringRef Text(Buffer + CommentEndDecomp.second, DeclLocDecomp.second - CommentEndDecomp.second); // There should be no other declarations or preprocessor directives between // comment and declaration. if (Text.find_first_of(",;{}#@") != StringRef::npos) return NULL; return *Comment; } namespace { /// If we have a 'templated' declaration for a template, adjust 'D' to /// refer to the actual template. /// If we have an implicit instantiation, adjust 'D' to refer to template. const Decl *adjustDeclToTemplate(const Decl *D) { if (const FunctionDecl *FD = dyn_cast
(D)) { // Is this function declaration part of a function template? if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) return FTD; // Nothing to do if function is not an implicit instantiation. if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) return D; // Function is an implicit instantiation of a function template? if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) return FTD; // Function is instantiated from a member definition of a class template? if (const FunctionDecl *MemberDecl = FD->getInstantiatedFromMemberFunction()) return MemberDecl; return D; } if (const VarDecl *VD = dyn_cast
(D)) { // Static data member is instantiated from a member definition of a class // template? if (VD->isStaticDataMember()) if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember()) return MemberDecl; return D; } if (const CXXRecordDecl *CRD = dyn_cast
(D)) { // Is this class declaration part of a class template? if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate()) return CTD; // Class is an implicit instantiation of a class template or partial // specialization? if (const ClassTemplateSpecializationDecl *CTSD = dyn_cast
(CRD)) { if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation) return D; llvm::PointerUnion
PU = CTSD->getSpecializedTemplateOrPartial(); return PU.is
() ? static_cast
(PU.get
()) : static_cast
( PU.get
()); } // Class is instantiated from a member definition of a class template? if (const MemberSpecializationInfo *Info = CRD->getMemberSpecializationInfo()) return Info->getInstantiatedFrom(); return D; } if (const EnumDecl *ED = dyn_cast
(D)) { // Enum is instantiated from a member definition of a class template? if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum()) return MemberDecl; return D; } // FIXME: Adjust alias templates? return D; } } // unnamed namespace const RawComment *ASTContext::getRawCommentForAnyRedecl( const Decl *D, const Decl **OriginalDecl) const { D = adjustDeclToTemplate(D); // Check whether we have cached a comment for this declaration already. { llvm::DenseMap
::iterator Pos = RedeclComments.find(D); if (Pos != RedeclComments.end()) { const RawCommentAndCacheFlags &Raw = Pos->second; if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { if (OriginalDecl) *OriginalDecl = Raw.getOriginalDecl(); return Raw.getRaw(); } } } // Search for comments attached to declarations in the redeclaration chain. const RawComment *RC = NULL; const Decl *OriginalDeclForRC = NULL; for (Decl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I) { llvm::DenseMap
::iterator Pos = RedeclComments.find(*I); if (Pos != RedeclComments.end()) { const RawCommentAndCacheFlags &Raw = Pos->second; if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { RC = Raw.getRaw(); OriginalDeclForRC = Raw.getOriginalDecl(); break; } } else { RC = getRawCommentForDeclNoCache(*I); OriginalDeclForRC = *I; RawCommentAndCacheFlags Raw; if (RC) { Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromDecl); } else Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl); Raw.setOriginalDecl(*I); RedeclComments[*I] = Raw; if (RC) break; } } // If we found a comment, it should be a documentation comment. assert(!RC || RC->isDocumentation()); if (OriginalDecl) *OriginalDecl = OriginalDeclForRC; // Update cache for every declaration in the redeclaration chain. RawCommentAndCacheFlags Raw; Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromRedecl); Raw.setOriginalDecl(OriginalDeclForRC); for (Decl::redecl_iterator I = D->redecls_begin(), E = D->redecls_end(); I != E; ++I) { RawCommentAndCacheFlags &R = RedeclComments[*I]; if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl) R = Raw; } return RC; } comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const { D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); llvm::DenseMap
::iterator Pos = ParsedComments.find(Canonical); if (Pos != ParsedComments.end()) return Pos->second; const Decl *OriginalDecl; const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); if (!RC) return NULL; // If the RawComment was attached to other redeclaration of this Decl, we // should parse the comment in context of that other Decl. This is important // because comments can contain references to parameter names which can be // different across redeclarations. if (D != OriginalDecl) return getCommentForDecl(OriginalDecl); comments::FullComment *FC = RC->parse(*this, D); ParsedComments[Canonical] = FC; return FC; } 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
(*P)) { ID.AddInteger(0); ID.AddBoolean(TTP->isParameterPack()); continue; } if (NonTypeTemplateParmDecl *NTTP = dyn_cast
(*P)) { ID.AddInteger(1); ID.AddBoolean(NTTP->isParameterPack()); ID.AddPointer(NTTP->getType().getCanonicalType().getAsOpaquePtr()); if (NTTP->isExpandedParameterPack()) { ID.AddBoolean(true); ID.AddInteger(NTTP->getNumExpansionTypes()); for (unsigned I = 0, N = NTTP->getNumExpansionTypes(); I != N; ++I) { QualType T = NTTP->getExpansionType(I); ID.AddPointer(T.getCanonicalType().getAsOpaquePtr()); } } else ID.AddBoolean(false); continue; } TemplateTemplateParmDecl *TTP = cast
(*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(); SmallVector
CanonParams; CanonParams.reserve(Params->size()); for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); P != PEnd; ++P) { if (TemplateTypeParmDecl *TTP = dyn_cast
(*P)) CanonParams.push_back( TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), TTP->getDepth(), TTP->getIndex(), 0, false, TTP->isParameterPack())); else if (NonTypeTemplateParmDecl *NTTP = dyn_cast
(*P)) { QualType T = getCanonicalType(NTTP->getType()); TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); NonTypeTemplateParmDecl *Param; if (NTTP->isExpandedParameterPack()) { SmallVector
ExpandedTypes; SmallVector
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
(*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); } llvm_unreachable("Invalid CXXABI type!"); } 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 4, // cuda_device 5, // cuda_constant 6 // cuda_shared }; return &FakeAddrSpaceMap; } else { return &T.getAddressSpaceMap(); } } ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, const TargetInfo *t, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins, unsigned size_reserve, bool DelayInitialization) : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(0), Int128Decl(0), UInt128Decl(0), BuiltinVaListDecl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0), BOOLDecl(0), CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0), BlockDescriptorType(0), BlockDescriptorExtendedType(0), cudaConfigureCallDecl(0), NullTypeSourceInfo(QualType()), FirstLocalImport(), LastLocalImport(), SourceMgr(SM), LangOpts(LOpts), AddrSpaceMap(0), Target(t), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), CommentCommandTraits(BumpAlloc), LastSDM(0, 0), UniqueBlockByRefTypeID(0) { if (size_reserve > 0) Types.reserve(size_reserve); TUDecl = TranslationUnitDecl::Create(*this); if (!DelayInitialization) { assert(t && "No target supplied for ASTContext initialization"); InitBuiltinTypes(*t); } } 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); // ASTRecordLayout objects in ASTRecordLayouts must always be destroyed // because they can contain DenseMaps. for (llvm::DenseMap
::iterator I = ObjCLayouts.begin(), E = ObjCLayouts.end(); I != E; ) // Increment in loop to prevent using deallocated memory. if (ASTRecordLayout *R = const_cast
((I++)->second)) R->Destroy(*this); for (llvm::DenseMap
::iterator I = ASTRecordLayouts.begin(), E = ASTRecordLayouts.end(); I != E; ) { // Increment in loop to prevent using deallocated memory. if (ASTRecordLayout *R = const_cast
((I++)->second)) R->Destroy(*this); } for (llvm::DenseMap
::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(OwningPtr
&Source) { ExternalSource.reset(Source.take()); } void ASTContext::PrintStats() const { llvm::errs() << "\n*** AST Context Stats:\n"; llvm::errs() << " " << Types.size() << " types total.\n"; 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]) \ llvm::errs() << " " << counts[Idx] << " " << #Name \ << " types\n"; \ TotalBytes += counts[Idx] * sizeof(Name##Type); \ ++Idx; #define ABSTRACT_TYPE(Name, Parent) #include "clang/AST/TypeNodes.def" llvm::errs() << "Total bytes = " << TotalBytes << "\n"; // Implicit special member functions. llvm::errs() << NumImplicitDefaultConstructorsDeclared << "/" << NumImplicitDefaultConstructors << " implicit default constructors created\n"; llvm::errs() << NumImplicitCopyConstructorsDeclared << "/" << NumImplicitCopyConstructors << " implicit copy constructors created\n"; if (getLangOpts().CPlusPlus) llvm::errs() << NumImplicitMoveConstructorsDeclared << "/" << NumImplicitMoveConstructors << " implicit move constructors created\n"; llvm::errs() << NumImplicitCopyAssignmentOperatorsDeclared << "/" << NumImplicitCopyAssignmentOperators << " implicit copy assignment operators created\n"; if (getLangOpts().CPlusPlus) llvm::errs() << NumImplicitMoveAssignmentOperatorsDeclared << "/" << NumImplicitMoveAssignmentOperators << " implicit move assignment operators created\n"; llvm::errs() << NumImplicitDestructorsDeclared << "/" << NumImplicitDestructors << " implicit destructors created\n"; if (ExternalSource.get()) { llvm::errs() << "\n"; ExternalSource->PrintStats(); } BumpAlloc.PrintStats(); } TypedefDecl *ASTContext::getInt128Decl() const { if (!Int128Decl) { TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(Int128Ty); Int128Decl = TypedefDecl::Create(const_cast
(*this), getTranslationUnitDecl(), SourceLocation(), SourceLocation(), &Idents.get("__int128_t"), TInfo); } return Int128Decl; } TypedefDecl *ASTContext::getUInt128Decl() const { if (!UInt128Decl) { TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(UnsignedInt128Ty); UInt128Decl = TypedefDecl::Create(const_cast
(*this), getTranslationUnitDecl(), SourceLocation(), SourceLocation(), &Idents.get("__uint128_t"), TInfo); } return UInt128Decl; } 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(const TargetInfo &Target) { assert((!this->Target || this->Target == &Target) && "Incorrect target reinitialization"); assert(VoidTy.isNull() && "Context reinitialized?"); this->Target = &Target; ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); // 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 && LangOpts.WChar) { // 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 (or C++ using -fno-wchar) WCharTy = getFromTargetType(Target.getWCharType()); WIntTy = getFromTargetType(Target.getWIntType()); 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); // Placeholder type for pseudo-objects. InitBuiltinType(PseudoObjectTy, BuiltinType::PseudoObject); // "any" type; useful for debugger-like clients. InitBuiltinType(UnknownAnyTy, BuiltinType::UnknownAny); // Placeholder type for unbridged ARC casts. InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast); // Placeholder type for builtin functions. InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); // Builtin type for __objc_yes and __objc_no ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? SignedCharTy : BoolTy); ObjCConstantStringType = QualType(); // void * type VoidPtrTy = getPointerType(VoidTy); // nullptr type (C++0x 2.14.7) InitBuiltinType(NullPtrTy, BuiltinType::NullPtr); // half type (OpenCL 6.1.1.1) / ARM NEON __fp16 InitBuiltinType(HalfTy, BuiltinType::Half); // Builtin type used to help define __builtin_va_list. VaListTagTy = QualType(); } DiagnosticsEngine &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
::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
::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); } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( const FunctionDecl *FD){ assert(FD && "Specialization is 0"); llvm::DenseMap
::const_iterator Pos = ClassScopeSpecializationPattern.find(FD); if (Pos == ClassScopeSpecializationPattern.end()) return 0; return Pos->second; } void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD, FunctionDecl *Pattern) { assert(FD && "Specialization is 0"); assert(Pattern && "Class scope specialization pattern is 0"); ClassScopeSpecializationPattern[FD] = Pattern; } NamedDecl * ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) { llvm::DenseMap
::const_iterator Pos = InstantiatedFromUsingDecl.find(UUD); if (Pos == InstantiatedFromUsingDecl.end()) return 0; return Pos->second; } void ASTContext::setInstantiatedFromUsingDecl(UsingDecl *Inst, NamedDecl *Pattern) { assert((isa
(Pattern) || isa
(Pattern) || isa
(Pattern)) && "pattern decl is not a using decl"); assert(!InstantiatedFromUsingDecl[Inst] && "pattern already exists"); InstantiatedFromUsingDecl[Inst] = Pattern; } UsingShadowDecl * ASTContext::getInstantiatedFromUsingShadowDecl(UsingShadowDecl *Inst) { llvm::DenseMap
::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
::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->getBitWidthValue(*this) == 0); } bool ASTContext::ZeroBitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && LastFD->isBitField() && FD->getBitWidthValue(*this) == 0 && LastFD->getBitWidthValue(*this) != 0); } bool ASTContext::BitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && LastFD->isBitField() && FD->getBitWidthValue(*this) && LastFD->getBitWidthValue(*this)); } bool ASTContext::NonBitfieldFollowsBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (!FD->isBitField() && LastFD && LastFD->isBitField() && LastFD->getBitWidthValue(*this)); } bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, const FieldDecl *LastFD) const { return (FD->isBitField() && LastFD && !LastFD->isBitField() && FD->getBitWidthValue(*this)); } ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap
::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_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_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); } void ASTContext::addedLocalImportDecl(ImportDecl *Import) { assert(!Import->NextLocalImport && "Import declaration already in the chain"); assert(!Import->isFromASTFile() && "Non-local import declaration"); if (!FirstLocalImport) { FirstLocalImport = Import; LastLocalImport = Import; return; } LastLocalImport->NextLocalImport = Import; LastLocalImport = Import; } //===----------------------------------------------------------------------===// // 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
(); assert(BT && "Not a floating point type!"); switch (BT->getKind()) { default: llvm_unreachable("Not a floating point type!"); case BuiltinType::Half: return Target->getHalfFormat(); 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 alignas to decrease alignment, so we can // ignore that possibility; Sema should diagnose it. if (isa
(D)) { UseAlignAttrOnly = D->hasAttr
() || cast
(D)->getParent()->hasAttr
(); } else { UseAlignAttrOnly = true; } } else if (isa
(D)) UseAlignAttrOnly = D->hasAttr
() || cast
(D)->getParent()->hasAttr
(); // 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
(D)) { QualType T = VD->getType(); if (const ReferenceType* RT = T->getAs
()) { 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
(arrayType)) Align = std::max(Align, Target->getLargeArrayAlign()); else if (isa
(arrayType) && MinWidth <= getTypeSize(cast
(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
(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
(lowBitOfOffset); } Align = std::min(Align, fieldAlign); } } return toCharUnitsFromBits(Align); } // getTypeInfoDataSizeInChars - Return the size of a type, in // chars. If the type is a record, its data size is returned. This is // the size of the memcpy that's performed when assigning this type // using a trivial copy/move assignment operator. std::pair
ASTContext::getTypeInfoDataSizeInChars(QualType T) const { std::pair
sizeAndAlign = getTypeInfoInChars(T); // In C++, objects can sometimes be allocated into the tail padding // of a base-class subobject. We decide whether that's possible // during class layout, so here we can just trust the layout results. if (getLangOpts().CPlusPlus) { if (const RecordType *RT = T->getAs
()) { const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); sizeAndAlign.first = layout.getDataSize(); } } return sizeAndAlign; } std::pair
ASTContext::getTypeInfoInChars(const Type *T) const { std::pair
Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); } std::pair
ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } std::pair
ASTContext::getTypeInfo(const Type *T) const { TypeInfoMap::iterator it = MemoizedTypeInfo.find(T); if (it != MemoizedTypeInfo.end()) return it->second; std::pair
Info = getTypeInfoImpl(T); MemoizedTypeInfo.insert(std::make_pair(T, Info)); return Info; } /// getTypeInfoImpl - 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
ASTContext::getTypeInfoImpl(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" llvm_unreachable("Should not see dependent types"); 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
(T)->getElementType()); break; case Type::ConstantArray: { const ConstantArrayType *CAT = cast
(T); std::pair
EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) && "Overflow in array type bit size evaluation"); Width = EltInfo.first*Size; Align = EltInfo.second; Width = llvm::RoundUpToAlignment(Width, Align); break; } case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast
(T); std::pair
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); } // Adjust the alignment based on the target max. uint64_t TargetVectorAlign = Target->getMaxVectorAlign(); if (TargetVectorAlign && TargetVectorAlign < Align) Align = TargetVectorAlign; break; } case Type::Builtin: switch (cast
(T)->getKind()) { default: llvm_unreachable("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::Half: Width = Target->getHalfWidth(); Align = Target->getHalfAlign(); 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
(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
(T)->getPointeeType()); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; } case Type::Pointer: { unsigned AS = getTargetAddressSpace(cast
(T)->getPointeeType()); Width = Target->getPointerWidth(AS); Align = Target->getPointerAlign(AS); break; } case Type::MemberPointer: { const MemberPointerType *MPT = cast
(T); std::pair
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
EltInfo = getTypeInfo(cast
(T)->getElementType()); Width = EltInfo.first*2; Align = EltInfo.second; break; } case Type::ObjCObject: return getTypeInfo(cast
(T)->getBaseType().getTypePtr()); case Type::ObjCInterface: { const ObjCInterfaceType *ObjCI = cast
(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
(T); if (TT->getDecl()->isInvalidDecl()) { Width = 8; Align = 8; break; } if (const EnumType *ET = dyn_cast
(TT)) return getTypeInfo(ET->getDecl()->getIntegerType()); const RecordType *RT = cast
(TT); const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); break; } case Type::SubstTemplateTypeParm: return getTypeInfo(cast
(T)-> getReplacementType().getTypePtr()); case Type::Auto: { const AutoType *A = cast
(T); assert(A->isDeduced() && "Cannot request the size of a dependent type"); return getTypeInfo(A->getDeducedType().getTypePtr()); } case Type::Paren: return getTypeInfo(cast
(T)->getInnerType().getTypePtr()); case Type::Typedef: { const TypedefNameDecl *Typedef = cast
(T)->getDecl(); std::pair
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
(T)->getUnderlyingExpr()->getType() .getTypePtr()); case Type::TypeOf: return getTypeInfo(cast
(T)->getUnderlyingType().getTypePtr()); case Type::Decltype: return getTypeInfo(cast
(T)->getUnderlyingExpr()->getType() .getTypePtr()); case Type::UnaryTransform: return getTypeInfo(cast
(T)->getUnderlyingType()); case Type::Elaborated: return getTypeInfo(cast
(T)->getNamedType().getTypePtr()); case Type::Attributed: return getTypeInfo( cast
(T)->getEquivalentType().getTypePtr()); case Type::TemplateSpecialization: { assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); const TemplateSpecializationType *TST = cast
(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)); } case Type::Atomic: { std::pair
Info = getTypeInfo(cast
(T)->getValueType()); Width = Info.first; Align = Info.second; if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth() && llvm::isPowerOf2_64(Width)) { // We can potentially perform lock-free atomic operations for this // type; promote the alignment appropriately. // FIXME: We could potentially promote the width here as well... // is that worthwhile? (Non-struct atomic types generally have // power-of-two size anyway, but structs might not. Requires a bit // of implementation work to make sure we zero out the extra bits.) Align = static_cast
(Width); } } } assert(llvm::isPowerOf2_32(Align) && "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
()) T = CT->getElementType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong)) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; } /// 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, SmallVectorImpl
&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 { ObjCInterfaceDecl *IDecl = const_cast
(OI); for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; Iv= Iv->getNextIvar()) Ivars.push_back(Iv); } } /// CollectInheritedProtocols - Collect all protocols in current class and /// those inherited by it. void ASTContext::CollectInheritedProtocols(const Decl *CDecl, llvm::SmallPtrSet
&Protocols) { if (const ObjCInterfaceDecl *OI = dyn_cast
(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->getCanonicalDecl()); for (ObjCProtocolDecl::protocol_iterator P = Proto->protocol_begin(), PE = Proto->protocol_end(); P != PE; ++P) { Protocols.insert((*P)->getCanonicalDecl()); 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
(CDecl)) { for (ObjCCategoryDecl::protocol_iterator P = OC->protocol_begin(), PE = OC->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); Protocols.insert(Proto->getCanonicalDecl()); 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
(CDecl)) { for (ObjCProtocolDecl::protocol_iterator P = OP->protocol_begin(), PE = OP->protocol_end(); P != PE; ++P) { ObjCProtocolDecl *Proto = (*P); Protocols.insert(Proto->getCanonicalDecl()); 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; } bool ASTContext::isSentinelNullExpr(const Expr *E) { if (!E) return false; // nullptr_t is always treated as null. if (E->getType()->isNullPtrType()) return true; if (E->getType()->isAnyPointerType() && E->IgnoreParenCasts()->isNullPointerConstant(*this, Expr::NPC_ValueDependentIsNull)) return true; // Unfortunately, __null has type 'int'. if (isa
(E)) return true; return false; } /// \brief Get the implementation of ObjCInterfaceDecl,or NULL if none exists. ObjCImplementationDecl *ASTContext::getObjCImplementation(ObjCInterfaceDecl *D) { llvm::DenseMap
::iterator I = ObjCImpls.find(D); if (I != ObjCImpls.end()) return cast
(I->second); return 0; } /// \brief Get the implementation of ObjCCategoryDecl, or NULL if none exists. ObjCCategoryImplDecl *ASTContext::getObjCImplementation(ObjCCategoryDecl *D) { llvm::DenseMap
::iterator I = ObjCImpls.find(D); if (I != ObjCImpls.end()) return cast
(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; } ObjCInterfaceDecl *ASTContext::getObjContainingInterface(NamedDecl *ND) const { if (ObjCInterfaceDecl *ID = dyn_cast
(ND->getDeclContext())) return ID; if (ObjCCategoryDecl *CD = dyn_cast
(ND->getDeclContext())) return CD->getClassInterface(); if (ObjCImplDecl *IMD = dyn_cast
(ND->getDeclContext())) return IMD->getClassInterface(); return 0; } /// \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
() && "getBlockVarCopyInits - not __block var"); llvm::DenseMap
::iterator I = BlockVarCopyInits.find(VD); return (I != BlockVarCopyInits.end()) ? cast
(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
() && "setBlockVarCopyInits - not __block var"); BlockVarCopyInits[VD] = Init; } 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
(*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.Quals.addConsistentQualifiers(quals); canon = getExtQualType(canonSplit.Ty, canonSplit.Quals); // 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
()) { 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
(T)) { Result = getFunctionNoProtoType(FNPT->getResultType(), Info); } else { const FunctionProtoType *FPT = cast
(T); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = Info; Result = getFunctionType(FPT->getResultType(), FPT->arg_type_begin(), FPT->getNumArgs(), EPI); } return cast
(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
(); // 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
(); // 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.Ty, 0), ArySize, ASM, IndexTypeQuals); Canon = getQualifiedType(Canon, canonSplit.Quals); // 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.Ty; 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
(ty)->getPointeeType())); break; case Type::LValueReference: { const LValueReferenceType *lv = cast
(ty); result = getLValueReferenceType( getVariableArrayDecayedType(lv->getPointeeType()), lv->isSpelledAsLValue()); break; } case Type::RValueReference: { const RValueReferenceType *lv = cast
(ty); result = getRValueReferenceType( getVariableArrayDecayedType(lv->getPointeeType())); break; } case Type::Atomic: { const AtomicType *at = cast
(ty); result = getAtomicType(getVariableArrayDecayedType(at->getValueType())); break; } case Type::ConstantArray: { const ConstantArrayType *cat = cast
(ty); result = getConstantArrayType( getVariableArrayDecayedType(cat->getElementType()), cat->getSize(), cat->getSizeModifier(), cat->getIndexTypeCVRQualifiers()); break; } case Type::DependentSizedArray: { const DependentSizedArrayType *dat = cast
(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
(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
(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.Quals); } /// 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.Ty, 0), NumElts, ASM, IndexTypeQuals, Brackets); Canon = getQualifiedType(Canon, canonSplit.Quals); } 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.Ty, 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.Ty, 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.Quals); // If we didn't need extra canonicalization for the element type, // then just use that as our result. if (QualType(canonElementType.Ty, 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.Ty, 0), ASM, elementTypeQuals); canon = getQualifiedType(canon, canonSplit.Quals); // 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() || vecType->isDependentType()); // 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() && !EPI.HasTrailingReturn; 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) { SmallVector
CanonicalArgs; CanonicalArgs.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) CanonicalArgs.push_back(getCanonicalParamType(ArgArray[i])); FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI; CanonicalEPI.HasTrailingReturn = false; 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 three variable size arrays at the end: // - parameter types // - exception types // - consumed-arguments flags // Instead of the exception types, there could be a noexcept // expression, or information used to resolve the exception // specification. 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*); } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); } else if (EPI.ExceptionSpecType == EST_Unevaluated) { Size += sizeof(FunctionDecl*); } if (EPI.ConsumedArguments) Size += NumArgs * sizeof(bool); 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
(D)) return false; const CXXRecordDecl *RD = cast
(D); if (isa
(RD)) return true; if (RD->getDescribedClassTemplate() && !isa
(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
(Decl->TypeForDecl)); } else if (CXXRecordDecl *PrevDecl = Decl->getPreviousDecl()) { assert(PrevDecl->TypeForDecl && "previous declaration has no type"); Decl->TypeForDecl = PrevDecl->TypeForDecl; assert(isa
(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
(Decl)) return getTypedefType(Typedef); assert(!isa
(Decl) && "Template type parameter types are always available."); if (const RecordDecl *Record = dyn_cast
(Decl)) { assert(!Record->getPreviousDecl() && "struct/union has previous declaration"); assert(!NeedsInjectedClassNameType(Record)); return getRecordType(Record); } else if (const EnumDecl *Enum = dyn_cast
(Decl)) { assert(!Enum->getPreviousDecl() && "enum has previous declaration"); return getEnumType(Enum); } else if (const UnresolvedUsingTypenameDecl *Using = dyn_cast
(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->getPreviousDecl()) 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->getPreviousDecl()) 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
(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
(DI->getTypeLoc()); TL.setTemplateKeywordLoc(SourceLocation()); 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(); SmallVector
ArgVec; ArgVec.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Underlying); } #ifndef NDEBUG static bool hasAnyPackExpansions(const TemplateArgument *Args, unsigned NumArgs) { for (unsigned I = 0; I != NumArgs; ++I) if (Args[I].isPackExpansion()) return true; return true; } #endif 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
(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); else { // We can get here with an alias template when the specialization contains // a pack expansion that does not match up with a parameter pack. assert((!IsTypeAlias || hasAnyPackExpansions(Args, NumArgs)) && "Caller must compute aliased type"); IsTypeAlias = false; 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!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector
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 SmallVector
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; SmallVector
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
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 = getCanonicalType(Pattern); // The canonical type might not contain an unexpanded parameter pack, if it // contains an alias template specialization which ignores one of its // parameters. if (Canon->containsUnexpandedParameterPack()) { Canon = getPackExpansionType(getCanonicalType(Pattern), NumExpansions); // Find the insert position again, in case we inserted an element into // PackExpansionTypes and invalidated our insert position. 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; if (Protocols[0]->getCanonicalDecl() != Protocols[0]) return false; for (unsigned i = 1; i != NumProtocols; ++i) if (!CmpProtocolNames(Protocols[i-1], Protocols[i]) || Protocols[i]->getCanonicalDecl() != 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); // Canonicalize. for (unsigned I = 0, N = NumProtocols; I != N; ++I) Protocols[I] = Protocols[I]->getCanonicalDecl(); // 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
(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) { SmallVector
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, ObjCInterfaceDecl *PrevDecl) const { if (Decl->TypeForDecl) return QualType(Decl->TypeForDecl, 0); if (PrevDecl) { assert(PrevDecl->TypeForDecl && "previous decl has no TypeForDecl"); Decl->TypeForDecl = PrevDecl->TypeForDecl; return QualType(PrevDecl->TypeForDecl, 0); } // Prefer the definition, if there is one. if (const ObjCInterfaceDecl *Def = Decl->getDefinition()) Decl = Def; 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
" 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
" 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); } /// getDecltypeType - Unlike many "get
" 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 types (which are always unique). QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { DecltypeType *dt; // C++0x [temp.type]p2: // If an expression e involves a template parameter, decltype(e) denotes a // unique dependent type. Two such decltype-specifiers refer to the same // type only if their expressions are equivalent (14.5.6.1). if (e->isInstantiationDependent()) { 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, UnderlyingType, 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 { dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType, getCanonicalType(UnderlyingType)); } 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() : getCanonicalType(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); } /// getAtomicType - Return the uniqued reference to the atomic type for /// the given value type. QualType ASTContext::getAtomicType(QualType T) const { // Unique pointers, to guarantee there is only one pointer of a particular // structure. llvm::FoldingSetNodeID ID; AtomicType::Profile(ID, T); void *InsertPos = 0; if (AtomicType *AT = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); // If the atomic value 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 = getAtomicType(getCanonicalType(T)); // Get the new insert position for the node we care about. AtomicType *NewIP = AtomicTypes.FindNodeOrInsertPos(ID, InsertPos); assert(NewIP == 0 && "Shouldn't be in the map!"); (void)NewIP; } AtomicType *New = new (*this, TypeAlignment) AtomicType(T, Canonical); Types.push_back(New); AtomicTypes.InsertNode(New, InsertPos); return QualType(New, 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
(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
. CanQualType ASTContext::getSizeType() const { return getFromTargetType(Target->getSizeType()); } /// getIntMaxType - Return the unique type for "intmax_t" (C99 7.18.1.5). CanQualType ASTContext::getIntMaxType() const { return getFromTargetType(Target->getIntMaxType()); } /// getUIntMaxType - Return the unique type for "uintmax_t" (C99 7.18.1.5). CanQualType ASTContext::getUIntMaxType() const { return getFromTargetType(Target->getUIntMaxType()); } /// 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" (C99 7.17) /// defined in
. 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
(Ty)) { Result = getArrayDecayedType(QualType(Ty,0)); } else if (isa
(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
(splitType.Ty->getUnqualifiedDesugaredType()); // If we don't have an array, just use the results in splitType. if (!AT) { quals = splitType.Quals; return QualType(splitType.Ty, 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.Quals; return QualType(splitType.Ty, 0); } // Otherwise, add in the qualifiers from the outermost type, then // build the type back up. quals.addConsistentQualifiers(splitType.Quals); if (const ConstantArrayType *CAT = dyn_cast
(AT)) { return getConstantArrayType(unqualElementType, CAT->getSize(), CAT->getSizeModifier(), 0); } if (const IncompleteArrayType *IAT = dyn_cast
(AT)) { return getIncompleteArrayType(unqualElementType, IAT->getSizeModifier(), 0); } if (const VariableArrayType *VAT = dyn_cast
(AT)) { return getVariableArrayType(unqualElementType, VAT->getSizeExpr(), VAT->getSizeModifier(), VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange()); } const DependentSizedArrayType *DSAT = cast
(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
(), *T2PtrType = T2->getAs
(); if (T1PtrType && T2PtrType) { T1 = T1PtrType->getPointeeType(); T2 = T2PtrType->getPointeeType(); return true; } const MemberPointerType *T1MPType = T1->getAs
(), *T2MPType = T2->getAs
(); if (T1MPType && T2MPType && hasSameUnqualifiedType(QualType(T1MPType->getClass(), 0), QualType(T2MPType->getClass(), 0))) { T1 = T1MPType->getPointeeType(); T2 = T2MPType->getPointeeType(); return true; } if (getLangOpts().ObjC1) { const ObjCObjectPointerType *T1OPType = T1->getAs
(), *T2OPType = T2->getAs
(); 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 { switch (Name.getKind()) { case TemplateName::QualifiedTemplate: case TemplateName::Template: // DNInfo work in progress: CHECKME: what about DNLoc? return DeclarationNameInfo(Name.getAsTemplateDecl()->getDeclName(), NameLoc); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); // DNInfo work in progress: CHECKME: what about DNLoc? return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } case TemplateName::DependentTemplate: { 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); } } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = Name.getAsSubstTemplateTemplateParm(); return DeclarationNameInfo(subst->getParameter()->getDeclName(), NameLoc); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *subst = Name.getAsSubstTemplateTemplateParmPack(); return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), NameLoc); } } llvm_unreachable("bad template name kind!"); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { switch (Name.getKind()) { case TemplateName::QualifiedTemplate: case TemplateName::Template: { TemplateDecl *Template = Name.getAsTemplateDecl(); if (TemplateTemplateParmDecl *TTP = dyn_cast
(Template)) Template = getCanonicalTemplateTemplateParmDecl(TTP); // The canonical template name is the canonical template declaration. return TemplateName(cast
(Template->getCanonicalDecl())); } case TemplateName::OverloadedTemplate: llvm_unreachable("cannot canonicalize overloaded template"); case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); return DTN->CanonicalTemplateName; } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = Name.getAsSubstTemplateTemplateParm(); return getCanonicalTemplateName(subst->getReplacement()); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *subst = Name.getAsSubstTemplateTemplateParmPack(); TemplateTemplateParmDecl *canonParameter = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack()); TemplateArgument canonArgPack = getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); } } llvm_unreachable("bad template name!"); } 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: { if (Decl *D = Arg.getAsDecl()) return TemplateArgument(D->getCanonicalDecl()); return TemplateArgument((Decl*)0); } case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); case TemplateArgument::TemplateExpansion: return TemplateArgument(getCanonicalTemplateName( Arg.getAsTemplateOrTemplatePattern()), Arg.getNumTemplateExpansions()); case TemplateArgument::Integral: return TemplateArgument(Arg, 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 llvm_unreachable("Unhandled template argument kind"); } 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
()) return NestedNameSpecifier::Create(*this, DNT->getQualifier(), const_cast
(DNT->getIdentifier())); // Otherwise, just canonicalize the type, and force it to be a TypeSpec. // FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the // first place? return NestedNameSpecifier::Create(*this, 0, false, const_cast
(T.getTypePtr())); } case NestedNameSpecifier::Global: // The global specifier is canonical and unique. return NNS; } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } 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
(T)) return AT; } // Handle the common negative case fast. if (!isa
(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.Quals; // If we have a simple case, just return now. const ArrayType *ATy = dyn_cast
(split.Ty); 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
(ATy)) return cast
(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast
(ATy)) return cast
(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), IAT->getIndexTypeCVRQualifiers())); if (const DependentSizedArrayType *DSAT = dyn_cast
(ATy)) return cast
( getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), DSAT->getSizeModifier(), DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); const VariableArrayType *VAT = cast
(ATy); return cast
(getVariableArrayType(NewEltTy, VAT->getSizeExpr(), VAT->getSizeModifier(), VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange())); } QualType ASTContext::getAdjustedParameterType(QualType T) const { // C99 6.7.5.3p7: // A declaration of a parameter as "array of type" shall be // adjusted to "qualified pointer to type", where the type // qualifiers (if any) are those specified within the [ and ] of // the array type derivation. if (T->isArrayType()) return getArrayDecayedType(T); // C99 6.7.5.3p8: // A declaration of a parameter as "function returning type" // shall be adjusted to "pointer to function returning type", as // in 6.3.2.1. if (T->isFunctionType()) return getPointerType(T); return T; } QualType ASTContext::getSignatureParameterType(QualType T) const { T = getVariableArrayDecayedType(T); T = getAdjustedParameterType(T); return T.getUnqualifiedType(); } /// 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.Ty->getAsArrayTypeUnsafe(); if (!array) break; type = array->getElementType(); qs.addConsistentQualifiers(split.Quals); } 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
(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
()) return getFloatingRank(CT->getElementType()); assert(T->getAs
() && "getFloatingRank(): not a floating type"); switch (T->getAs
()->getKind()) { default: llvm_unreachable("getFloatingRank(): not a floating type"); case BuiltinType::Half: return HalfRank; 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) { case HalfRank: llvm_unreachable("Complex half is not supported"); case FloatRank: return FloatComplexTy; case DoubleRank: return DoubleComplexTy; case LongDoubleRank: return LongDoubleComplexTy; } } assert(Domain->isRealFloatingType() && "Unknown domain!"); switch (EltRank) { case HalfRank: llvm_unreachable("Half ranks are not valid here"); case FloatRank: return FloatTy; case DoubleRank: return DoubleTy; case LongDoubleRank: return LongDoubleTy; } llvm_unreachable("getFloatingRank(): illegal value for rank"); } /// 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"); switch (cast
(T)->getKind()) { default: llvm_unreachable("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(); uint64_t BitWidth = Field->getBitWidthValue(*this); 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
()) return ET->getDecl()->getPromotionType(); if (const BuiltinType *BT = Promotable->getAs
()) { // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t // (3.9.1) can be converted to a prvalue of the first of the following // types that can represent all the values of its underlying type: // int, unsigned int, long int, unsigned long int, long long int, or // unsigned long long int [...] // FIXME: Is there some better way to compute this? if (BT->getKind() == BuiltinType::WChar_S || BT->getKind() == BuiltinType::WChar_U || BT->getKind() == BuiltinType::Char16 || BT->getKind() == BuiltinType::Char32) { bool FromIsSigned = BT->getKind() == BuiltinType::WChar_S; uint64_t FromSize = getTypeSize(BT); QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy, LongLongTy, UnsignedLongLongTy }; for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) { uint64_t ToSize = getTypeSize(PromoteTypes[Idx]); if (FromSize < ToSize || (FromSize == ToSize && FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType())) return PromoteTypes[Idx]; } llvm_unreachable("char type should fit into long long"); } } // At this point, we should have a signed or unsigned integer type. 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; } /// \brief Recurses in pointer/array types until it finds an objc retainable /// type and returns its ownership. Qualifiers::ObjCLifetime ASTContext::getInnerObjCOwnership(QualType T) const { while (!T.isNull()) { if (T.getObjCLifetime() != Qualifiers::OCL_None) return T.getObjCLifetime(); if (T->isArrayType()) T = getBaseElementType(T); else if (const PointerType *PT = T->getAs
()) T = PT->getPointeeType(); else if (const ReferenceType *RT = T->getAs
()) T = RT->getPointeeType(); else break; } return Qualifiers::OCL_None; } /// 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.getLangOpts().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, ICIS_NoInit); Field->setAccess(AS_public); CFConstantStringTypeDecl->addDecl(Field); } CFConstantStringTypeDecl->completeDefinition(); } return getTagDeclType(CFConstantStringTypeDecl); } void ASTContext::setCFConstantStringType(QualType T) { const RecordType *Rec = T->getAs
(); assert(Rec && "Invalid CFConstantStringType"); CFConstantStringTypeDecl = Rec->getDecl(); } 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, ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } T->completeDefinition(); BlockDescriptorType = T; return getTagDeclType(BlockDescriptorType); } 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, ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } T->completeDefinition(); BlockDescriptorExtendedType = T; return getTagDeclType(BlockDescriptorExtendedType); } bool ASTContext::BlockRequiresCopying(QualType Ty) const { if (Ty->isObjCRetainableType()) return true; if (getLangOpts().CPlusPlus) { if (const RecordType *RT = Ty->getAs
()) { CXXRecordDecl *RD = cast
(RT->getDecl()); return RD->hasConstCopyConstructor(); } } return false; } QualType ASTContext::BuildByRefType(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 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 }; 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, ICIS_NoInit); Field->setAccess(AS_public); T->addDecl(Field); } T->completeDefinition(); return getPointerType(getTagDeclType(T)); } TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { if (!ObjCInstanceTypeDecl) ObjCInstanceTypeDecl = TypedefDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), &Idents.get("instancetype"), getTrivialTypeSourceInfo(getObjCIdType())); return ObjCInstanceTypeDecl; } // This returns true if a type has been typedefed to BOOL: // typedef
BOOL; static bool isTypeTypedefedAsBOOL(QualType T) { if (const TypedefType *TT = dyn_cast
(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
()->getPointeeType(); // Encode result type. getObjCEncodingForType(BlockTy->getAs
()->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); if (sz.isZero()) continue; assert (sz.isPositive() && "BlockExpr - Incomplete param type"); ParmOffset += sz; } // Size of the argument frame S += charUnitsToString(ParmOffset); // Block pointer and offset. S += "@?0"; // 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
(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa
(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()) continue; 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
(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa
(AT)) PType = PVDecl->getType(); } else if (PType->isFunctionType()) PType = PVDecl->getType(); getObjCEncodingForType(PType, S); S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } return false; } /// getObjCEncodingForMethodParameter - Return the encoded type for a single /// method parameter or return type. If Extended, include class names and /// block object types. void ASTContext::getObjCEncodingForMethodParameter(Decl::ObjCDeclQualifier QT, QualType T, std::string& S, bool Extended) const { // Encode type qualifer, 'in', 'inout', etc. for the parameter. getObjCEncodingForTypeQualifier(QT, S); // Encode parameter type. getObjCEncodingForTypeImpl(T, S, true, true, 0, true /*OutermostType*/, false /*EncodingProperty*/, false /*StructField*/, Extended /*EncodeBlockParameters*/, Extended /*EncodeClassNames*/); } /// getObjCEncodingForMethodDecl - Return the encoded type for this method /// declaration. bool ASTContext::getObjCEncodingForMethodDecl(const ObjCMethodDecl *Decl, std::string& S, bool Extended) const { // FIXME: This is not very efficient. // Encode return type. getObjCEncodingForMethodParameter(Decl->getObjCDeclQualifier(), Decl->getResultType(), S, Extended); // 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_const_iterator PI = Decl->param_begin(), E = Decl->sel_param_end(); PI != E; ++PI) { QualType PType = (*PI)->getType(); CharUnits sz = getObjCEncodingTypeSize(PType); if (sz.isZero()) continue; 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_const_iterator PI = Decl->param_begin(), E = Decl->sel_param_end(); PI != E; ++PI) { const ParmVarDecl *PVDecl = *PI; QualType PType = PVDecl->getOriginalType(); if (const ArrayType *AT = dyn_cast
(PType->getCanonicalTypeInternal())) { // Use array's original type only if it has known number of // elements. if (!isa
(AT)) PType = PVDecl->getType(); } else if (PType->isFunctionType()) PType = PVDecl->getType(); getObjCEncodingForMethodParameter(PVDecl->getObjCDeclQualifier(), PType, S, Extended); 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
(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
(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; case ObjCPropertyDecl::Weak: S += ",W"; 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
(PointeeTy.getTypePtr())) { if (const BuiltinType *BT = PointeeTy->getAs
()) { 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
()->getKind()) { default: llvm_unreachable("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 char ObjCEncodingForEnumType(const ASTContext *C, const EnumType *ET) { EnumDecl *Enum = ET->getDecl(); // The encoding of an non-fixed enum type is always 'i', regardless of size. if (!Enum->isFixed()) return 'i'; // The encoding of a fixed enum type matches its fixed underlying type. return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType()); } static void EncodeBitField(const ASTContext *Ctx, std::string& S, QualType T, const FieldDecl *FD) { assert(FD->isBitField() && "not a bitfield - 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->getLangOpts().ObjCRuntime.isGNUFamily()) { const RecordDecl *RD = FD->getParent(); const ASTRecordLayout &RL = Ctx->getASTRecordLayout(RD); S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex())); if (const EnumType *ET = T->getAs
()) S += ObjCEncodingForEnumType(Ctx, ET); else S += ObjCEncodingForPrimitiveKind(Ctx, T); } S += llvm::utostr(FD->getBitWidthValue(*Ctx)); } // 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, bool EncodeBlockParameters, bool EncodeClassNames) const { if (T->getAs
()) { if (FD && FD->isBitField()) return EncodeBitField(this, S, T, FD); S += ObjCEncodingForPrimitiveKind(this, T); return; } if (const ComplexType *CT = T->getAs
()) { 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
()) { if (PT->isObjCSelType()) { S += ':'; return; } PointeeTy = PT->getPointeeType(); } else if (const ReferenceType *RT = T->getAs
()) 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
(T.getTypePtr())) { if (OutermostType && T.isConstQualified()) { isReadOnly = true; S += 'r'; } } else if (OutermostType) { QualType P = PointeeTy; while (P->getAs
()) P = P->getAs
()->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 (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
()) { // 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
(T->getCanonicalTypeInternal())) { if (isa