HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
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 "CXXABI.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Comment.h" #include "clang/AST/CommentCommandTraits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/Mangle.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/VTableBuilder.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/ADT/Triple.h" #include "llvm/Support/Capacity.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.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, Float128Rank }; RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { if (!CommentsLoaded && ExternalSource) { ExternalSource->ReadComments(); #ifndef NDEBUG ArrayRef
RawComments = Comments.getComments(); assert(std::is_sorted(RawComments.begin(), RawComments.end(), BeforeThanCompare
(SourceMgr))); #endif CommentsLoaded = true; } assert(D); // User can not attach documentation to implicit declarations. if (D->isImplicit()) return nullptr; // User can not attach documentation to implicit instantiations. if (const FunctionDecl *FD = dyn_cast
(D)) { if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } if (const VarDecl *VD = dyn_cast
(D)) { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } if (const CXXRecordDecl *CRD = dyn_cast
(D)) { if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } if (const ClassTemplateSpecializationDecl *CTSD = dyn_cast
(D)) { TemplateSpecializationKind TSK = CTSD->getSpecializationKind(); if (TSK == TSK_ImplicitInstantiation || TSK == TSK_Undeclared) return nullptr; } if (const EnumDecl *ED = dyn_cast
(D)) { if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return nullptr; } if (const TagDecl *TD = dyn_cast
(D)) { // When tag declaration (but not definition!) is part of the // decl-specifier-seq of some other declaration, it doesn't get comment if (TD->isEmbeddedInDeclarator() && !TD->isCompleteDefinition()) return nullptr; } // TODO: handle comments for function parameters properly. if (isa
(D)) return nullptr; // TODO: we could look up template parameter documentation in the template // documentation. if (isa
(D) || isa
(D) || isa
(D)) return nullptr; ArrayRef
RawComments = Comments.getComments(); // If there are no comments anywhere, we won't find anything. if (RawComments.empty()) return nullptr; // 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 (DeclLoc.isMacroID()) { if (isa
(D)) { // If location of the typedef name is in a macro, it is because being // declared via a macro. Try using declaration's starting location as // the "declaration location". DeclLoc = D->getLocStart(); } else if (const TagDecl *TD = dyn_cast
(D)) { // If location of the tag decl is inside a macro, but the spelling of // the tag name comes from a macro argument, it looks like a special // macro like NS_ENUM is being used to define the tag decl. In that // case, adjust the source location to the expansion loc so that we can // attach the comment to the tag decl. if (SourceMgr.isMacroArgExpansion(DeclLoc) && TD->isCompleteDefinition()) DeclLoc = SourceMgr.getExpansionLoc(DeclLoc); } } } // 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 nullptr; // 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), false, LangOpts.CommentOpts.ParseAllComments); 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) || 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 nullptr; --Comment; // Check that we actually have a non-member Doxygen comment. if (!(*Comment)->isDocumentation() || (*Comment)->isTrailingComment()) return nullptr; // 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 nullptr; // Get the corresponding buffer. bool Invalid = false; const char *Buffer = SourceMgr.getBufferData(DeclLocDecomp.first, &Invalid).data(); if (Invalid) return nullptr; // 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 nullptr; 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; } } // anonymous 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 = nullptr; const Decl *OriginalDeclForRC = nullptr; for (auto I : D->redecls()) { 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) { // Call order swapped to work around ICE in VS2015 RTM (Release Win32) // https://connect.microsoft.com/VisualStudio/feedback/details/1741530 Raw.setKind(RawCommentAndCacheFlags::FromDecl); Raw.setRaw(RC); } 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 (auto I : D->redecls()) { RawCommentAndCacheFlags &R = RedeclComments[I]; if (R.getKind() == RawCommentAndCacheFlags::NoCommentInDecl) R = Raw; } return RC; } static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, SmallVectorImpl
&Redeclared) { const DeclContext *DC = ObjCMethod->getDeclContext(); if (const ObjCImplDecl *IMD = dyn_cast
(DC)) { const ObjCInterfaceDecl *ID = IMD->getClassInterface(); if (!ID) return; // Add redeclared method here. for (const auto *Ext : ID->known_extensions()) { if (ObjCMethodDecl *RedeclaredMethod = Ext->getMethod(ObjCMethod->getSelector(), ObjCMethod->isInstanceMethod())) Redeclared.push_back(RedeclaredMethod); } } } comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, const Decl *D) const { comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo; ThisDeclInfo->CommentDecl = D; ThisDeclInfo->IsFilled = false; ThisDeclInfo->fill(); ThisDeclInfo->CommentDecl = FC->getDecl(); if (!ThisDeclInfo->TemplateParameters) ThisDeclInfo->TemplateParameters = FC->getDeclInfo()->TemplateParameters; comments::FullComment *CFC = new (*this) comments::FullComment(FC->getBlocks(), ThisDeclInfo); return CFC; } comments::FullComment *ASTContext::getLocalCommentForDeclUncached(const Decl *D) const { const RawComment *RC = getRawCommentForDeclNoCache(D); return RC ? RC->parse(*this, nullptr, D) : nullptr; } comments::FullComment *ASTContext::getCommentForDecl( const Decl *D, const Preprocessor *PP) const { if (D->isInvalidDecl()) return nullptr; D = adjustDeclToTemplate(D); const Decl *Canonical = D->getCanonicalDecl(); llvm::DenseMap
::iterator Pos = ParsedComments.find(Canonical); if (Pos != ParsedComments.end()) { if (Canonical != D) { comments::FullComment *FC = Pos->second; comments::FullComment *CFC = cloneFullComment(FC, D); return CFC; } return Pos->second; } const Decl *OriginalDecl; const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); if (!RC) { if (isa
(D) || isa
(D)) { SmallVector
Overridden; const ObjCMethodDecl *OMD = dyn_cast
(D); if (OMD && OMD->isPropertyAccessor()) if (const ObjCPropertyDecl *PDecl = OMD->findPropertyDecl()) if (comments::FullComment *FC = getCommentForDecl(PDecl, PP)) return cloneFullComment(FC, D); if (OMD) addRedeclaredMethods(OMD, Overridden); getOverriddenMethods(dyn_cast
(D), Overridden); for (unsigned i = 0, e = Overridden.size(); i < e; i++) if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) return cloneFullComment(FC, D); } else if (const TypedefNameDecl *TD = dyn_cast
(D)) { // Attach any tag type's documentation to its typedef if latter // does not have one of its own. QualType QT = TD->getUnderlyingType(); if (const TagType *TT = QT->getAs
()) if (const Decl *TD = TT->getDecl()) if (comments::FullComment *FC = getCommentForDecl(TD, PP)) return cloneFullComment(FC, D); } else if (const ObjCInterfaceDecl *IC = dyn_cast
(D)) { while (IC->getSuperClass()) { IC = IC->getSuperClass(); if (comments::FullComment *FC = getCommentForDecl(IC, PP)) return cloneFullComment(FC, D); } } else if (const ObjCCategoryDecl *CD = dyn_cast
(D)) { if (const ObjCInterfaceDecl *IC = CD->getClassInterface()) if (comments::FullComment *FC = getCommentForDecl(IC, PP)) return cloneFullComment(FC, D); } else if (const CXXRecordDecl *RD = dyn_cast
(D)) { if (!(RD = RD->getDefinition())) return nullptr; // Check non-virtual bases. for (const auto &I : RD->bases()) { if (I.isVirtual() || (I.getAccessSpecifier() != AS_public)) continue; QualType Ty = I.getType(); if (Ty.isNull()) continue; if (const CXXRecordDecl *NonVirtualBase = Ty->getAsCXXRecordDecl()) { if (!(NonVirtualBase= NonVirtualBase->getDefinition())) continue; if (comments::FullComment *FC = getCommentForDecl((NonVirtualBase), PP)) return cloneFullComment(FC, D); } } // Check virtual bases. for (const auto &I : RD->vbases()) { if (I.getAccessSpecifier() != AS_public) continue; QualType Ty = I.getType(); if (Ty.isNull()) continue; if (const CXXRecordDecl *VirtualBase = Ty->getAsCXXRecordDecl()) { if (!(VirtualBase= VirtualBase->getDefinition())) continue; if (comments::FullComment *FC = getCommentForDecl((VirtualBase), PP)) return cloneFullComment(FC, D); } } } return nullptr; } // 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, PP); comments::FullComment *FC = RC->parse(*this, PP, 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 = nullptr; 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(), nullptr, 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(), nullptr, T, TInfo, ExpandedTypes, ExpandedTInfos); } else { Param = NonTypeTemplateParmDecl::Create(*this, getTranslationUnitDecl(), SourceLocation(), SourceLocation(), NTTP->getDepth(), NTTP->getPosition(), nullptr, 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(), nullptr, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams, SourceLocation())); // Get the new insert position for the node we care about. Canonical = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); assert(!Canonical && "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 nullptr; switch (T.getCXXABI().getKind()) { case TargetCXXABI::GenericARM: // Same as Itanium at this level case TargetCXXABI::iOS: case TargetCXXABI::iOS64: case TargetCXXABI::WatchOS: case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericMIPS: case TargetCXXABI::GenericItanium: case TargetCXXABI::WebAssembly: return CreateItaniumCXXABI(*this); case TargetCXXABI::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, // opencl_generic 5, // cuda_device 6, // cuda_constant 7 // cuda_shared }; return &FakeAddrSpaceMap; } else { return &T.getAddressSpaceMap(); } } static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI, const LangOptions &LangOpts) { switch (LangOpts.getAddressSpaceMapMangling()) { case LangOptions::ASMM_Target: return TI.useAddressSpaceMapMangling(); case LangOptions::ASMM_On: return true; case LangOptions::ASMM_Off: return false; } llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything."); } ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins) : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), SubstTemplateTemplateParmPacks(this_()), GlobalNestedNameSpecifier(nullptr), Int128Decl(nullptr), UInt128Decl(nullptr), BuiltinVaListDecl(nullptr), BuiltinMSVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr), CFConstantStringTagDecl(nullptr), CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr), FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr), MakeIntegerSeqDecl(nullptr), TypePackElementDecl(nullptr), SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), AddrSpaceMap(nullptr), Target(nullptr), AuxTarget(nullptr), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr), Listener(nullptr), Comments(SM), CommentsLoaded(false), CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(nullptr, 0) { TUDecl = TranslationUnitDecl::Create(*this); } ASTContext::~ASTContext() { ReleaseParentMapEntries(); // Release the DenseMaps associated with DeclContext objects. // FIXME: Is this the ideal solution? ReleaseDeclContextMaps(); // Call all of the deallocation functions on all of their targets. for (auto &Pair : Deallocations) (Pair.first)(Pair.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(); for (std::pair
&MTVPair : MaterializedTemporaryValues) MTVPair.second->~APValue(); llvm::DeleteContainerSeconds(MangleNumberingContexts); } void ASTContext::ReleaseParentMapEntries() { if (!PointerParents) return; for (const auto &Entry : *PointerParents) { if (Entry.second.is
()) { delete Entry.second.get
(); } else if (Entry.second.is
()) { delete Entry.second.get
(); } } for (const auto &Entry : *OtherParents) { if (Entry.second.is
()) { delete Entry.second.get
(); } else if (Entry.second.is
()) { delete Entry.second.get
(); } } } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { Deallocations.push_back({Callback, Data}); } void ASTContext::setExternalSource(IntrusiveRefCntPtr
Source) { ExternalSource = std::move(Source); } 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) { llvm::errs() << "\n"; ExternalSource->PrintStats(); } BumpAlloc.PrintStats(); } void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M, bool NotifyListeners) { if (NotifyListeners) if (auto *Listener = getASTMutationListener()) Listener->RedefinedHiddenDefinition(ND, M); if (getLangOpts().ModulesLocalVisibility) MergedDefModules[ND].push_back(M); else ND->setHidden(false); } void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) { auto It = MergedDefModules.find(ND); if (It == MergedDefModules.end()) return; auto &Merged = It->second; llvm::DenseSet
Found; for (Module *&M : Merged) if (!Found.insert(M).second) M = nullptr; Merged.erase(std::remove(Merged.begin(), Merged.end(), nullptr), Merged.end()); } ExternCContextDecl *ASTContext::getExternCContextDecl() const { if (!ExternCContext) ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); return ExternCContext; } BuiltinTemplateDecl * ASTContext::buildBuiltinTemplateDecl(BuiltinTemplateKind BTK, const IdentifierInfo *II) const { auto *BuiltinTemplate = BuiltinTemplateDecl::Create(*this, TUDecl, II, BTK); BuiltinTemplate->setImplicit(); TUDecl->addDecl(BuiltinTemplate); return BuiltinTemplate; } BuiltinTemplateDecl * ASTContext::getMakeIntegerSeqDecl() const { if (!MakeIntegerSeqDecl) MakeIntegerSeqDecl = buildBuiltinTemplateDecl(BTK__make_integer_seq, getMakeIntegerSeqName()); return MakeIntegerSeqDecl; } BuiltinTemplateDecl * ASTContext::getTypePackElementDecl() const { if (!TypePackElementDecl) TypePackElementDecl = buildBuiltinTemplateDecl(BTK__type_pack_element, getTypePackElementName()); return TypePackElementDecl; } RecordDecl *ASTContext::buildImplicitRecord(StringRef Name, RecordDecl::TagKind TK) const { SourceLocation Loc; RecordDecl *NewDecl; if (getLangOpts().CPlusPlus) NewDecl = CXXRecordDecl::Create(*this, TK, getTranslationUnitDecl(), Loc, Loc, &Idents.get(Name)); else NewDecl = RecordDecl::Create(*this, TK, getTranslationUnitDecl(), Loc, Loc, &Idents.get(Name)); NewDecl->setImplicit(); NewDecl->addAttr(TypeVisibilityAttr::CreateImplicit( const_cast
(*this), TypeVisibilityAttr::Default)); return NewDecl; } TypedefDecl *ASTContext::buildImplicitTypedef(QualType T, StringRef Name) const { TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); TypedefDecl *NewDecl = TypedefDecl::Create( const_cast
(*this), getTranslationUnitDecl(), SourceLocation(), SourceLocation(), &Idents.get(Name), TInfo); NewDecl->setImplicit(); return NewDecl; } TypedefDecl *ASTContext::getInt128Decl() const { if (!Int128Decl) Int128Decl = buildImplicitTypedef(Int128Ty, "__int128_t"); return Int128Decl; } TypedefDecl *ASTContext::getUInt128Decl() const { if (!UInt128Decl) UInt128Decl = buildImplicitTypedef(UnsignedInt128Ty, "__uint128_t"); 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, const TargetInfo *AuxTarget) { assert((!this->Target || this->Target == &Target) && "Incorrect target reinitialization"); assert(VoidTy.isNull() && "Context reinitialized?"); this->Target = &Target; this->AuxTarget = AuxTarget; ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); AddrSpaceMapMangling = isAddrSpaceMapManglingEnabled(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, __float128 for IEEE quadruple precision InitBuiltinType(Float128Ty, BuiltinType::Float128); // GNU extension, 128-bit integers. InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); // 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); if (LangOpts.CPlusPlus && LangOpts.WChar) WideCharTy = WCharTy; else { // C99 (or C++ using -fno-wchar). WideCharTy = 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); // Placeholder type for OMP array sections. if (LangOpts.OpenMP) InitBuiltinType(OMPArraySectionTy, BuiltinType::OMPArraySection); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); Float128ComplexTy = getComplexType(Float128Ty); // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); if (LangOpts.OpenCL) { #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ InitBuiltinType(SingletonId, BuiltinType::Id); #include "clang/Basic/OpenCLImageTypes.def" InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler); InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent); InitBuiltinType(OCLClkEventTy, BuiltinType::OCLClkEvent); InitBuiltinType(OCLQueueTy, BuiltinType::OCLQueue); InitBuiltinType(OCLNDRangeTy, BuiltinType::OCLNDRange); InitBuiltinType(OCLReserveIDTy, BuiltinType::OCLReserveID); } // Builtin type for __objc_yes and __objc_no ObjCBuiltinBoolTy = (Target.useSignedCharForObjCBool() ? SignedCharTy : BoolTy); ObjCConstantStringType = QualType(); ObjCSuperType = 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. VaListTagDecl = nullptr; } 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); } } // FIXME: Remove ? MemberSpecializationInfo * ASTContext::getInstantiatedFromStaticDataMember(const VarDecl *Var) { assert(Var->isStaticDataMember() && "Not a static data member"); return getTemplateOrSpecializationInfo(Var) .dyn_cast
(); } ASTContext::TemplateOrSpecializationInfo ASTContext::getTemplateOrSpecializationInfo(const VarDecl *Var) { llvm::DenseMap
::iterator Pos = TemplateOrInstantiation.find(Var); if (Pos == TemplateOrInstantiation.end()) return TemplateOrSpecializationInfo(); 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"); setTemplateOrSpecializationInfo(Inst, new (*this) MemberSpecializationInfo( Tmpl, TSK, PointOfInstantiation)); } void ASTContext::setTemplateOrSpecializationInfo(VarDecl *Inst, TemplateOrSpecializationInfo TSI) { assert(!TemplateOrInstantiation[Inst] && "Already noted what the variable was instantiated from"); TemplateOrInstantiation[Inst] = TSI; } FunctionDecl *ASTContext::getClassScopeSpecializationPattern( const FunctionDecl *FD){ assert(FD && "Specialization is 0"); llvm::DenseMap
::const_iterator Pos = ClassScopeSpecializationPattern.find(FD); if (Pos == ClassScopeSpecializationPattern.end()) return nullptr; 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 nullptr; 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 nullptr; 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 nullptr; 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; } ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap
::const_iterator Pos = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; 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->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return nullptr; return Pos->second.end(); } unsigned ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { llvm::DenseMap
::const_iterator Pos = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; return Pos->second.size(); } ASTContext::overridden_method_range ASTContext::overridden_methods(const CXXMethodDecl *Method) const { return overridden_method_range(overridden_methods_begin(Method), overridden_methods_end(Method)); } void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden) { assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl()); OverriddenMethods[Method].push_back(Overridden); } void ASTContext::getOverriddenMethods( const NamedDecl *D, SmallVectorImpl
&Overridden) const { assert(D); if (const CXXMethodDecl *CXXMethod = dyn_cast
(D)) { Overridden.append(overridden_methods_begin(CXXMethod), overridden_methods_end(CXXMethod)); return; } const ObjCMethodDecl *Method = dyn_cast
(D); if (!Method) return; SmallVector
OverDecls; Method->getOverriddenMethods(OverDecls); Overridden.append(OverDecls.begin(), OverDecls.end()); } 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(); case BuiltinType::Float128: return Target->getFloat128Format(); } } CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) 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 (ForAlignof) T = RT->getPointeeType(); else T = getPointerType(RT->getPointeeType()); } QualType BaseT = getBaseElementType(T); if (!BaseT->isIncompleteType() && !T->isFunctionType()) { // Adjust alignments of declarations with array type by the // large-array alignment on the target. if (const ArrayType *arrayType = getAsArrayType(T)) { unsigned MinWidth = Target->getLargeArrayMinWidth(); if (!ForAlignof && MinWidth) { if (isa
(arrayType)) Align = std::max(Align, Target->getLargeArrayAlign()); else if (isa
(arrayType) && MinWidth <= getTypeSize(cast
(arrayType))) Align = std::max(Align, Target->getLargeArrayAlign()); } } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); if (const VarDecl *VD = dyn_cast
(D)) { if (VD->hasGlobalStorage() && !ForAlignof) Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); } } // 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)) { const RecordDecl *Parent = Field->getParent(); // We can only produce a sensible answer if the record is valid. if (!Parent->isInvalidDecl()) { const ASTRecordLayout &Layout = getASTRecordLayout(Parent); // 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; } /// getConstantArrayInfoInChars - Performing the computation in CharUnits /// instead of in bits prevents overflowing the uint64_t for some large arrays. std::pair
static getConstantArrayInfoInChars(const ASTContext &Context, const ConstantArrayType *CAT) { std::pair
EltInfo = Context.getTypeInfoInChars(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); assert((Size == 0 || static_cast
(EltInfo.first.getQuantity()) <= (uint64_t)(-1)/Size) && "Overflow in array type char size evaluation"); uint64_t Width = EltInfo.first.getQuantity() * Size; unsigned Align = EltInfo.second.getQuantity(); if (!Context.getTargetInfo().getCXXABI().isMicrosoft() || Context.getTargetInfo().getPointerWidth(0) == 64) Width = llvm::alignTo(Width, Align); return std::make_pair(CharUnits::fromQuantity(Width), CharUnits::fromQuantity(Align)); } std::pair
ASTContext::getTypeInfoInChars(const Type *T) const { if (const ConstantArrayType *CAT = dyn_cast
(T)) return getConstantArrayInfoInChars(*this, CAT); TypeInfo Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.Width), toCharUnitsFromBits(Info.Align)); } std::pair
ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } bool ASTContext::isAlignmentRequired(const Type *T) const { return getTypeInfo(T).AlignIsRequired; } bool ASTContext::isAlignmentRequired(QualType T) const { return isAlignmentRequired(T.getTypePtr()); } TypeInfo ASTContext::getTypeInfo(const Type *T) const { TypeInfoMap::iterator I = MemoizedTypeInfo.find(T); if (I != MemoizedTypeInfo.end()) return I->second; // This call can invalidate MemoizedTypeInfo[T], so we need a second lookup. TypeInfo TI = getTypeInfoImpl(T); MemoizedTypeInfo[T] = TI; return TI; } /// 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. TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { uint64_t Width = 0; unsigned Align = 8; bool AlignIsRequired = false; 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: #define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(Class, Base) \ case Type::Class: \ assert(!T->isDependentType() && "should not see dependent types here"); \ return getTypeInfo(cast
(T)->desugar().getTypePtr()); #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); TypeInfo EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) && "Overflow in array type bit size evaluation"); Width = EltInfo.Width * Size; Align = EltInfo.Align; if (!getTargetInfo().getCXXABI().isMicrosoft() || getTargetInfo().getPointerWidth(0) == 64) Width = llvm::alignTo(Width, Align); break; } case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast
(T); TypeInfo EltInfo = getTypeInfo(VT->getElementType()); Width = EltInfo.Width * 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::alignTo(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::Float128: Width = Target->getFloat128Width(); Align = Target->getFloat128Align(); 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; case BuiltinType::OCLSampler: // Samplers are modeled as integers. Width = Target->getIntWidth(); Align = Target->getIntAlign(); break; case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLNDRange: case BuiltinType::OCLReserveID: #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" // Currently these types are pointers to opaque types. 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::tie(Width, Align) = ABI->getMemberPointerWidthAndAlign(MPT); break; } case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. TypeInfo EltInfo = getTypeInfo(cast
(T)->getElementType()); Width = EltInfo.Width * 2; Align = EltInfo.Align; break; } case Type::ObjCObject: return getTypeInfo(cast
(T)->getBaseType().getTypePtr()); case Type::Adjusted: case Type::Decayed: return getTypeInfo(cast
(T)->getAdjustedType().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)) { const EnumDecl *ED = ET->getDecl(); TypeInfo Info = getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); if (unsigned AttrAlign = ED->getMaxAlignment()) { Info.Align = AttrAlign; Info.AlignIsRequired = true; } return Info; } const RecordType *RT = cast
(TT); const RecordDecl *RD = RT->getDecl(); const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); AlignIsRequired = RD->hasAttr
(); break; } case Type::SubstTemplateTypeParm: return getTypeInfo(cast
(T)-> getReplacementType().getTypePtr()); case Type::Auto: { const AutoType *A = cast
(T); assert(!A->getDeducedType().isNull() && "cannot request the size of an undeduced or dependent auto type"); return getTypeInfo(A->getDeducedType().getTypePtr()); } case Type::Paren: return getTypeInfo(cast
(T)->getInnerType().getTypePtr()); case Type::Typedef: { const TypedefNameDecl *Typedef = cast
(T)->getDecl(); TypeInfo 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; AlignIsRequired = true; } else { Align = Info.Align; AlignIsRequired = Info.AlignIsRequired; } Width = Info.Width; break; } case Type::Elaborated: return getTypeInfo(cast
(T)->getNamedType().getTypePtr()); case Type::Attributed: return getTypeInfo( cast
(T)->getEquivalentType().getTypePtr()); case Type::Atomic: { // Start with the base type information. TypeInfo Info = getTypeInfo(cast
(T)->getValueType()); Width = Info.Width; Align = Info.Align; // If the size of the type doesn't exceed the platform's max // atomic promotion width, make the size and alignment more // favorable to atomic operations: if (Width != 0 && Width <= Target->getMaxAtomicPromoteWidth()) { // Round the size up to a power of 2. if (!llvm::isPowerOf2_64(Width)) Width = llvm::NextPowerOf2(Width); // Set the alignment equal to the size. Align = static_cast
(Width); } } break; case Type::Pipe: { TypeInfo Info = getTypeInfo(cast
(T)->getElementType()); Width = Info.Width; Align = Info.Align; } } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); return TypeInfo(Width, Align, AlignIsRequired); } unsigned ASTContext::getOpenMPDefaultSimdAlign(QualType T) const { unsigned SimdAlign = getTargetInfo().getSimdDefaultAlign(); // Target ppc64 with QPX: simd default alignment for pointer to double is 32. if ((getTargetInfo().getTriple().getArch() == llvm::Triple::ppc64 || getTargetInfo().getTriple().getArch() == llvm::Triple::ppc64le) && getTargetInfo().getABI() == "elfv1-qpx" && T->isSpecificBuiltinType(BuiltinType::Double)) SimdAlign = 256; return SimdAlign; } /// 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 getTypeInfoInChars(T).first; } CharUnits ASTContext::getTypeSizeInChars(const Type *T) const { return getTypeInfoInChars(T).first; } /// 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 { TypeInfo TI = getTypeInfo(T); unsigned ABIAlign = TI.Align; T = T->getBaseElementTypeUnsafe(); // The preferred alignment of member pointers is that of a pointer. if (T->isMemberPointerType()) return getPreferredTypeAlign(getPointerDiffType().getTypePtr()); if (!Target->allowsLargerPreferedTypeAlignment()) return ABIAlign; // Double and long long should be naturally aligned if possible. if (const ComplexType *CT = T->getAs
()) T = CT->getElementType().getTypePtr(); if (const EnumType *ET = T->getAs
()) T = ET->getDecl()->getIntegerType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong)) // Don't increase the alignment if an alignment attribute was specified on a // typedef declaration. if (!TI.AlignIsRequired) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; } /// getTargetDefaultAlignForAttributeAligned - Return the default alignment /// for __attribute__((aligned)) on this target, to be used if no alignment /// value is specified. unsigned ASTContext::getTargetDefaultAlignForAttributeAligned() const { return getTargetInfo().getDefaultAlignForAttributeAligned(); } /// getAlignOfGlobalVar - Return the alignment in bits that should be given /// to a global variable of the specified type. unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { return std::max(getTypeAlign(T), getTargetInfo().getMinGlobalAlign()); } /// getAlignOfGlobalVarInChars - Return the alignment in characters that /// should be given to a global variable of the specified type. CharUnits ASTContext::getAlignOfGlobalVarInChars(QualType T) const { return toCharUnitsFromBits(getAlignOfGlobalVar(T)); } CharUnits ASTContext::getOffsetOfBaseWithVBPtr(const CXXRecordDecl *RD) const { CharUnits Offset = CharUnits::Zero(); const ASTRecordLayout *Layout = &getASTRecordLayout(RD); while (const CXXRecordDecl *Base = Layout->getBaseSharingVBPtr()) { Offset += Layout->getBaseClassOffset(Base); Layout = &getASTRecordLayout(Base); } return Offset; } /// 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 (const auto *I : OI->ivars()) 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 (auto *Proto : OI->all_referenced_protocols()) { CollectInheritedProtocols(Proto, Protocols); } // Categories of this Interface. for (const auto *Cat : OI->visible_categories()) CollectInheritedProtocols(Cat, Protocols); if (ObjCInterfaceDecl *SD = OI->getSuperClass()) while (SD) { CollectInheritedProtocols(SD, Protocols); SD = SD->getSuperClass(); } } else if (const ObjCCategoryDecl *OC = dyn_cast
(CDecl)) { for (auto *Proto : OC->protocols()) { CollectInheritedProtocols(Proto, Protocols); } } else if (const ObjCProtocolDecl *OP = dyn_cast
(CDecl)) { // Insert the protocol. if (!Protocols.insert( const_cast
(OP->getCanonicalDecl())).second) return; for (auto *Proto : OP->protocols()) CollectInheritedProtocols(Proto, Protocols); } } unsigned ASTContext::CountNonClassIvars(const ObjCInterfaceDecl *OI) const { unsigned count = 0; // Count ivars declared in class extension. for (const auto *Ext : OI->known_extensions()) count += Ext->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 nullptr; } /// \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 nullptr; } /// \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; } const ObjCMethodDecl * ASTContext::getObjCMethodRedeclaration(const ObjCMethodDecl *MD) const { return ObjCMethodRedecls.lookup(MD); } void ASTContext::setObjCMethodRedeclaration(const ObjCMethodDecl *MD, const ObjCMethodDecl *Redecl) { assert(!getObjCMethodRedeclaration(MD) && "MD already has a redeclaration"); ObjCMethodRedecls[MD] = Redecl; } const ObjCInterfaceDecl *ASTContext::getObjContainingInterface( const NamedDecl *ND) const { if (const ObjCInterfaceDecl *ID = dyn_cast
(ND->getDeclContext())) return ID; if (const ObjCCategoryDecl *CD = dyn_cast
(ND->getDeclContext())) return CD->getClassInterface(); if (const ObjCImplDecl *IMD = dyn_cast
(ND->getDeclContext())) return IMD->getClassInterface(); return nullptr; } /// \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) : nullptr; } /// \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, nullptr); } 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 = nullptr; 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->getReturnType(), Info); } else { const FunctionProtoType *FPT = cast
(T); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); EPI.ExtInfo = Info; Result = getFunctionType(FPT->getReturnType(), FPT->getParamTypes(), EPI); } return cast
(Result.getTypePtr()); } void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, QualType ResultType) { FD = FD->getMostRecentDecl(); while (true) { const FunctionProtoType *FPT = FD->getType()->castAs
(); FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); FD->setType(getFunctionType(ResultType, FPT->getParamTypes(), EPI)); if (FunctionDecl *Next = FD->getPreviousDecl()) FD = Next; else break; } if (ASTMutationListener *L = getASTMutationListener()) L->DeducedReturnType(FD, ResultType); } /// Get a function type and produce the equivalent function type with the /// specified exception specification. Type sugar that can be present on a /// declaration of a function with an exception specification is permitted /// and preserved. Other type sugar (for instance, typedefs) is not. static QualType getFunctionTypeWithExceptionSpec( ASTContext &Context, QualType Orig, const FunctionProtoType::ExceptionSpecInfo &ESI) { // Might have some parens. if (auto *PT = dyn_cast
(Orig)) return Context.getParenType( getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI)); // Might have a calling-convention attribute. if (auto *AT = dyn_cast
(Orig)) return Context.getAttributedType( AT->getAttrKind(), getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI), getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(), ESI)); // Anything else must be a function type. Rebuild it with the new exception // specification. const FunctionProtoType *Proto = cast
(Orig); return Context.getFunctionType( Proto->getReturnType(), Proto->getParamTypes(), Proto->getExtProtoInfo().withExceptionSpec(ESI)); } void ASTContext::adjustExceptionSpec( FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI, bool AsWritten) { // Update the type. QualType Updated = getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI); FD->setType(Updated); if (!AsWritten) return; // Update the type in the type source information too. if (TypeSourceInfo *TSInfo = FD->getTypeSourceInfo()) { // If the type and the type-as-written differ, we may need to update // the type-as-written too. if (TSInfo->getType() != FD->getType()) Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI); // FIXME: When we get proper type location information for exceptions, // we'll also have to rebuild the TypeSourceInfo. For now, we just patch // up the TypeSourceInfo; assert(TypeLoc::getFullDataSizeForType(Updated) == TypeLoc::getFullDataSizeForType(TSInfo->getType()) && "TypeLoc size mismatch from updating exception specification"); TSInfo->overrideType(Updated); } } /// 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 = nullptr; 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 && "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 = nullptr; 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 && "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); } QualType ASTContext::getAdjustedType(QualType Orig, QualType New) const { llvm::FoldingSetNodeID ID; AdjustedType::Profile(ID, Orig, New); void *InsertPos = nullptr; AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); if (AT) return QualType(AT, 0); QualType Canonical = getCanonicalType(New); // Get the new insert position for the node we care about. AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!AT && "Shouldn't be in the map!"); AT = new (*this, TypeAlignment) AdjustedType(Type::Adjusted, Orig, New, Canonical); Types.push_back(AT); AdjustedTypes.InsertNode(AT, InsertPos); return QualType(AT, 0); } QualType ASTContext::getDecayedType(QualType T) const { assert((T->isArrayType() || T->isFunctionType()) && "T does not decay"); QualType Decayed; // 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()) Decayed = 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()) Decayed = getPointerType(T); llvm::FoldingSetNodeID ID; AdjustedType::Profile(ID, T, Decayed); void *InsertPos = nullptr; AdjustedType *AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); if (AT) return QualType(AT, 0); QualType Canonical = getCanonicalType(Decayed); // Get the new insert position for the node we care about. AT = AdjustedTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!AT && "Shouldn't be in the map!"); AT = new (*this, TypeAlignment) DecayedType(T, Decayed, Canonical); Types.push_back(AT); AdjustedTypes.InsertNode(AT, InsertPos); return QualType(AT, 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 = nullptr; 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 && "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 = nullptr; 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 && "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 = nullptr; 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 && "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 = nullptr; 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 && "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 = nullptr; 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 && "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: case Type::Pipe: 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*/ nullptr, 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*/ nullptr, 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 = nullptr; 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 or the size // expression, then just use that as our result. if (QualType(canonElementType.Ty, 0) == elementType && canonTy->getSizeExpr() == numElements) 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 = nullptr; 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 = nullptr; 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 && "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 = nullptr; 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 && "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 = nullptr; 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); } /// \brief Determine whether \p T is canonical as the result type of a function. static bool isCanonicalResultType(QualType T) { return T.isCanonical() && (T.getObjCLifetime() == Qualifiers::OCL_None || T.getObjCLifetime() == Qualifiers::OCL_ExplicitNone); } /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; FunctionNoProtoType::Profile(ID, ResultTy, Info); void *InsertPos = nullptr; if (FunctionNoProtoType *FT = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(FT, 0); QualType Canonical; if (!isCanonicalResultType(ResultTy)) { Canonical = getFunctionNoProtoType(getCanonicalFunctionResultType(ResultTy), Info); // Get the new insert position for the node we care about. FunctionNoProtoType *NewIP = FunctionNoProtoTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } FunctionNoProtoType *New = new (*this, TypeAlignment) FunctionNoProtoType(ResultTy, Canonical, Info); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); } CanQualType ASTContext::getCanonicalFunctionResultType(QualType ResultType) const { CanQualType CanResultType = getCanonicalType(ResultType); // Canonical result types do not have ARC lifetime qualifiers. if (CanResultType.getQualifiers().hasObjCLifetime()) { Qualifiers Qs = CanResultType.getQualifiers(); Qs.removeObjCLifetime(); return CanQualType::CreateUnsafe( getQualifiedType(CanResultType.getUnqualifiedType(), Qs)); } return CanResultType; } QualType ASTContext::getFunctionType(QualType ResultTy, ArrayRef
ArgArray, const FunctionProtoType::ExtProtoInfo &EPI) const { size_t NumArgs = ArgArray.size(); // Unique functions, to guarantee there is only one function of a particular // structure. llvm::FoldingSetNodeID ID; FunctionProtoType::Profile(ID, ResultTy, ArgArray.begin(), NumArgs, EPI, *this); void *InsertPos = nullptr; 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.ExceptionSpec.Type == EST_None && isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn; for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) isCanonical = false; // If this type isn't canonical, get the canonical version of it. // The exception spec is not part of the canonical type. QualType Canonical; if (!isCanonical) { 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.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo(); // Adjust the canonical function result type. CanQualType CanResultTy = getCanonicalFunctionResultType(ResultTy); Canonical = getFunctionType(CanResultTy, CanonicalArgs, CanonicalEPI); // Get the new insert position for the node we care about. FunctionProtoType *NewIP = FunctionProtoTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "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 // - extended parameter information // 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.ExceptionSpec.Type == EST_Dynamic) { Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType); } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) { Size += sizeof(Expr*); } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { Size += sizeof(FunctionDecl*); } // Put the ExtParameterInfos last. If all were equal, it would make // more sense to put these before the exception specification, because // it's much easier to skip past them compared to the elaborate switch // required to skip the exception specification. However, all is not // equal; ExtParameterInfos are used to model very uncommon features, // and it's better not to burden the more common paths. if (EPI.ExtParameterInfos) { Size += NumArgs * sizeof(FunctionProtoType::ExtParameterInfo); } FunctionProtoType *FTP = (FunctionProtoType*) Allocate(Size, TypeAlignment); FunctionProtoType::ExtProtoInfo newEPI = EPI; new (FTP) FunctionProtoType(ResultTy, ArgArray, Canonical, newEPI); Types.push_back(FTP); FunctionProtoTypes.InsertNode(FTP, InsertPos); return QualType(FTP, 0); } /// Return pipe type for the specified type. QualType ASTContext::getPipeType(QualType T) const { llvm::FoldingSetNodeID ID; PipeType::Profile(ID, T); void *InsertPos = 0; if (PipeType *PT = PipeTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(PT, 0); // If the pipe element 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 = getPipeType(getCanonicalType(T)); // Get the new insert position for the node we care about. PipeType *NewIP = PipeTypes.FindNodeOrInsertPos(ID, InsertPos); assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } PipeType *New = new (*this, TypeAlignment) PipeType(T, Canonical); Types.push_back(New); PipeTypes.InsertNode(New, InsertPos); return QualType(New, 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->isFirstDecl() && "struct/union has previous declaration"); assert(!NeedsInjectedClassNameType(Record)); return getRecordType(Record); } else if (const EnumDecl *Enum = dyn_cast
(Decl)) { assert(Enum->isFirstDecl() && "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 = nullptr; 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 = nullptr; 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 (const auto &P : ArgPack.pack_elements()) { 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 = nullptr; 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 = nullptr; 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 = DI->getTypeLoc().castAs
(); 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!"); SmallVector
ArgVec; ArgVec.reserve(Args.size()); for (const TemplateArgumentLoc &Arg : Args.arguments()) ArgVec.push_back(Arg.getArgument()); return getTemplateSpecializationType(Template, ArgVec, Underlying); } #ifndef NDEBUG static bool hasAnyPackExpansions(ArrayRef
Args) { for (const TemplateArgument &Arg : Args) if (Arg.isPackExpansion()) return true; return true; } #endif QualType ASTContext::getTemplateSpecializationType(TemplateName Template, ArrayRef
Args, 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)) && "Caller must compute aliased type"); IsTypeAlias = false; CanonType = getCanonicalTemplateSpecializationType(Template, Args); } // 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) * Args.size() + (IsTypeAlias? sizeof(QualType) : 0), TypeAlignment); TemplateSpecializationType *Spec = new (Mem) TemplateSpecializationType(Template, Args, CanonType, IsTypeAlias ? Underlying : QualType()); Types.push_back(Spec); return QualType(Spec, 0); } QualType ASTContext::getCanonicalTemplateSpecializationType( TemplateName Template, ArrayRef
Args) 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; unsigned NumArgs = Args.size(); CanonArgs.reserve(NumArgs); for (const TemplateArgument &Arg : Args) CanonArgs.push_back(getCanonicalTemplateArgument(Arg)); // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; TemplateSpecializationType::Profile(ID, CanonTemplate, CanonArgs, *this); void *InsertPos = nullptr; 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, 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 = nullptr; 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, TypeAlignment) 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 = nullptr; 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, TypeAlignment) 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 { 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 = nullptr; DependentNameType *T = DependentNameTypes.FindNodeOrInsertPos(ID, InsertPos); if (T) return QualType(T, 0); T = new (*this, TypeAlignment) 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); } QualType ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, ArrayRef
Args) const { assert((!NNS || NNS->isDependent()) && "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS, Name, Args); void *InsertPos = nullptr; 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; unsigned NumArgs = Args.size(); 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, CanonArgs); // 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, Args, Canon); Types.push_back(T); DependentTemplateSpecializationTypes.InsertNode(T, InsertPos); return QualType(T, 0); } QualType ASTContext::getPackExpansionType(QualType Pattern, Optional
NumExpansions) { llvm::FoldingSetNodeID ID; PackExpansionType::Profile(ID, Pattern, NumExpansions); assert(Pattern->containsUnexpandedParameterPack() && "Pack expansions must expand one or more parameter packs"); void *InsertPos = nullptr; 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(Canon, 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, TypeAlignment) PackExpansionType(Pattern, Canon, NumExpansions); Types.push_back(T); PackExpansionTypes.InsertNode(T, InsertPos); return QualType(T, 0); } /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static int CmpProtocolNames(ObjCProtocolDecl *const *LHS, ObjCProtocolDecl *const *RHS) { return DeclarationName::compare((*LHS)->getDeclName(), (*RHS)->getDeclName()); } static bool areSortedAndUniqued(ArrayRef
Protocols) { if (Protocols.empty()) return true; if (Protocols[0]->getCanonicalDecl() != Protocols[0]) return false; for (unsigned i = 1; i != Protocols.size(); ++i) if (CmpProtocolNames(&Protocols[i - 1], &Protocols[i]) >= 0 || Protocols[i]->getCanonicalDecl() != Protocols[i]) return false; return true; } static void SortAndUniqueProtocols(SmallVectorImpl
&Protocols) { // Sort protocols, keyed by name. llvm::array_pod_sort(Protocols.begin(), Protocols.end(), CmpProtocolNames); // Canonicalize. for (ObjCProtocolDecl *&P : Protocols) P = P->getCanonicalDecl(); // Remove duplicates. auto ProtocolsEnd = std::unique(Protocols.begin(), Protocols.end()); Protocols.erase(ProtocolsEnd, Protocols.end()); } QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { return getObjCObjectType(BaseType, { }, llvm::makeArrayRef(Protocols, NumProtocols), /*isKindOf=*/false); } QualType ASTContext::getObjCObjectType( QualType baseType, ArrayRef
typeArgs, ArrayRef
protocols, bool isKindOf) const { // If the base type is an interface and there aren't any protocols or // type arguments to add, then the interface type will do just fine. if (typeArgs.empty() && protocols.empty() && !isKindOf && isa
(baseType)) return baseType; // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; ObjCObjectTypeImpl::Profile(ID, baseType, typeArgs, protocols, isKindOf); void *InsertPos = nullptr; if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); // Determine the type arguments to be used for canonicalization, // which may be explicitly specified here or written on the base // type. ArrayRef
effectiveTypeArgs = typeArgs; if (effectiveTypeArgs.empty()) { if (auto baseObject = baseType->getAs
()) effectiveTypeArgs = baseObject->getTypeArgs(); } // Build the canonical type, which has the canonical base type and a // sorted-and-uniqued list of protocols and the type arguments // canonicalized. QualType canonical; bool typeArgsAreCanonical = std::all_of(effectiveTypeArgs.begin(), effectiveTypeArgs.end(), [&](QualType type) { return type.isCanonical(); }); bool protocolsSorted = areSortedAndUniqued(protocols); if (!typeArgsAreCanonical || !protocolsSorted || !baseType.isCanonical()) { // Determine the canonical type arguments. ArrayRef
canonTypeArgs; SmallVector
canonTypeArgsVec; if (!typeArgsAreCanonical) { canonTypeArgsVec.reserve(effectiveTypeArgs.size()); for (auto typeArg : effectiveTypeArgs) canonTypeArgsVec.push_back(getCanonicalType(typeArg)); canonTypeArgs = canonTypeArgsVec; } else { canonTypeArgs = effectiveTypeArgs; } ArrayRef
canonProtocols; SmallVector
canonProtocolsVec; if (!protocolsSorted) { canonProtocolsVec.append(protocols.begin(), protocols.end()); SortAndUniqueProtocols(canonProtocolsVec); canonProtocols = canonProtocolsVec; } else { canonProtocols = protocols; } canonical = getObjCObjectType(getCanonicalType(baseType), canonTypeArgs, canonProtocols, isKindOf); // Regenerate InsertPos. ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } unsigned size = sizeof(ObjCObjectTypeImpl); size += typeArgs.size() * sizeof(QualType); size += protocols.size() * sizeof(ObjCProtocolDecl *); void *mem = Allocate(size, TypeAlignment); ObjCObjectTypeImpl *T = new (mem) ObjCObjectTypeImpl(canonical, baseType, typeArgs, protocols, isKindOf); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); return QualType(T, 0); } /// ObjCObjectAdoptsQTypeProtocols - Checks that protocols in IC's /// protocol list adopt all protocols in QT's qualified-id protocol /// list. bool ASTContext::ObjCObjectAdoptsQTypeProtocols(QualType QT, ObjCInterfaceDecl *IC) { if (!QT->isObjCQualifiedIdType()) return false; if (const ObjCObjectPointerType *OPT = QT->getAs
()) { // If both the right and left sides have qualifiers. for (auto *Proto : OPT->quals()) { if (!IC->ClassImplementsProtocol(Proto, false)) return false; } return true; } return false; } /// QIdProtocolsAdoptObjCObjectProtocols - Checks that protocols in /// QT's qualified-id protocol list adopt all protocols in IDecl's list /// of protocols. bool ASTContext::QIdProtocolsAdoptObjCObjectProtocols(QualType QT, ObjCInterfaceDecl *IDecl) { if (!QT->isObjCQualifiedIdType()) return false; const ObjCObjectPointerType *OPT = QT->getAs
(); if (!OPT) return false; if (!IDecl->hasDefinition()) return false; llvm::SmallPtrSet
InheritedProtocols; CollectInheritedProtocols(IDecl, InheritedProtocols); if (InheritedProtocols.empty()) return false; // Check that if every protocol in list of id
conforms to a protcol // of IDecl's, then bridge casting is ok. bool Conforms = false; for (auto *Proto : OPT->quals()) { Conforms = false; for (auto *PI : InheritedProtocols) { if (ProtocolCompatibleWithProtocol(Proto, PI)) { Conforms = true; break; } } if (!Conforms) break; } if (Conforms) return true; for (auto *PI : InheritedProtocols) { // If both the right and left sides have qualifiers. bool Adopts = false; for (auto *Proto : OPT->quals()) { // return 'true' if 'PI' is in the inheritance hierarchy of Proto if ((Adopts = ProtocolCompatibleWithProtocol(PI, Proto))) break; } if (!Adopts) return false; } return true; } /// 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 = nullptr; 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 = nullptr; 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 nodes. 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 affect the type checker, since it operates /// on canonical types (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); } /// \brief Unlike many "get
" functions, we don't unique DecltypeType /// nodes. This would never be helpful, since each such type has its own /// expression, and would not give a significant memory saving, since there /// is an Expr tree under each such type. QualType ASTContext::getDecltypeType(Expr *e, QualType UnderlyingType) const { DecltypeType *dt; // C++11 [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 = nullptr; DependentDecltypeType *Canon = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos); if (!Canon) { // Build a new, canonical typeof(expr) type. Canon = new (*this, TypeAlignment) DependentDecltypeType(*this, e); DependentDecltypeTypes.InsertNode(Canon, InsertPos); } dt = new (*this, TypeAlignment) DecltypeType(e, UnderlyingType, QualType((DecltypeType *)Canon, 0)); } 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 *ut = nullptr; if (BaseType->isDependentType()) { // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; DependentUnaryTransformType::Profile(ID, getCanonicalType(BaseType), Kind); void *InsertPos = nullptr; DependentUnaryTransformType *Canon = DependentUnaryTransformTypes.FindNodeOrInsertPos(ID, InsertPos); if (!Canon) { // Build a new, canonical __underlying_type(type) type. Canon = new (*this, TypeAlignment) DependentUnaryTransformType(*this, getCanonicalType(BaseType), Kind); DependentUnaryTransformTypes.InsertNode(Canon, InsertPos); } ut = new (*this, TypeAlignment) UnaryTransformType (BaseType, QualType(), Kind, QualType(Canon, 0)); } else { QualType CanonType = getCanonicalType(UnderlyingType); ut = new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType, Kind, CanonType); } Types.push_back(ut); return QualType(ut, 0); } /// getAutoType - Return the uniqued reference to the 'auto' type which has been /// deduced to the given type, or to the canonical undeduced 'auto' type, or the /// canonical deduced-but-dependent 'auto' type. QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent) const { if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; AutoType::Profile(ID, DeducedType, Keyword, IsDependent); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, Keyword, IsDependent); 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 = nullptr; 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 && "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 = QualType( new (*this, TypeAlignment) AutoType(QualType(), AutoTypeKeyword::Auto, /*dependent*/false), 0); 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; } QualType ASTContext::getIntPtrType() const { return getFromTargetType(Target->getIntPtrType()); } QualType ASTContext::getUIntPtrType() const { return getCorrespondingUnsignedType(getIntPtrType()); } /// 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)); } /// \brief Return the unique type for "pid_t" defined in ///
. We need this to compute the correct type for vfork(). QualType ASTContext::getProcessIDType() const { return getFromTargetType(Target->getProcessIDType()); } //===----------------------------------------------------------------------===// // 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