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