brintos

brintos / llvm-project-archived public Read only

0
0
Text · 24.1 KiB · 53fbc36 Raw
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