1*0fca6ea1SDimitry Andric //===- Visitor.cpp ---------------------------------------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric 9*0fca6ea1SDimitry Andric #include "clang/InstallAPI/Visitor.h" 10*0fca6ea1SDimitry Andric #include "clang/AST/Availability.h" 11*0fca6ea1SDimitry Andric #include "clang/AST/ParentMapContext.h" 12*0fca6ea1SDimitry Andric #include "clang/AST/VTableBuilder.h" 13*0fca6ea1SDimitry Andric #include "clang/Basic/Linkage.h" 14*0fca6ea1SDimitry Andric #include "clang/InstallAPI/DylibVerifier.h" 15*0fca6ea1SDimitry Andric #include "clang/InstallAPI/FrontendRecords.h" 16*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallString.h" 17*0fca6ea1SDimitry Andric #include "llvm/ADT/StringRef.h" 18*0fca6ea1SDimitry Andric #include "llvm/IR/DataLayout.h" 19*0fca6ea1SDimitry Andric #include "llvm/IR/Mangler.h" 20*0fca6ea1SDimitry Andric 21*0fca6ea1SDimitry Andric using namespace llvm; 22*0fca6ea1SDimitry Andric using namespace llvm::MachO; 23*0fca6ea1SDimitry Andric 24*0fca6ea1SDimitry Andric namespace { 25*0fca6ea1SDimitry Andric enum class CXXLinkage { 26*0fca6ea1SDimitry Andric ExternalLinkage, 27*0fca6ea1SDimitry Andric LinkOnceODRLinkage, 28*0fca6ea1SDimitry Andric WeakODRLinkage, 29*0fca6ea1SDimitry Andric PrivateLinkage, 30*0fca6ea1SDimitry Andric }; 31*0fca6ea1SDimitry Andric } 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric namespace clang::installapi { 34*0fca6ea1SDimitry Andric 35*0fca6ea1SDimitry Andric // Exported NamedDecl needs to have external linkage and 36*0fca6ea1SDimitry Andric // default visibility from LinkageComputer. 37*0fca6ea1SDimitry Andric static bool isExported(const NamedDecl *D) { 38*0fca6ea1SDimitry Andric auto LV = D->getLinkageAndVisibility(); 39*0fca6ea1SDimitry Andric return isExternallyVisible(LV.getLinkage()) && 40*0fca6ea1SDimitry Andric (LV.getVisibility() == DefaultVisibility); 41*0fca6ea1SDimitry Andric } 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric static bool isInlined(const FunctionDecl *D) { 44*0fca6ea1SDimitry Andric bool HasInlineAttribute = false; 45*0fca6ea1SDimitry Andric bool NoCXXAttr = 46*0fca6ea1SDimitry Andric (!D->getASTContext().getLangOpts().CPlusPlus && 47*0fca6ea1SDimitry Andric !D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() && 48*0fca6ea1SDimitry Andric !D->hasAttr<DLLExportAttr>()); 49*0fca6ea1SDimitry Andric 50*0fca6ea1SDimitry Andric // Check all redeclarations to find an inline attribute or keyword. 51*0fca6ea1SDimitry Andric for (const auto *RD : D->redecls()) { 52*0fca6ea1SDimitry Andric if (!RD->isInlined()) 53*0fca6ea1SDimitry Andric continue; 54*0fca6ea1SDimitry Andric HasInlineAttribute = true; 55*0fca6ea1SDimitry Andric if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>())) 56*0fca6ea1SDimitry Andric continue; 57*0fca6ea1SDimitry Andric if (RD->doesThisDeclarationHaveABody() && 58*0fca6ea1SDimitry Andric RD->isInlineDefinitionExternallyVisible()) 59*0fca6ea1SDimitry Andric return false; 60*0fca6ea1SDimitry Andric } 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric if (!HasInlineAttribute) 63*0fca6ea1SDimitry Andric return false; 64*0fca6ea1SDimitry Andric 65*0fca6ea1SDimitry Andric return true; 66*0fca6ea1SDimitry Andric } 67*0fca6ea1SDimitry Andric 68*0fca6ea1SDimitry Andric static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal = false) { 69*0fca6ea1SDimitry Andric SymbolFlags Result = SymbolFlags::None; 70*0fca6ea1SDimitry Andric if (WeakDef) 71*0fca6ea1SDimitry Andric Result |= SymbolFlags::WeakDefined; 72*0fca6ea1SDimitry Andric if (ThreadLocal) 73*0fca6ea1SDimitry Andric Result |= SymbolFlags::ThreadLocalValue; 74*0fca6ea1SDimitry Andric 75*0fca6ea1SDimitry Andric return Result; 76*0fca6ea1SDimitry Andric } 77*0fca6ea1SDimitry Andric 78*0fca6ea1SDimitry Andric void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) { 79*0fca6ea1SDimitry Andric if (ASTCtx.getDiagnostics().hasErrorOccurred()) 80*0fca6ea1SDimitry Andric return; 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric auto *D = ASTCtx.getTranslationUnitDecl(); 83*0fca6ea1SDimitry Andric TraverseDecl(D); 84*0fca6ea1SDimitry Andric } 85*0fca6ea1SDimitry Andric 86*0fca6ea1SDimitry Andric std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const { 87*0fca6ea1SDimitry Andric SmallString<256> Name; 88*0fca6ea1SDimitry Andric if (MC->shouldMangleDeclName(D)) { 89*0fca6ea1SDimitry Andric raw_svector_ostream NStream(Name); 90*0fca6ea1SDimitry Andric MC->mangleName(D, NStream); 91*0fca6ea1SDimitry Andric } else 92*0fca6ea1SDimitry Andric Name += D->getNameAsString(); 93*0fca6ea1SDimitry Andric 94*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 95*0fca6ea1SDimitry Andric } 96*0fca6ea1SDimitry Andric 97*0fca6ea1SDimitry Andric std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const { 98*0fca6ea1SDimitry Andric SmallString<256> FinalName; 99*0fca6ea1SDimitry Andric Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout)); 100*0fca6ea1SDimitry Andric return std::string(FinalName); 101*0fca6ea1SDimitry Andric } 102*0fca6ea1SDimitry Andric 103*0fca6ea1SDimitry Andric std::optional<HeaderType> 104*0fca6ea1SDimitry Andric InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const { 105*0fca6ea1SDimitry Andric SourceLocation Loc = D->getLocation(); 106*0fca6ea1SDimitry Andric if (Loc.isInvalid()) 107*0fca6ea1SDimitry Andric return std::nullopt; 108*0fca6ea1SDimitry Andric 109*0fca6ea1SDimitry Andric // If the loc refers to a macro expansion, InstallAPI needs to first get the 110*0fca6ea1SDimitry Andric // file location of the expansion. 111*0fca6ea1SDimitry Andric auto FileLoc = SrcMgr.getFileLoc(Loc); 112*0fca6ea1SDimitry Andric FileID ID = SrcMgr.getFileID(FileLoc); 113*0fca6ea1SDimitry Andric if (ID.isInvalid()) 114*0fca6ea1SDimitry Andric return std::nullopt; 115*0fca6ea1SDimitry Andric 116*0fca6ea1SDimitry Andric const FileEntry *FE = SrcMgr.getFileEntryForID(ID); 117*0fca6ea1SDimitry Andric if (!FE) 118*0fca6ea1SDimitry Andric return std::nullopt; 119*0fca6ea1SDimitry Andric 120*0fca6ea1SDimitry Andric auto Header = Ctx.findAndRecordFile(FE, PP); 121*0fca6ea1SDimitry Andric if (!Header.has_value()) 122*0fca6ea1SDimitry Andric return std::nullopt; 123*0fca6ea1SDimitry Andric 124*0fca6ea1SDimitry Andric HeaderType Access = Header.value(); 125*0fca6ea1SDimitry Andric assert(Access != HeaderType::Unknown && "unexpected access level for global"); 126*0fca6ea1SDimitry Andric return Access; 127*0fca6ea1SDimitry Andric } 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric /// Check if the interface itself or any of its super classes have an 130*0fca6ea1SDimitry Andric /// exception attribute. InstallAPI needs to export an additional symbol 131*0fca6ea1SDimitry Andric /// ("OBJC_EHTYPE_$CLASS_NAME") if any of the classes have the exception 132*0fca6ea1SDimitry Andric /// attribute. 133*0fca6ea1SDimitry Andric static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) { 134*0fca6ea1SDimitry Andric for (; D != nullptr; D = D->getSuperClass()) 135*0fca6ea1SDimitry Andric if (D->hasAttr<ObjCExceptionAttr>()) 136*0fca6ea1SDimitry Andric return true; 137*0fca6ea1SDimitry Andric 138*0fca6ea1SDimitry Andric return false; 139*0fca6ea1SDimitry Andric } 140*0fca6ea1SDimitry Andric void InstallAPIVisitor::recordObjCInstanceVariables( 141*0fca6ea1SDimitry Andric const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass, 142*0fca6ea1SDimitry Andric const llvm::iterator_range< 143*0fca6ea1SDimitry Andric DeclContext::specific_decl_iterator<ObjCIvarDecl>> 144*0fca6ea1SDimitry Andric Ivars) { 145*0fca6ea1SDimitry Andric RecordLinkage Linkage = RecordLinkage::Exported; 146*0fca6ea1SDimitry Andric const RecordLinkage ContainerLinkage = Record->getLinkage(); 147*0fca6ea1SDimitry Andric // If fragile, set to unknown. 148*0fca6ea1SDimitry Andric if (ASTCtx.getLangOpts().ObjCRuntime.isFragile()) 149*0fca6ea1SDimitry Andric Linkage = RecordLinkage::Unknown; 150*0fca6ea1SDimitry Andric // Linkage should be inherited from container. 151*0fca6ea1SDimitry Andric else if (ContainerLinkage != RecordLinkage::Unknown) 152*0fca6ea1SDimitry Andric Linkage = ContainerLinkage; 153*0fca6ea1SDimitry Andric for (const auto *IV : Ivars) { 154*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(IV); 155*0fca6ea1SDimitry Andric if (!Access) 156*0fca6ea1SDimitry Andric continue; 157*0fca6ea1SDimitry Andric StringRef Name = IV->getName(); 158*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV); 159*0fca6ea1SDimitry Andric auto AC = IV->getCanonicalAccessControl(); 160*0fca6ea1SDimitry Andric auto [ObjCIVR, FA] = 161*0fca6ea1SDimitry Andric Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC); 162*0fca6ea1SDimitry Andric Ctx.Verifier->verify(ObjCIVR, FA, SuperClass); 163*0fca6ea1SDimitry Andric } 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric 166*0fca6ea1SDimitry Andric bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { 167*0fca6ea1SDimitry Andric // Skip forward declaration for classes (@class) 168*0fca6ea1SDimitry Andric if (!D->isThisDeclarationADefinition()) 169*0fca6ea1SDimitry Andric return true; 170*0fca6ea1SDimitry Andric 171*0fca6ea1SDimitry Andric // Skip over declarations that access could not be collected for. 172*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(D); 173*0fca6ea1SDimitry Andric if (!Access) 174*0fca6ea1SDimitry Andric return true; 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric StringRef Name = D->getObjCRuntimeNameAsString(); 177*0fca6ea1SDimitry Andric const RecordLinkage Linkage = 178*0fca6ea1SDimitry Andric isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal; 179*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 180*0fca6ea1SDimitry Andric const bool IsEHType = 181*0fca6ea1SDimitry Andric (!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() && 182*0fca6ea1SDimitry Andric hasObjCExceptionAttribute(D)); 183*0fca6ea1SDimitry Andric 184*0fca6ea1SDimitry Andric auto [Class, FA] = 185*0fca6ea1SDimitry Andric Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType); 186*0fca6ea1SDimitry Andric Ctx.Verifier->verify(Class, FA); 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric // Get base class. 189*0fca6ea1SDimitry Andric StringRef SuperClassName; 190*0fca6ea1SDimitry Andric if (const auto *SuperClass = D->getSuperClass()) 191*0fca6ea1SDimitry Andric SuperClassName = SuperClass->getObjCRuntimeNameAsString(); 192*0fca6ea1SDimitry Andric 193*0fca6ea1SDimitry Andric recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(), 194*0fca6ea1SDimitry Andric D->ivars()); 195*0fca6ea1SDimitry Andric return true; 196*0fca6ea1SDimitry Andric } 197*0fca6ea1SDimitry Andric 198*0fca6ea1SDimitry Andric bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { 199*0fca6ea1SDimitry Andric StringRef CategoryName = D->getName(); 200*0fca6ea1SDimitry Andric // Skip over declarations that access could not be collected for. 201*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(D); 202*0fca6ea1SDimitry Andric if (!Access) 203*0fca6ea1SDimitry Andric return true; 204*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 205*0fca6ea1SDimitry Andric const ObjCInterfaceDecl *InterfaceD = D->getClassInterface(); 206*0fca6ea1SDimitry Andric const StringRef InterfaceName = InterfaceD->getName(); 207*0fca6ea1SDimitry Andric 208*0fca6ea1SDimitry Andric ObjCCategoryRecord *CategoryRecord = 209*0fca6ea1SDimitry Andric Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, Avail, D, *Access) 210*0fca6ea1SDimitry Andric .first; 211*0fca6ea1SDimitry Andric recordObjCInstanceVariables(D->getASTContext(), CategoryRecord, InterfaceName, 212*0fca6ea1SDimitry Andric D->ivars()); 213*0fca6ea1SDimitry Andric return true; 214*0fca6ea1SDimitry Andric } 215*0fca6ea1SDimitry Andric 216*0fca6ea1SDimitry Andric bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) { 217*0fca6ea1SDimitry Andric // Skip function parameters. 218*0fca6ea1SDimitry Andric if (isa<ParmVarDecl>(D)) 219*0fca6ea1SDimitry Andric return true; 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric // Skip variables in records. They are handled separately for C++. 222*0fca6ea1SDimitry Andric if (D->getDeclContext()->isRecord()) 223*0fca6ea1SDimitry Andric return true; 224*0fca6ea1SDimitry Andric 225*0fca6ea1SDimitry Andric // Skip anything inside functions or methods. 226*0fca6ea1SDimitry Andric if (!D->isDefinedOutsideFunctionOrMethod()) 227*0fca6ea1SDimitry Andric return true; 228*0fca6ea1SDimitry Andric 229*0fca6ea1SDimitry Andric // If this is a template but not specialization or instantiation, skip. 230*0fca6ea1SDimitry Andric if (D->getASTContext().getTemplateOrSpecializationInfo(D) && 231*0fca6ea1SDimitry Andric D->getTemplateSpecializationKind() == TSK_Undeclared) 232*0fca6ea1SDimitry Andric return true; 233*0fca6ea1SDimitry Andric 234*0fca6ea1SDimitry Andric // Skip over declarations that access could not collected for. 235*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(D); 236*0fca6ea1SDimitry Andric if (!Access) 237*0fca6ea1SDimitry Andric return true; 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric const RecordLinkage Linkage = 240*0fca6ea1SDimitry Andric isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal; 241*0fca6ea1SDimitry Andric const bool WeakDef = D->hasAttr<WeakAttr>(); 242*0fca6ea1SDimitry Andric const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None; 243*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 244*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage, 245*0fca6ea1SDimitry Andric GlobalRecord::Kind::Variable, Avail, D, 246*0fca6ea1SDimitry Andric *Access, getFlags(WeakDef, ThreadLocal)); 247*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 248*0fca6ea1SDimitry Andric return true; 249*0fca6ea1SDimitry Andric } 250*0fca6ea1SDimitry Andric 251*0fca6ea1SDimitry Andric bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) { 252*0fca6ea1SDimitry Andric if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) { 253*0fca6ea1SDimitry Andric // Skip member function in class templates. 254*0fca6ea1SDimitry Andric if (M->getParent()->getDescribedClassTemplate() != nullptr) 255*0fca6ea1SDimitry Andric return true; 256*0fca6ea1SDimitry Andric 257*0fca6ea1SDimitry Andric // Skip methods in CXX RecordDecls. 258*0fca6ea1SDimitry Andric for (const DynTypedNode &P : D->getASTContext().getParents(*M)) { 259*0fca6ea1SDimitry Andric if (P.get<CXXRecordDecl>()) 260*0fca6ea1SDimitry Andric return true; 261*0fca6ea1SDimitry Andric } 262*0fca6ea1SDimitry Andric 263*0fca6ea1SDimitry Andric // Skip CXX ConstructorDecls and DestructorDecls. 264*0fca6ea1SDimitry Andric if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M)) 265*0fca6ea1SDimitry Andric return true; 266*0fca6ea1SDimitry Andric } 267*0fca6ea1SDimitry Andric 268*0fca6ea1SDimitry Andric // Skip templated functions. 269*0fca6ea1SDimitry Andric switch (D->getTemplatedKind()) { 270*0fca6ea1SDimitry Andric case FunctionDecl::TK_NonTemplate: 271*0fca6ea1SDimitry Andric case FunctionDecl::TK_DependentNonTemplate: 272*0fca6ea1SDimitry Andric break; 273*0fca6ea1SDimitry Andric case FunctionDecl::TK_MemberSpecialization: 274*0fca6ea1SDimitry Andric case FunctionDecl::TK_FunctionTemplateSpecialization: 275*0fca6ea1SDimitry Andric if (auto *TempInfo = D->getTemplateSpecializationInfo()) { 276*0fca6ea1SDimitry Andric if (!TempInfo->isExplicitInstantiationOrSpecialization()) 277*0fca6ea1SDimitry Andric return true; 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric break; 280*0fca6ea1SDimitry Andric case FunctionDecl::TK_FunctionTemplate: 281*0fca6ea1SDimitry Andric case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 282*0fca6ea1SDimitry Andric return true; 283*0fca6ea1SDimitry Andric } 284*0fca6ea1SDimitry Andric 285*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(D); 286*0fca6ea1SDimitry Andric if (!Access) 287*0fca6ea1SDimitry Andric return true; 288*0fca6ea1SDimitry Andric auto Name = getMangledName(D); 289*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 290*0fca6ea1SDimitry Andric const bool ExplicitInstantiation = D->getTemplateSpecializationKind() == 291*0fca6ea1SDimitry Andric TSK_ExplicitInstantiationDeclaration; 292*0fca6ea1SDimitry Andric const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>(); 293*0fca6ea1SDimitry Andric const bool Inlined = isInlined(D); 294*0fca6ea1SDimitry Andric const RecordLinkage Linkage = (Inlined || !isExported(D)) 295*0fca6ea1SDimitry Andric ? RecordLinkage::Internal 296*0fca6ea1SDimitry Andric : RecordLinkage::Exported; 297*0fca6ea1SDimitry Andric auto [GR, FA] = 298*0fca6ea1SDimitry Andric Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, 299*0fca6ea1SDimitry Andric D, *Access, getFlags(WeakDef), Inlined); 300*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 301*0fca6ea1SDimitry Andric return true; 302*0fca6ea1SDimitry Andric } 303*0fca6ea1SDimitry Andric 304*0fca6ea1SDimitry Andric static bool hasVTable(const CXXRecordDecl *D) { 305*0fca6ea1SDimitry Andric // Check if vtable symbols should be emitted, only dynamic classes need 306*0fca6ea1SDimitry Andric // vtables. 307*0fca6ea1SDimitry Andric if (!D->hasDefinition() || !D->isDynamicClass()) 308*0fca6ea1SDimitry Andric return false; 309*0fca6ea1SDimitry Andric 310*0fca6ea1SDimitry Andric assert(D->isExternallyVisible() && "Should be externally visible"); 311*0fca6ea1SDimitry Andric assert(D->isCompleteDefinition() && "Only works on complete definitions"); 312*0fca6ea1SDimitry Andric 313*0fca6ea1SDimitry Andric const CXXMethodDecl *KeyFunctionD = 314*0fca6ea1SDimitry Andric D->getASTContext().getCurrentKeyFunction(D); 315*0fca6ea1SDimitry Andric // If this class has a key function, then there is a vtable, possibly internal 316*0fca6ea1SDimitry Andric // though. 317*0fca6ea1SDimitry Andric if (KeyFunctionD) { 318*0fca6ea1SDimitry Andric switch (KeyFunctionD->getTemplateSpecializationKind()) { 319*0fca6ea1SDimitry Andric case TSK_Undeclared: 320*0fca6ea1SDimitry Andric case TSK_ExplicitSpecialization: 321*0fca6ea1SDimitry Andric case TSK_ImplicitInstantiation: 322*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDefinition: 323*0fca6ea1SDimitry Andric return true; 324*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDeclaration: 325*0fca6ea1SDimitry Andric llvm_unreachable( 326*0fca6ea1SDimitry Andric "Unexpected TemplateSpecializationKind for key function"); 327*0fca6ea1SDimitry Andric } 328*0fca6ea1SDimitry Andric } else if (D->isAbstract()) { 329*0fca6ea1SDimitry Andric // If the class is abstract and it doesn't have a key function, it is a 330*0fca6ea1SDimitry Andric // 'pure' virtual class. It doesn't need a vtable. 331*0fca6ea1SDimitry Andric return false; 332*0fca6ea1SDimitry Andric } 333*0fca6ea1SDimitry Andric 334*0fca6ea1SDimitry Andric switch (D->getTemplateSpecializationKind()) { 335*0fca6ea1SDimitry Andric case TSK_Undeclared: 336*0fca6ea1SDimitry Andric case TSK_ExplicitSpecialization: 337*0fca6ea1SDimitry Andric case TSK_ImplicitInstantiation: 338*0fca6ea1SDimitry Andric return false; 339*0fca6ea1SDimitry Andric 340*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDeclaration: 341*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDefinition: 342*0fca6ea1SDimitry Andric return true; 343*0fca6ea1SDimitry Andric } 344*0fca6ea1SDimitry Andric 345*0fca6ea1SDimitry Andric llvm_unreachable("Invalid TemplateSpecializationKind!"); 346*0fca6ea1SDimitry Andric } 347*0fca6ea1SDimitry Andric 348*0fca6ea1SDimitry Andric static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) { 349*0fca6ea1SDimitry Andric assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable"); 350*0fca6ea1SDimitry Andric assert(D->isExternallyVisible() && "Record should be externally visible"); 351*0fca6ea1SDimitry Andric if (D->getVisibility() == HiddenVisibility) 352*0fca6ea1SDimitry Andric return CXXLinkage::PrivateLinkage; 353*0fca6ea1SDimitry Andric 354*0fca6ea1SDimitry Andric const CXXMethodDecl *KeyFunctionD = 355*0fca6ea1SDimitry Andric D->getASTContext().getCurrentKeyFunction(D); 356*0fca6ea1SDimitry Andric if (KeyFunctionD) { 357*0fca6ea1SDimitry Andric // If this class has a key function, use that to determine the 358*0fca6ea1SDimitry Andric // linkage of the vtable. 359*0fca6ea1SDimitry Andric switch (KeyFunctionD->getTemplateSpecializationKind()) { 360*0fca6ea1SDimitry Andric case TSK_Undeclared: 361*0fca6ea1SDimitry Andric case TSK_ExplicitSpecialization: 362*0fca6ea1SDimitry Andric if (isInlined(KeyFunctionD)) 363*0fca6ea1SDimitry Andric return CXXLinkage::LinkOnceODRLinkage; 364*0fca6ea1SDimitry Andric return CXXLinkage::ExternalLinkage; 365*0fca6ea1SDimitry Andric case TSK_ImplicitInstantiation: 366*0fca6ea1SDimitry Andric llvm_unreachable("No external vtable for implicit instantiations"); 367*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDefinition: 368*0fca6ea1SDimitry Andric return CXXLinkage::WeakODRLinkage; 369*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDeclaration: 370*0fca6ea1SDimitry Andric llvm_unreachable( 371*0fca6ea1SDimitry Andric "Unexpected TemplateSpecializationKind for key function"); 372*0fca6ea1SDimitry Andric } 373*0fca6ea1SDimitry Andric } 374*0fca6ea1SDimitry Andric 375*0fca6ea1SDimitry Andric switch (D->getTemplateSpecializationKind()) { 376*0fca6ea1SDimitry Andric case TSK_Undeclared: 377*0fca6ea1SDimitry Andric case TSK_ExplicitSpecialization: 378*0fca6ea1SDimitry Andric case TSK_ImplicitInstantiation: 379*0fca6ea1SDimitry Andric return CXXLinkage::LinkOnceODRLinkage; 380*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDeclaration: 381*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDefinition: 382*0fca6ea1SDimitry Andric return CXXLinkage::WeakODRLinkage; 383*0fca6ea1SDimitry Andric } 384*0fca6ea1SDimitry Andric 385*0fca6ea1SDimitry Andric llvm_unreachable("Invalid TemplateSpecializationKind!"); 386*0fca6ea1SDimitry Andric } 387*0fca6ea1SDimitry Andric 388*0fca6ea1SDimitry Andric static bool isRTTIWeakDef(const CXXRecordDecl *D) { 389*0fca6ea1SDimitry Andric if (D->hasAttr<WeakAttr>()) 390*0fca6ea1SDimitry Andric return true; 391*0fca6ea1SDimitry Andric 392*0fca6ea1SDimitry Andric if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr) 393*0fca6ea1SDimitry Andric return true; 394*0fca6ea1SDimitry Andric 395*0fca6ea1SDimitry Andric if (D->isDynamicClass()) 396*0fca6ea1SDimitry Andric return getVTableLinkage(D) != CXXLinkage::ExternalLinkage; 397*0fca6ea1SDimitry Andric 398*0fca6ea1SDimitry Andric return false; 399*0fca6ea1SDimitry Andric } 400*0fca6ea1SDimitry Andric 401*0fca6ea1SDimitry Andric static bool hasRTTI(const CXXRecordDecl *D) { 402*0fca6ea1SDimitry Andric if (!D->getASTContext().getLangOpts().RTTI) 403*0fca6ea1SDimitry Andric return false; 404*0fca6ea1SDimitry Andric 405*0fca6ea1SDimitry Andric if (!D->hasDefinition()) 406*0fca6ea1SDimitry Andric return false; 407*0fca6ea1SDimitry Andric 408*0fca6ea1SDimitry Andric if (!D->isDynamicClass()) 409*0fca6ea1SDimitry Andric return false; 410*0fca6ea1SDimitry Andric 411*0fca6ea1SDimitry Andric // Don't emit weak-def RTTI information. InstallAPI cannot reliably determine 412*0fca6ea1SDimitry Andric // if the final binary will have those weak defined RTTI symbols. This depends 413*0fca6ea1SDimitry Andric // on the optimization level and if the class has been instantiated and used. 414*0fca6ea1SDimitry Andric // 415*0fca6ea1SDimitry Andric // Luckily, the Apple static linker doesn't need those weak defined RTTI 416*0fca6ea1SDimitry Andric // symbols for linking. They are only needed by the runtime linker. That means 417*0fca6ea1SDimitry Andric // they can be safely dropped. 418*0fca6ea1SDimitry Andric if (isRTTIWeakDef(D)) 419*0fca6ea1SDimitry Andric return false; 420*0fca6ea1SDimitry Andric 421*0fca6ea1SDimitry Andric return true; 422*0fca6ea1SDimitry Andric } 423*0fca6ea1SDimitry Andric 424*0fca6ea1SDimitry Andric std::string 425*0fca6ea1SDimitry Andric InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const { 426*0fca6ea1SDimitry Andric SmallString<256> Name; 427*0fca6ea1SDimitry Andric raw_svector_ostream NameStream(Name); 428*0fca6ea1SDimitry Andric MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream); 429*0fca6ea1SDimitry Andric 430*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 431*0fca6ea1SDimitry Andric } 432*0fca6ea1SDimitry Andric 433*0fca6ea1SDimitry Andric std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const { 434*0fca6ea1SDimitry Andric SmallString<256> Name; 435*0fca6ea1SDimitry Andric raw_svector_ostream NameStream(Name); 436*0fca6ea1SDimitry Andric MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream); 437*0fca6ea1SDimitry Andric 438*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 439*0fca6ea1SDimitry Andric } 440*0fca6ea1SDimitry Andric 441*0fca6ea1SDimitry Andric std::string 442*0fca6ea1SDimitry Andric InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const { 443*0fca6ea1SDimitry Andric SmallString<256> Name; 444*0fca6ea1SDimitry Andric raw_svector_ostream NameStream(Name); 445*0fca6ea1SDimitry Andric MC->mangleCXXVTable(D, NameStream); 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 448*0fca6ea1SDimitry Andric } 449*0fca6ea1SDimitry Andric 450*0fca6ea1SDimitry Andric std::string InstallAPIVisitor::getMangledCXXThunk( 451*0fca6ea1SDimitry Andric const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const { 452*0fca6ea1SDimitry Andric SmallString<256> Name; 453*0fca6ea1SDimitry Andric raw_svector_ostream NameStream(Name); 454*0fca6ea1SDimitry Andric const auto *Method = cast<CXXMethodDecl>(D.getDecl()); 455*0fca6ea1SDimitry Andric if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) 456*0fca6ea1SDimitry Andric MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk, ElideOverrideInfo, 457*0fca6ea1SDimitry Andric NameStream); 458*0fca6ea1SDimitry Andric else 459*0fca6ea1SDimitry Andric MC->mangleThunk(Method, Thunk, ElideOverrideInfo, NameStream); 460*0fca6ea1SDimitry Andric 461*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 462*0fca6ea1SDimitry Andric } 463*0fca6ea1SDimitry Andric 464*0fca6ea1SDimitry Andric std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D, 465*0fca6ea1SDimitry Andric int Type) const { 466*0fca6ea1SDimitry Andric SmallString<256> Name; 467*0fca6ea1SDimitry Andric raw_svector_ostream NameStream(Name); 468*0fca6ea1SDimitry Andric GlobalDecl GD; 469*0fca6ea1SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) 470*0fca6ea1SDimitry Andric GD = GlobalDecl(Ctor, CXXCtorType(Type)); 471*0fca6ea1SDimitry Andric else { 472*0fca6ea1SDimitry Andric const auto *Dtor = cast<CXXDestructorDecl>(D); 473*0fca6ea1SDimitry Andric GD = GlobalDecl(Dtor, CXXDtorType(Type)); 474*0fca6ea1SDimitry Andric } 475*0fca6ea1SDimitry Andric MC->mangleName(GD, NameStream); 476*0fca6ea1SDimitry Andric return getBackendMangledName(Name); 477*0fca6ea1SDimitry Andric } 478*0fca6ea1SDimitry Andric 479*0fca6ea1SDimitry Andric void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D, 480*0fca6ea1SDimitry Andric const AvailabilityInfo &Avail, 481*0fca6ea1SDimitry Andric const HeaderType Access, 482*0fca6ea1SDimitry Andric bool EmittedVTable) { 483*0fca6ea1SDimitry Andric if (hasVTable(D)) { 484*0fca6ea1SDimitry Andric EmittedVTable = true; 485*0fca6ea1SDimitry Andric const CXXLinkage VTableLinkage = getVTableLinkage(D); 486*0fca6ea1SDimitry Andric if (VTableLinkage == CXXLinkage::ExternalLinkage || 487*0fca6ea1SDimitry Andric VTableLinkage == CXXLinkage::WeakODRLinkage) { 488*0fca6ea1SDimitry Andric const std::string Name = getMangledCXXVTableName(D); 489*0fca6ea1SDimitry Andric const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage; 490*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 491*0fca6ea1SDimitry Andric GlobalRecord::Kind::Variable, Avail, 492*0fca6ea1SDimitry Andric D, Access, getFlags(WeakDef)); 493*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 494*0fca6ea1SDimitry Andric if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) { 495*0fca6ea1SDimitry Andric VTableContextBase *VTable = D->getASTContext().getVTableContext(); 496*0fca6ea1SDimitry Andric auto AddThunk = [&](GlobalDecl GD) { 497*0fca6ea1SDimitry Andric const ItaniumVTableContext::ThunkInfoVectorTy *Thunks = 498*0fca6ea1SDimitry Andric VTable->getThunkInfo(GD); 499*0fca6ea1SDimitry Andric if (!Thunks) 500*0fca6ea1SDimitry Andric return; 501*0fca6ea1SDimitry Andric 502*0fca6ea1SDimitry Andric for (const auto &Thunk : *Thunks) { 503*0fca6ea1SDimitry Andric const std::string Name = 504*0fca6ea1SDimitry Andric getMangledCXXThunk(GD, Thunk, /*ElideOverrideInfo=*/true); 505*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 506*0fca6ea1SDimitry Andric GlobalRecord::Kind::Function, 507*0fca6ea1SDimitry Andric Avail, GD.getDecl(), Access); 508*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 509*0fca6ea1SDimitry Andric } 510*0fca6ea1SDimitry Andric }; 511*0fca6ea1SDimitry Andric 512*0fca6ea1SDimitry Andric for (const auto *Method : D->methods()) { 513*0fca6ea1SDimitry Andric if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual()) 514*0fca6ea1SDimitry Andric continue; 515*0fca6ea1SDimitry Andric 516*0fca6ea1SDimitry Andric if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) { 517*0fca6ea1SDimitry Andric // Skip default destructor. 518*0fca6ea1SDimitry Andric if (Dtor->isDefaulted()) 519*0fca6ea1SDimitry Andric continue; 520*0fca6ea1SDimitry Andric AddThunk({Dtor, Dtor_Deleting}); 521*0fca6ea1SDimitry Andric AddThunk({Dtor, Dtor_Complete}); 522*0fca6ea1SDimitry Andric } else 523*0fca6ea1SDimitry Andric AddThunk(Method); 524*0fca6ea1SDimitry Andric } 525*0fca6ea1SDimitry Andric } 526*0fca6ea1SDimitry Andric } 527*0fca6ea1SDimitry Andric } 528*0fca6ea1SDimitry Andric 529*0fca6ea1SDimitry Andric if (!EmittedVTable) 530*0fca6ea1SDimitry Andric return; 531*0fca6ea1SDimitry Andric 532*0fca6ea1SDimitry Andric if (hasRTTI(D)) { 533*0fca6ea1SDimitry Andric std::string Name = getMangledCXXRTTI(D); 534*0fca6ea1SDimitry Andric auto [GR, FA] = 535*0fca6ea1SDimitry Andric Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 536*0fca6ea1SDimitry Andric GlobalRecord::Kind::Variable, Avail, D, Access); 537*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 538*0fca6ea1SDimitry Andric 539*0fca6ea1SDimitry Andric Name = getMangledCXXRTTIName(D); 540*0fca6ea1SDimitry Andric auto [NamedGR, NamedFA] = 541*0fca6ea1SDimitry Andric Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 542*0fca6ea1SDimitry Andric GlobalRecord::Kind::Variable, Avail, D, Access); 543*0fca6ea1SDimitry Andric Ctx.Verifier->verify(NamedGR, NamedFA); 544*0fca6ea1SDimitry Andric } 545*0fca6ea1SDimitry Andric 546*0fca6ea1SDimitry Andric for (const auto &It : D->bases()) { 547*0fca6ea1SDimitry Andric const CXXRecordDecl *Base = 548*0fca6ea1SDimitry Andric cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl()); 549*0fca6ea1SDimitry Andric const auto BaseAccess = getAccessForDecl(Base); 550*0fca6ea1SDimitry Andric if (!BaseAccess) 551*0fca6ea1SDimitry Andric continue; 552*0fca6ea1SDimitry Andric const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base); 553*0fca6ea1SDimitry Andric emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true); 554*0fca6ea1SDimitry Andric } 555*0fca6ea1SDimitry Andric } 556*0fca6ea1SDimitry Andric 557*0fca6ea1SDimitry Andric bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) { 558*0fca6ea1SDimitry Andric if (!D->isCompleteDefinition()) 559*0fca6ea1SDimitry Andric return true; 560*0fca6ea1SDimitry Andric 561*0fca6ea1SDimitry Andric // Skip templated classes. 562*0fca6ea1SDimitry Andric if (D->getDescribedClassTemplate() != nullptr) 563*0fca6ea1SDimitry Andric return true; 564*0fca6ea1SDimitry Andric 565*0fca6ea1SDimitry Andric // Skip partial templated classes too. 566*0fca6ea1SDimitry Andric if (isa<ClassTemplatePartialSpecializationDecl>(D)) 567*0fca6ea1SDimitry Andric return true; 568*0fca6ea1SDimitry Andric 569*0fca6ea1SDimitry Andric auto Access = getAccessForDecl(D); 570*0fca6ea1SDimitry Andric if (!Access) 571*0fca6ea1SDimitry Andric return true; 572*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 573*0fca6ea1SDimitry Andric 574*0fca6ea1SDimitry Andric // Check whether to emit the vtable/rtti symbols. 575*0fca6ea1SDimitry Andric if (isExported(D)) 576*0fca6ea1SDimitry Andric emitVTableSymbols(D, Avail, *Access); 577*0fca6ea1SDimitry Andric 578*0fca6ea1SDimitry Andric TemplateSpecializationKind ClassSK = TSK_Undeclared; 579*0fca6ea1SDimitry Andric bool KeepInlineAsWeak = false; 580*0fca6ea1SDimitry Andric if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 581*0fca6ea1SDimitry Andric ClassSK = Templ->getTemplateSpecializationKind(); 582*0fca6ea1SDimitry Andric if (ClassSK == TSK_ExplicitInstantiationDeclaration) 583*0fca6ea1SDimitry Andric KeepInlineAsWeak = true; 584*0fca6ea1SDimitry Andric } 585*0fca6ea1SDimitry Andric 586*0fca6ea1SDimitry Andric // Record the class methods. 587*0fca6ea1SDimitry Andric for (const auto *M : D->methods()) { 588*0fca6ea1SDimitry Andric // Inlined methods are usually not emitted, except when it comes from a 589*0fca6ea1SDimitry Andric // specialized template. 590*0fca6ea1SDimitry Andric bool WeakDef = false; 591*0fca6ea1SDimitry Andric if (isInlined(M)) { 592*0fca6ea1SDimitry Andric if (!KeepInlineAsWeak) 593*0fca6ea1SDimitry Andric continue; 594*0fca6ea1SDimitry Andric 595*0fca6ea1SDimitry Andric WeakDef = true; 596*0fca6ea1SDimitry Andric } 597*0fca6ea1SDimitry Andric 598*0fca6ea1SDimitry Andric if (!isExported(M)) 599*0fca6ea1SDimitry Andric continue; 600*0fca6ea1SDimitry Andric 601*0fca6ea1SDimitry Andric switch (M->getTemplateSpecializationKind()) { 602*0fca6ea1SDimitry Andric case TSK_Undeclared: 603*0fca6ea1SDimitry Andric case TSK_ExplicitSpecialization: 604*0fca6ea1SDimitry Andric break; 605*0fca6ea1SDimitry Andric case TSK_ImplicitInstantiation: 606*0fca6ea1SDimitry Andric continue; 607*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDeclaration: 608*0fca6ea1SDimitry Andric if (ClassSK == TSK_ExplicitInstantiationDeclaration) 609*0fca6ea1SDimitry Andric WeakDef = true; 610*0fca6ea1SDimitry Andric break; 611*0fca6ea1SDimitry Andric case TSK_ExplicitInstantiationDefinition: 612*0fca6ea1SDimitry Andric WeakDef = true; 613*0fca6ea1SDimitry Andric break; 614*0fca6ea1SDimitry Andric } 615*0fca6ea1SDimitry Andric 616*0fca6ea1SDimitry Andric if (!M->isUserProvided()) 617*0fca6ea1SDimitry Andric continue; 618*0fca6ea1SDimitry Andric 619*0fca6ea1SDimitry Andric // Methods that are deleted are not exported. 620*0fca6ea1SDimitry Andric if (M->isDeleted()) 621*0fca6ea1SDimitry Andric continue; 622*0fca6ea1SDimitry Andric 623*0fca6ea1SDimitry Andric const auto Access = getAccessForDecl(M); 624*0fca6ea1SDimitry Andric if (!Access) 625*0fca6ea1SDimitry Andric return true; 626*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M); 627*0fca6ea1SDimitry Andric 628*0fca6ea1SDimitry Andric if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) { 629*0fca6ea1SDimitry Andric // Defaulted constructors are not exported. 630*0fca6ea1SDimitry Andric if (Ctor->isDefaulted()) 631*0fca6ea1SDimitry Andric continue; 632*0fca6ea1SDimitry Andric 633*0fca6ea1SDimitry Andric std::string Name = getMangledCtorDtor(M, Ctor_Base); 634*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 635*0fca6ea1SDimitry Andric GlobalRecord::Kind::Function, Avail, 636*0fca6ea1SDimitry Andric D, *Access, getFlags(WeakDef)); 637*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 638*0fca6ea1SDimitry Andric 639*0fca6ea1SDimitry Andric if (!D->isAbstract()) { 640*0fca6ea1SDimitry Andric std::string Name = getMangledCtorDtor(M, Ctor_Complete); 641*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal( 642*0fca6ea1SDimitry Andric Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, 643*0fca6ea1SDimitry Andric D, *Access, getFlags(WeakDef)); 644*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 645*0fca6ea1SDimitry Andric } 646*0fca6ea1SDimitry Andric 647*0fca6ea1SDimitry Andric continue; 648*0fca6ea1SDimitry Andric } 649*0fca6ea1SDimitry Andric 650*0fca6ea1SDimitry Andric if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) { 651*0fca6ea1SDimitry Andric // Defaulted destructors are not exported. 652*0fca6ea1SDimitry Andric if (Dtor->isDefaulted()) 653*0fca6ea1SDimitry Andric continue; 654*0fca6ea1SDimitry Andric 655*0fca6ea1SDimitry Andric std::string Name = getMangledCtorDtor(M, Dtor_Base); 656*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 657*0fca6ea1SDimitry Andric GlobalRecord::Kind::Function, Avail, 658*0fca6ea1SDimitry Andric D, *Access, getFlags(WeakDef)); 659*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 660*0fca6ea1SDimitry Andric 661*0fca6ea1SDimitry Andric Name = getMangledCtorDtor(M, Dtor_Complete); 662*0fca6ea1SDimitry Andric auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal( 663*0fca6ea1SDimitry Andric Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D, 664*0fca6ea1SDimitry Andric *Access, getFlags(WeakDef)); 665*0fca6ea1SDimitry Andric Ctx.Verifier->verify(CompleteGR, CompleteFA); 666*0fca6ea1SDimitry Andric 667*0fca6ea1SDimitry Andric if (Dtor->isVirtual()) { 668*0fca6ea1SDimitry Andric Name = getMangledCtorDtor(M, Dtor_Deleting); 669*0fca6ea1SDimitry Andric auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal( 670*0fca6ea1SDimitry Andric Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, 671*0fca6ea1SDimitry Andric D, *Access, getFlags(WeakDef)); 672*0fca6ea1SDimitry Andric Ctx.Verifier->verify(VirtualGR, VirtualFA); 673*0fca6ea1SDimitry Andric } 674*0fca6ea1SDimitry Andric 675*0fca6ea1SDimitry Andric continue; 676*0fca6ea1SDimitry Andric } 677*0fca6ea1SDimitry Andric 678*0fca6ea1SDimitry Andric // Though abstract methods can map to exports, this is generally unexpected. 679*0fca6ea1SDimitry Andric // Except in the case of destructors. Only ignore pure virtuals after 680*0fca6ea1SDimitry Andric // checking if the member function was a destructor. 681*0fca6ea1SDimitry Andric if (M->isPureVirtual()) 682*0fca6ea1SDimitry Andric continue; 683*0fca6ea1SDimitry Andric 684*0fca6ea1SDimitry Andric std::string Name = getMangledName(M); 685*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 686*0fca6ea1SDimitry Andric GlobalRecord::Kind::Function, Avail, M, 687*0fca6ea1SDimitry Andric *Access, getFlags(WeakDef)); 688*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 689*0fca6ea1SDimitry Andric } 690*0fca6ea1SDimitry Andric 691*0fca6ea1SDimitry Andric if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 692*0fca6ea1SDimitry Andric if (!Templ->isExplicitInstantiationOrSpecialization()) 693*0fca6ea1SDimitry Andric return true; 694*0fca6ea1SDimitry Andric } 695*0fca6ea1SDimitry Andric 696*0fca6ea1SDimitry Andric using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>; 697*0fca6ea1SDimitry Andric using var_range = iterator_range<var_iter>; 698*0fca6ea1SDimitry Andric for (const auto *Var : var_range(D->decls())) { 699*0fca6ea1SDimitry Andric // Skip const static member variables. 700*0fca6ea1SDimitry Andric // \code 701*0fca6ea1SDimitry Andric // struct S { 702*0fca6ea1SDimitry Andric // static const int x = 0; 703*0fca6ea1SDimitry Andric // }; 704*0fca6ea1SDimitry Andric // \endcode 705*0fca6ea1SDimitry Andric if (Var->isStaticDataMember() && Var->hasInit()) 706*0fca6ea1SDimitry Andric continue; 707*0fca6ea1SDimitry Andric 708*0fca6ea1SDimitry Andric // Skip unexported var decls. 709*0fca6ea1SDimitry Andric if (!isExported(Var)) 710*0fca6ea1SDimitry Andric continue; 711*0fca6ea1SDimitry Andric 712*0fca6ea1SDimitry Andric const std::string Name = getMangledName(Var); 713*0fca6ea1SDimitry Andric const auto Access = getAccessForDecl(Var); 714*0fca6ea1SDimitry Andric if (!Access) 715*0fca6ea1SDimitry Andric return true; 716*0fca6ea1SDimitry Andric const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var); 717*0fca6ea1SDimitry Andric const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak; 718*0fca6ea1SDimitry Andric 719*0fca6ea1SDimitry Andric auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 720*0fca6ea1SDimitry Andric GlobalRecord::Kind::Variable, Avail, D, 721*0fca6ea1SDimitry Andric *Access, getFlags(WeakDef)); 722*0fca6ea1SDimitry Andric Ctx.Verifier->verify(GR, FA); 723*0fca6ea1SDimitry Andric } 724*0fca6ea1SDimitry Andric 725*0fca6ea1SDimitry Andric return true; 726*0fca6ea1SDimitry Andric } 727*0fca6ea1SDimitry Andric 728*0fca6ea1SDimitry Andric } // namespace clang::installapi 729