HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Lollipop
|
5.0.1_r1
下载
查看原文件
收藏
根目录
external
clang
lib
AST
ASTContext.cpp
//===--- ASTContext.cpp - Context to hold long-lived AST nodes ------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the ASTContext interface. // //===----------------------------------------------------------------------===// #include "clang/AST/ASTContext.h" #include "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/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 }; 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; } } // unnamed namespace const RawComment *ASTContext::getRawCommentForAnyRedecl( const Decl *D, const Decl **OriginalDecl) const { D = adjustDeclToTemplate(D); // Check whether we have cached a comment for this declaration already. { llvm::DenseMap
::iterator Pos = RedeclComments.find(D); if (Pos != RedeclComments.end()) { const RawCommentAndCacheFlags &Raw = Pos->second; if (Raw.getKind() != RawCommentAndCacheFlags::NoCommentInDecl) { if (OriginalDecl) *OriginalDecl = Raw.getOriginalDecl(); return Raw.getRaw(); } } } // Search for comments attached to declarations in the redeclaration chain. const RawComment *RC = 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) { Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromDecl); } else Raw.setKind(RawCommentAndCacheFlags::NoCommentInDecl); Raw.setOriginalDecl(I); RedeclComments[I] = Raw; if (RC) break; } } // If we found a comment, it should be a documentation comment. assert(!RC || RC->isDocumentation()); if (OriginalDecl) *OriginalDecl = OriginalDeclForRC; // Update cache for every declaration in the redeclaration chain. RawCommentAndCacheFlags Raw; Raw.setRaw(RC); Raw.setKind(RawCommentAndCacheFlags::FromRedecl); Raw.setOriginalDecl(OriginalDeclForRC); for (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.data(), ExpandedTypes.size(), ExpandedTInfos.data()); } 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.data(), CanonParams.size(), 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::GenericAArch64: case TargetCXXABI::GenericItanium: 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, // cuda_device 5, // cuda_constant 6 // 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), Float128StubDecl(nullptr), BuiltinVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr), CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr), FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), NullTypeSourceInfo(QualType()), FirstLocalImport(), LastLocalImport(), SourceMgr(SM), LangOpts(LOpts), AddrSpaceMap(nullptr), Target(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 (DeallocationMap::const_iterator I = Deallocations.begin(), E = Deallocations.end(); I != E; ++I) for (unsigned J = 0, N = I->second.size(); J != N; ++J) (I->first)((I->second)[J]); // 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(); llvm::DeleteContainerSeconds(MangleNumberingContexts); } void ASTContext::ReleaseParentMapEntries() { if (!AllParents) return; for (const auto &Entry : *AllParents) { if (Entry.second.is
()) { delete Entry.second.get
(); } else { assert(Entry.second.is
()); delete Entry.second.get
(); } } } void ASTContext::AddDeallocation(void (*Callback)(void*), void *Data) { Deallocations[Callback].push_back(Data); } void ASTContext::setExternalSource(IntrusiveRefCntPtr
Source) { ExternalSource = 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(); } 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(); 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; } TypeDecl *ASTContext::getFloat128StubType() const { assert(LangOpts.CPlusPlus && "should only be called for c++"); if (!Float128StubDecl) Float128StubDecl = buildImplicitRecord("__float128"); return Float128StubDecl; } void ASTContext::InitBuiltinType(CanQualType &R, BuiltinType::Kind K) { BuiltinType *Ty = new (*this, TypeAlignment) BuiltinType(K); R = CanQualType::CreateUnsafe(QualType(Ty, 0)); Types.push_back(Ty); } void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { assert((!this->Target || this->Target == &Target) && "Incorrect target reinitialization"); assert(VoidTy.isNull() && "Context reinitialized?"); this->Target = &Target; ABI.reset(createCXXABI(Target)); AddrSpaceMap = getAddressSpaceMap(Target, LangOpts); 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, 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); // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); LongDoubleComplexTy = getComplexType(LongDoubleTy); // Builtin types for 'id', 'Class', and 'SEL'. InitBuiltinType(ObjCBuiltinIdTy, BuiltinType::ObjCId); InitBuiltinType(ObjCBuiltinClassTy, BuiltinType::ObjCClass); InitBuiltinType(ObjCBuiltinSelTy, BuiltinType::ObjCSel); if (LangOpts.OpenCL) { InitBuiltinType(OCLImage1dTy, BuiltinType::OCLImage1d); InitBuiltinType(OCLImage1dArrayTy, BuiltinType::OCLImage1dArray); InitBuiltinType(OCLImage1dBufferTy, BuiltinType::OCLImage1dBuffer); InitBuiltinType(OCLImage2dTy, BuiltinType::OCLImage2d); InitBuiltinType(OCLImage2dArrayTy, BuiltinType::OCLImage2dArray); InitBuiltinType(OCLImage3dTy, BuiltinType::OCLImage3d); InitBuiltinType(OCLSamplerTy, BuiltinType::OCLSampler); InitBuiltinType(OCLEventTy, BuiltinType::OCLEvent); } // 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. VaListTagTy = QualType(); } DiagnosticsEngine &ASTContext::getDiagnostics() const { return SourceMgr.getDiagnostics(); } AttrVec& ASTContext::getDeclAttrs(const Decl *D) { AttrVec *&Result = DeclAttrs[D]; if (!Result) { void *Mem = Allocate(sizeof(AttrVec)); Result = new (Mem) AttrVec; } return *Result; } /// \brief Erase the attributes corresponding to the given declaration. void ASTContext::eraseDeclAttrs(const Decl *D) { llvm::DenseMap
::iterator Pos = DeclAttrs.find(D); if (Pos != DeclAttrs.end()) { Pos->second->~AttrVec(); DeclAttrs.erase(Pos); } } // 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(); } 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(); } } 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()) 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::RoundUpToAlignment(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); std::pair
Info = getTypeInfo(T); return std::make_pair(toCharUnitsFromBits(Info.first), toCharUnitsFromBits(Info.second)); } std::pair
ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } std::pair
ASTContext::getTypeInfo(const Type *T) const { TypeInfoMap::iterator it = MemoizedTypeInfo.find(T); if (it != MemoizedTypeInfo.end()) return it->second; std::pair
Info = getTypeInfoImpl(T); MemoizedTypeInfo.insert(std::make_pair(T, Info)); return Info; } /// getTypeInfoImpl - Return the size of the specified type, in bits. This /// method does not work on incomplete types. /// /// FIXME: Pointers into different addr spaces could have different sizes and /// alignment requirements: getPointerInfo should take an AddrSpace, this /// should take a QualType, &c. std::pair
ASTContext::getTypeInfoImpl(const Type *T) const { uint64_t Width=0; unsigned Align=8; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define NON_CANONICAL_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) case Type::Class: #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); std::pair
EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) && "Overflow in array type bit size evaluation"); Width = EltInfo.first*Size; Align = EltInfo.second; if (!getTargetInfo().getCXXABI().isMicrosoft() || getTargetInfo().getPointerWidth(0) == 64) Width = llvm::RoundUpToAlignment(Width, Align); break; } case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast
(T); std::pair
EltInfo = getTypeInfo(VT->getElementType()); Width = EltInfo.first*VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. if (Align & (Align-1)) { Align = llvm::NextPowerOf2(Align); Width = llvm::RoundUpToAlignment(Width, Align); } // Adjust the alignment based on the target max. uint64_t TargetVectorAlign = Target->getMaxVectorAlign(); if (TargetVectorAlign && TargetVectorAlign < Align) Align = TargetVectorAlign; break; } case Type::Builtin: switch (cast
(T)->getKind()) { default: llvm_unreachable("Unknown builtin type!"); case BuiltinType::Void: // GCC extension: alignof(void) = 8 bits. Width = 0; Align = 8; break; case BuiltinType::Bool: Width = Target->getBoolWidth(); Align = Target->getBoolAlign(); break; case BuiltinType::Char_S: case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::SChar: Width = Target->getCharWidth(); Align = Target->getCharAlign(); break; case BuiltinType::WChar_S: case BuiltinType::WChar_U: Width = Target->getWCharWidth(); Align = Target->getWCharAlign(); break; case BuiltinType::Char16: Width = Target->getChar16Width(); Align = Target->getChar16Align(); break; case BuiltinType::Char32: Width = Target->getChar32Width(); Align = Target->getChar32Align(); break; case BuiltinType::UShort: case BuiltinType::Short: Width = Target->getShortWidth(); Align = Target->getShortAlign(); break; case BuiltinType::UInt: case BuiltinType::Int: Width = Target->getIntWidth(); Align = Target->getIntAlign(); break; case BuiltinType::ULong: case BuiltinType::Long: Width = Target->getLongWidth(); Align = Target->getLongAlign(); break; case BuiltinType::ULongLong: case BuiltinType::LongLong: Width = Target->getLongLongWidth(); Align = Target->getLongLongAlign(); break; case BuiltinType::Int128: case BuiltinType::UInt128: Width = 128; Align = 128; // int128_t is 128-bit aligned on all targets. break; case BuiltinType::Half: Width = Target->getHalfWidth(); Align = Target->getHalfAlign(); break; case BuiltinType::Float: Width = Target->getFloatWidth(); Align = Target->getFloatAlign(); break; case BuiltinType::Double: Width = Target->getDoubleWidth(); Align = Target->getDoubleAlign(); break; case BuiltinType::LongDouble: Width = Target->getLongDoubleWidth(); Align = Target->getLongDoubleAlign(); break; case BuiltinType::NullPtr: Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) Align = Target->getPointerAlign(0); // == sizeof(void*) break; case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: Width = Target->getPointerWidth(0); Align = Target->getPointerAlign(0); break; case BuiltinType::OCLSampler: // Samplers are modeled as integers. Width = Target->getIntWidth(); Align = Target->getIntAlign(); break; case BuiltinType::OCLEvent: case BuiltinType::OCLImage1d: case BuiltinType::OCLImage1dArray: case BuiltinType::OCLImage1dBuffer: case BuiltinType::OCLImage2d: case BuiltinType::OCLImage2dArray: case BuiltinType::OCLImage3d: // 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. std::pair
EltInfo = getTypeInfo(cast
(T)->getElementType()); Width = EltInfo.first*2; Align = EltInfo.second; break; } case Type::ObjCObject: return getTypeInfo(cast
(T)->getBaseType().getTypePtr()); case Type::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)) return getTypeInfo(ET->getDecl()->getIntegerType()); const RecordType *RT = cast
(TT); const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); break; } case Type::SubstTemplateTypeParm: return getTypeInfo(cast
(T)-> getReplacementType().getTypePtr()); case Type::Auto: { const AutoType *A = cast
(T); assert(!A->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(); std::pair
Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. if (unsigned AttrAlign = Typedef->getMaxAlignment()) Align = AttrAlign; else Align = Info.second; Width = Info.first; break; } case Type::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. std::pair
Info = getTypeInfo(cast
(T)->getValueType()); Width = Info.first; Align = Info.second; // 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); } } } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); return std::make_pair(Width, Align); } /// toCharUnitsFromBits - Convert a size in bits to a size in characters. CharUnits ASTContext::toCharUnitsFromBits(int64_t BitSize) const { return CharUnits::fromQuantity(BitSize / getCharWidth()); } /// toBits - Convert a size in characters to a size in characters. int64_t ASTContext::toBits(CharUnits CharSize) const { return CharSize.getQuantity() * getCharWidth(); } /// getTypeSizeInChars - Return the size of the specified type, in characters. /// This method does not work on incomplete types. CharUnits ASTContext::getTypeSizeInChars(QualType T) const { return 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 { unsigned ABIAlign = getTypeAlign(T); if (Target->getTriple().getArch() == llvm::Triple::xcore) return ABIAlign; // Never overalign on XCore. const TypedefType *TT = T->getAs
(); // Double and long long should be naturally aligned if possible. T = T->getBaseElementTypeUnsafe(); if (const ComplexType *CT = T->getAs
()) T = CT->getElementType().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 (!TT || !TT->getDecl()->getMaxAlignment()) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; } /// 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)); } /// 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()) { Protocols.insert(Proto->getCanonicalDecl()); for (auto *P : Proto->protocols()) { Protocols.insert(P->getCanonicalDecl()); CollectInheritedProtocols(P, 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()) { Protocols.insert(Proto->getCanonicalDecl()); for (const auto *P : Proto->protocols()) CollectInheritedProtocols(P, Protocols); } } else if (const ObjCProtocolDecl *OP = dyn_cast
(CDecl)) { for (auto *Proto : OP->protocols()) { Protocols.insert(Proto->getCanonicalDecl()); for (const auto *P : Proto->protocols()) CollectInheritedProtocols(P, 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 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); } /// 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: 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, // then just use that as our result. if (QualType(canonElementType.Ty, 0) == elementType) return canon; // Otherwise, we need to build a type which follows the spelling // of the element type. DependentSizedArrayType *sugaredType = new (*this, TypeAlignment) DependentSizedArrayType(*this, elementType, canon, numElements, ASM, elementTypeQuals, brackets); Types.push_back(sugaredType); return QualType(sugaredType, 0); } QualType ASTContext::getIncompleteArrayType(QualType elementType, ArrayType::ArraySizeModifier ASM, unsigned elementTypeQuals) const { llvm::FoldingSetNodeID ID; IncompleteArrayType::Profile(ID, elementType, ASM, elementTypeQuals); void *insertPos = 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); } /// getFunctionNoProtoType - Return a K&R style C function type like 'int()'. /// QualType ASTContext::getFunctionNoProtoType(QualType ResultTy, const FunctionType::ExtInfo &Info) const { const CallingConv CallConv = Info.getCC(); // 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 (!ResultTy.isCanonical()) { Canonical = getFunctionNoProtoType(getCanonicalType(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; } FunctionProtoType::ExtInfo newInfo = Info.withCallingConv(CallConv); FunctionNoProtoType *New = new (*this, TypeAlignment) FunctionNoProtoType(ResultTy, Canonical, newInfo); Types.push_back(New); FunctionNoProtoTypes.InsertNode(New, InsertPos); return QualType(New, 0); } /// \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); } 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.ExceptionSpecType == 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.ExceptionSpecType = EST_None; CanonicalEPI.NumExceptions = 0; // Result types do not have ARC lifetime qualifiers. QualType CanResultTy = getCanonicalType(ResultTy); if (ResultTy.getQualifiers().hasObjCLifetime()) { Qualifiers Qs = CanResultTy.getQualifiers(); Qs.removeObjCLifetime(); CanResultTy = getQualifiedType(CanResultTy.getUnqualifiedType(), Qs); } 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 // - consumed-arguments flags // Instead of the exception types, there could be a noexcept // expression, or information used to resolve the exception // specification. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); if (EPI.ExceptionSpecType == EST_Dynamic) { Size += EPI.NumExceptions * sizeof(QualType); } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { Size += sizeof(Expr*); } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); } else if (EPI.ExceptionSpecType == EST_Unevaluated) { Size += sizeof(FunctionDecl*); } if (EPI.ConsumedParameters) Size += NumArgs * sizeof(bool); 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); } #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 (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), PEnd = ArgPack.pack_end(); P != PEnd; ++P) { assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type"); assert(P->getAsType().isCanonical() && "Pack contains non-canonical type"); } #endif llvm::FoldingSetNodeID ID; SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); void *InsertPos = 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!"); unsigned NumArgs = Args.size(); SmallVector
ArgVec; ArgVec.reserve(NumArgs); for (unsigned i = 0; i != NumArgs; ++i) ArgVec.push_back(Args[i].getArgument()); return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, Underlying); } #ifndef NDEBUG static bool hasAnyPackExpansions(const TemplateArgument *Args, unsigned NumArgs) { for (unsigned I = 0; I != NumArgs; ++I) if (Args[I].isPackExpansion()) return true; return true; } #endif QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); bool IsTypeAlias = Template.getAsTemplateDecl() && isa
(Template.getAsTemplateDecl()); QualType CanonType; if (!Underlying.isNull()) CanonType = getCanonicalType(Underlying); else { // We can get here with an alias template when the specialization contains // a pack expansion that does not match up with a parameter pack. assert((!IsTypeAlias || hasAnyPackExpansions(Args, NumArgs)) && "Caller must compute aliased type"); IsTypeAlias = false; CanonType = getCanonicalTemplateSpecializationType(Template, Args, NumArgs); } // Allocate the (non-canonical) template specialization type, but don't // try to unique it: these types typically have location information that // we don't unique and don't want to lose. void *Mem = Allocate(sizeof(TemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs + (IsTypeAlias? sizeof(QualType) : 0), TypeAlignment); TemplateSpecializationType *Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, CanonType, IsTypeAlias ? Underlying : QualType()); Types.push_back(Spec); return QualType(Spec, 0); } QualType ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); // Build the canonical template specialization type. TemplateName CanonTemplate = getCanonicalTemplateName(Template); SmallVector
CanonArgs; CanonArgs.reserve(NumArgs); for (unsigned I = 0; I != NumArgs; ++I) CanonArgs.push_back(getCanonicalTemplateArgument(Args[I])); // Determine whether this canonical template specialization type already // exists. llvm::FoldingSetNodeID ID; TemplateSpecializationType::Profile(ID, CanonTemplate, CanonArgs.data(), NumArgs, *this); void *InsertPos = 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.data(), NumArgs, QualType(), QualType()); Types.push_back(Spec); TemplateSpecializationTypes.InsertNode(Spec, InsertPos); } assert(Spec->isDependentType() && "Non-dependent template-id type must have a canonical type"); return QualType(Spec, 0); } QualType ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, QualType NamedType) const { llvm::FoldingSetNodeID ID; ElaboratedType::Profile(ID, Keyword, NNS, NamedType); void *InsertPos = 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) 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) 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) DependentNameType(Keyword, NNS, Name, Canon); Types.push_back(T); DependentNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); } QualType ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, const TemplateArgumentListInfo &Args) const { // TODO: avoid this copy SmallVector
ArgCopy; for (unsigned I = 0, E = Args.size(); I != E; ++I) ArgCopy.push_back(Args[I].getArgument()); return getDependentTemplateSpecializationType(Keyword, NNS, Name, ArgCopy.size(), ArgCopy.data()); } QualType ASTContext::getDependentTemplateSpecializationType( ElaboratedTypeKeyword Keyword, NestedNameSpecifier *NNS, const IdentifierInfo *Name, unsigned NumArgs, const TemplateArgument *Args) const { assert((!NNS || NNS->isDependent()) && "nested-name-specifier must be dependent"); llvm::FoldingSetNodeID ID; DependentTemplateSpecializationType::Profile(ID, *this, Keyword, NNS, Name, NumArgs, Args); void *InsertPos = 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; SmallVector
CanonArgs(NumArgs); for (unsigned I = 0; I != NumArgs; ++I) { CanonArgs[I] = getCanonicalTemplateArgument(Args[I]); if (!CanonArgs[I].structurallyEquals(Args[I])) AnyNonCanonArgs = true; } QualType Canon; if (AnyNonCanonArgs || CanonNNS != NNS || CanonKeyword != Keyword) { Canon = getDependentTemplateSpecializationType(CanonKeyword, CanonNNS, Name, NumArgs, CanonArgs.data()); // Find the insert position again. DependentTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); } void *Mem = Allocate((sizeof(DependentTemplateSpecializationType) + sizeof(TemplateArgument) * NumArgs), TypeAlignment); T = new (Mem) DependentTemplateSpecializationType(Keyword, NNS, Name, NumArgs, Args, Canon); Types.push_back(T); DependentTemplateSpecializationTypes.InsertNode(T, InsertPos); return QualType(T, 0); } QualType ASTContext::getPackExpansionType(QualType Pattern, 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) PackExpansionType(Pattern, Canon, NumExpansions); Types.push_back(T); PackExpansionTypes.InsertNode(T, InsertPos); return QualType(T, 0); } /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, const ObjCProtocolDecl *RHS) { return LHS->getDeclName() < RHS->getDeclName(); } static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) { if (NumProtocols == 0) return true; if (Protocols[0]->getCanonicalDecl() != Protocols[0]) return false; for (unsigned i = 1; i != NumProtocols; ++i) if (!CmpProtocolNames(Protocols[i-1], Protocols[i]) || Protocols[i]->getCanonicalDecl() != Protocols[i]) return false; return true; } static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, unsigned &NumProtocols) { ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; // Sort protocols, keyed by name. std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames); // Canonicalize. for (unsigned I = 0, N = NumProtocols; I != N; ++I) Protocols[I] = Protocols[I]->getCanonicalDecl(); // Remove duplicates. ProtocolsEnd = std::unique(Protocols, ProtocolsEnd); NumProtocols = ProtocolsEnd-Protocols; } QualType ASTContext::getObjCObjectType(QualType BaseType, ObjCProtocolDecl * const *Protocols, unsigned NumProtocols) const { // If the base type is an interface and there aren't any protocols // to add, then the interface type will do just fine. if (!NumProtocols && isa
(BaseType)) return BaseType; // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; ObjCObjectTypeImpl::Profile(ID, BaseType, Protocols, NumProtocols); void *InsertPos = nullptr; if (ObjCObjectType *QT = ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(QT, 0); // Build the canonical type, which has the canonical base type and // a sorted-and-uniqued list of protocols. QualType Canonical; bool ProtocolsSorted = areSortedAndUniqued(Protocols, NumProtocols); if (!ProtocolsSorted || !BaseType.isCanonical()) { if (!ProtocolsSorted) { SmallVector
Sorted(Protocols, Protocols + NumProtocols); unsigned UniqueCount = NumProtocols; SortAndUniqueProtocols(&Sorted[0], UniqueCount); Canonical = getObjCObjectType(getCanonicalType(BaseType), &Sorted[0], UniqueCount); } else { Canonical = getObjCObjectType(getCanonicalType(BaseType), Protocols, NumProtocols); } // Regenerate InsertPos. ObjCObjectTypes.FindNodeOrInsertPos(ID, InsertPos); } unsigned Size = sizeof(ObjCObjectTypeImpl); Size += NumProtocols * sizeof(ObjCProtocolDecl *); void *Mem = Allocate(Size, TypeAlignment); ObjCObjectTypeImpl *T = new (Mem) ObjCObjectTypeImpl(Canonical, BaseType, Protocols, NumProtocols); Types.push_back(T); ObjCObjectTypes.InsertNode(T, InsertPos); return QualType(T, 0); } /// 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 *Ty = new (*this, TypeAlignment) UnaryTransformType (BaseType, UnderlyingType, Kind, UnderlyingType->isDependentType() ? QualType() : getCanonicalType(UnderlyingType)); Types.push_back(Ty); return QualType(Ty, 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, bool IsDecltypeAuto, bool IsDependent) const { if (DeducedType.isNull() && !IsDecltypeAuto && !IsDependent) return getAutoDeductType(); // Look in the folding set for an existing type. void *InsertPos = nullptr; llvm::FoldingSetNodeID ID; AutoType::Profile(ID, DeducedType, IsDecltypeAuto, IsDependent); if (AutoType *AT = AutoTypes.FindNodeOrInsertPos(ID, InsertPos)) return QualType(AT, 0); AutoType *AT = new (*this, TypeAlignment) AutoType(DeducedType, IsDecltypeAuto, 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(), /*decltype(auto)*/false, /*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
(); if (T1OPType && T2OPType) { T1 = T1OPType->getPointeeType(); T2 = T2OPType->getPointeeType(); return true; } } // FIXME: Block pointers, too? return false; } DeclarationNameInfo ASTContext::getNameForTemplate(TemplateName Name, SourceLocation NameLoc) const { switch (Name.getKind()) { case TemplateName::QualifiedTemplate: case TemplateName::Template: // DNInfo work in progress: CHECKME: what about DNLoc? return DeclarationNameInfo(Name.getAsTemplateDecl()->getDeclName(), NameLoc); case TemplateName::OverloadedTemplate: { OverloadedTemplateStorage *Storage = Name.getAsOverloadedTemplate(); // DNInfo work in progress: CHECKME: what about DNLoc? return DeclarationNameInfo((*Storage->begin())->getDeclName(), NameLoc); } case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); DeclarationName DName; if (DTN->isIdentifier()) { DName = DeclarationNames.getIdentifier(DTN->getIdentifier()); return DeclarationNameInfo(DName, NameLoc); } else { DName = DeclarationNames.getCXXOperatorName(DTN->getOperator()); // DNInfo work in progress: FIXME: source locations? DeclarationNameLoc DNLoc; DNLoc.CXXOperatorName.BeginOpNameLoc = SourceLocation().getRawEncoding(); DNLoc.CXXOperatorName.EndOpNameLoc = SourceLocation().getRawEncoding(); return DeclarationNameInfo(DName, NameLoc, DNLoc); } } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = Name.getAsSubstTemplateTemplateParm(); return DeclarationNameInfo(subst->getParameter()->getDeclName(), NameLoc); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *subst = Name.getAsSubstTemplateTemplateParmPack(); return DeclarationNameInfo(subst->getParameterPack()->getDeclName(), NameLoc); } } llvm_unreachable("bad template name kind!"); } TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) const { switch (Name.getKind()) { case TemplateName::QualifiedTemplate: case TemplateName::Template: { TemplateDecl *Template = Name.getAsTemplateDecl(); if (TemplateTemplateParmDecl *TTP = dyn_cast
(Template)) Template = getCanonicalTemplateTemplateParmDecl(TTP); // The canonical template name is the canonical template declaration. return TemplateName(cast
(Template->getCanonicalDecl())); } case TemplateName::OverloadedTemplate: llvm_unreachable("cannot canonicalize overloaded template"); case TemplateName::DependentTemplate: { DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); return DTN->CanonicalTemplateName; } case TemplateName::SubstTemplateTemplateParm: { SubstTemplateTemplateParmStorage *subst = Name.getAsSubstTemplateTemplateParm(); return getCanonicalTemplateName(subst->getReplacement()); } case TemplateName::SubstTemplateTemplateParmPack: { SubstTemplateTemplateParmPackStorage *subst = Name.getAsSubstTemplateTemplateParmPack(); TemplateTemplateParmDecl *canonParameter = getCanonicalTemplateTemplateParmDecl(subst->getParameterPack()); TemplateArgument canonArgPack = getCanonicalTemplateArgument(subst->getArgumentPack()); return getSubstTemplateTemplateParmPack(canonParameter, canonArgPack); } } llvm_unreachable("bad template name!"); } bool ASTContext::hasSameTemplateName(TemplateName X, TemplateName Y) { X = getCanonicalTemplateName(X); Y = getCanonicalTemplateName(Y); return X.getAsVoidPointer() == Y.getAsVoidPointer(); } TemplateArgument ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { switch (Arg.getKind()) { case TemplateArgument::Null: return Arg; case TemplateArgument::Expression: return Arg; case TemplateArgument::Declaration: { ValueDecl *D = cast
(Arg.getAsDecl()->getCanonicalDecl()); return TemplateArgument(D, Arg.isDeclForReferenceParam()); } case TemplateArgument::NullPtr: return TemplateArgument(getCanonicalType(Arg.getNullPtrType()), /*isNullPtr*/true); case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); case TemplateArgument::TemplateExpansion: return TemplateArgument(getCanonicalTemplateName( Arg.getAsTemplateOrTemplatePattern()), Arg.getNumTemplateExpansions()); case TemplateArgument::Integral: return TemplateArgument(Arg, getCanonicalType(Arg.getIntegralType())); case TemplateArgument::Type: return TemplateArgument(getCanonicalType(Arg.getAsType())); case TemplateArgument::Pack: { if (Arg.pack_size() == 0) return Arg; TemplateArgument *CanonArgs = new (*this) TemplateArgument[Arg.pack_size()]; unsigned Idx = 0; for (TemplateArgument::pack_iterator A = Arg.pack_begin(), AEnd = Arg.pack_end(); A != AEnd; (void)++A, ++Idx) CanonArgs[Idx] = getCanonicalTemplateArgument(*A); return TemplateArgument(CanonArgs, Arg.pack_size()); } } // Silence GCC warning llvm_unreachable("Unhandled template argument kind"); } NestedNameSpecifier * ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { if (!NNS) return nullptr; switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: // Canonicalize the prefix but keep the identifier the same. return NestedNameSpecifier::Create(*this, getCanonicalNestedNameSpecifier(NNS->getPrefix()), NNS->getAsIdentifier()); case NestedNameSpecifier::Namespace: // A namespace is canonical; build a nested-name-specifier with // this namespace and no prefix. return NestedNameSpecifier::Create(*this, nullptr, NNS->getAsNamespace()->getOriginalNamespace()); case NestedNameSpecifier::NamespaceAlias: // A namespace is canonical; build a nested-name-specifier with // this namespace and no prefix. return NestedNameSpecifier::Create(*this, nullptr, NNS->getAsNamespaceAlias()->getNamespace() ->getOriginalNamespace()); case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); // If we have some kind of dependent-named type (e.g., "typename T::type"), // break it apart into its prefix and identifier, then reconsititute those // as the canonical nested-name-specifier. This is required to canonicalize // a dependent nested-name-specifier involving typedefs of dependent-name // types, e.g., // typedef typename T::type T1; // typedef typename T1::type T2; if (const DependentNameType *DNT = T->getAs
()) return NestedNameSpecifier::Create(*this, DNT->getQualifier(), const_cast
(DNT->getIdentifier())); // Otherwise, just canonicalize the type, and force it to be a TypeSpec. // FIXME: Why are TypeSpec and TypeSpecWithTemplate distinct in the // first place? return NestedNameSpecifier::Create(*this, nullptr, false, const_cast
(T.getTypePtr())); } case NestedNameSpecifier::Global: // The global specifier is canonical and unique. return NNS; } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } const ArrayType *ASTContext::getAsArrayType(QualType T) const { // Handle the non-qualified case efficiently. if (!T.hasLocalQualifiers()) { // Handle the common positive case fast. if (const ArrayType *AT = dyn_cast
(T)) return AT; } // Handle the common negative case fast. if (!isa
(T.getCanonicalType())) return nullptr; // Apply any qualifiers from the array type to the element type. This // implements C99 6.7.3p8: "If the specification of an array type includes // any type qualifiers, the element type is so qualified, not the array type." // If we get here, we either have type qualifiers on the type, or we have // sugar such as a typedef in the way. If we have type qualifiers on the type // we must propagate them down into the element type. SplitQualType split = T.getSplitDesugaredType(); Qualifiers qs = split.Quals; // If we have a simple case, just return now. const ArrayType *ATy = dyn_cast
(split.Ty); if (!ATy || qs.empty()) return ATy; // Otherwise, we have an array and we have qualifiers on it. Push the // qualifiers into the array element type and return a new array type. QualType NewEltTy = getQualifiedType(ATy->getElementType(), qs); if (const ConstantArrayType *CAT = dyn_cast
(ATy)) return cast
(getConstantArrayType(NewEltTy, CAT->getSize(), CAT->getSizeModifier(), CAT->getIndexTypeCVRQualifiers())); if (const IncompleteArrayType *IAT = dyn_cast
(ATy)) return cast
(getIncompleteArrayType(NewEltTy, IAT->getSizeModifier(), IAT->getIndexTypeCVRQualifiers())); if (const DependentSizedArrayType *DSAT = dyn_cast
(ATy)) return cast
( getDependentSizedArrayType(NewEltTy, DSAT->getSizeExpr(), DSAT->getSizeModifier(), DSAT->getIndexTypeCVRQualifiers(), DSAT->getBracketsRange())); const VariableArrayType *VAT = cast
(ATy); return cast