Path: blob/main/contrib/llvm-project/clang/lib/InstallAPI/Visitor.cpp
35233 views
//===- Visitor.cpp ---------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/InstallAPI/Visitor.h"9#include "clang/AST/Availability.h"10#include "clang/AST/ParentMapContext.h"11#include "clang/AST/VTableBuilder.h"12#include "clang/Basic/Linkage.h"13#include "clang/InstallAPI/DylibVerifier.h"14#include "clang/InstallAPI/FrontendRecords.h"15#include "llvm/ADT/SmallString.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/IR/DataLayout.h"18#include "llvm/IR/Mangler.h"1920using namespace llvm;21using namespace llvm::MachO;2223namespace {24enum class CXXLinkage {25ExternalLinkage,26LinkOnceODRLinkage,27WeakODRLinkage,28PrivateLinkage,29};30}3132namespace clang::installapi {3334// Exported NamedDecl needs to have external linkage and35// default visibility from LinkageComputer.36static bool isExported(const NamedDecl *D) {37auto LV = D->getLinkageAndVisibility();38return isExternallyVisible(LV.getLinkage()) &&39(LV.getVisibility() == DefaultVisibility);40}4142static bool isInlined(const FunctionDecl *D) {43bool HasInlineAttribute = false;44bool NoCXXAttr =45(!D->getASTContext().getLangOpts().CPlusPlus &&46!D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&47!D->hasAttr<DLLExportAttr>());4849// Check all redeclarations to find an inline attribute or keyword.50for (const auto *RD : D->redecls()) {51if (!RD->isInlined())52continue;53HasInlineAttribute = true;54if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>()))55continue;56if (RD->doesThisDeclarationHaveABody() &&57RD->isInlineDefinitionExternallyVisible())58return false;59}6061if (!HasInlineAttribute)62return false;6364return true;65}6667static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal = false) {68SymbolFlags Result = SymbolFlags::None;69if (WeakDef)70Result |= SymbolFlags::WeakDefined;71if (ThreadLocal)72Result |= SymbolFlags::ThreadLocalValue;7374return Result;75}7677void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) {78if (ASTCtx.getDiagnostics().hasErrorOccurred())79return;8081auto *D = ASTCtx.getTranslationUnitDecl();82TraverseDecl(D);83}8485std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const {86SmallString<256> Name;87if (MC->shouldMangleDeclName(D)) {88raw_svector_ostream NStream(Name);89MC->mangleName(D, NStream);90} else91Name += D->getNameAsString();9293return getBackendMangledName(Name);94}9596std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const {97SmallString<256> FinalName;98Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout));99return std::string(FinalName);100}101102std::optional<HeaderType>103InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const {104SourceLocation Loc = D->getLocation();105if (Loc.isInvalid())106return std::nullopt;107108// If the loc refers to a macro expansion, InstallAPI needs to first get the109// file location of the expansion.110auto FileLoc = SrcMgr.getFileLoc(Loc);111FileID ID = SrcMgr.getFileID(FileLoc);112if (ID.isInvalid())113return std::nullopt;114115const FileEntry *FE = SrcMgr.getFileEntryForID(ID);116if (!FE)117return std::nullopt;118119auto Header = Ctx.findAndRecordFile(FE, PP);120if (!Header.has_value())121return std::nullopt;122123HeaderType Access = Header.value();124assert(Access != HeaderType::Unknown && "unexpected access level for global");125return Access;126}127128/// 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) {133for (; D != nullptr; D = D->getSuperClass())134if (D->hasAttr<ObjCExceptionAttr>())135return true;136137return false;138}139void InstallAPIVisitor::recordObjCInstanceVariables(140const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass,141const llvm::iterator_range<142DeclContext::specific_decl_iterator<ObjCIvarDecl>>143Ivars) {144RecordLinkage Linkage = RecordLinkage::Exported;145const RecordLinkage ContainerLinkage = Record->getLinkage();146// If fragile, set to unknown.147if (ASTCtx.getLangOpts().ObjCRuntime.isFragile())148Linkage = RecordLinkage::Unknown;149// Linkage should be inherited from container.150else if (ContainerLinkage != RecordLinkage::Unknown)151Linkage = ContainerLinkage;152for (const auto *IV : Ivars) {153auto Access = getAccessForDecl(IV);154if (!Access)155continue;156StringRef Name = IV->getName();157const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);158auto AC = IV->getCanonicalAccessControl();159auto [ObjCIVR, FA] =160Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);161Ctx.Verifier->verify(ObjCIVR, FA, SuperClass);162}163}164165bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {166// Skip forward declaration for classes (@class)167if (!D->isThisDeclarationADefinition())168return true;169170// Skip over declarations that access could not be collected for.171auto Access = getAccessForDecl(D);172if (!Access)173return true;174175StringRef Name = D->getObjCRuntimeNameAsString();176const RecordLinkage Linkage =177isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;178const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);179const bool IsEHType =180(!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&181hasObjCExceptionAttribute(D));182183auto [Class, FA] =184Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);185Ctx.Verifier->verify(Class, FA);186187// Get base class.188StringRef SuperClassName;189if (const auto *SuperClass = D->getSuperClass())190SuperClassName = SuperClass->getObjCRuntimeNameAsString();191192recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(),193D->ivars());194return true;195}196197bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {198StringRef CategoryName = D->getName();199// Skip over declarations that access could not be collected for.200auto Access = getAccessForDecl(D);201if (!Access)202return true;203const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);204const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();205const StringRef InterfaceName = InterfaceD->getName();206207ObjCCategoryRecord *CategoryRecord =208Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, Avail, D, *Access)209.first;210recordObjCInstanceVariables(D->getASTContext(), CategoryRecord, InterfaceName,211D->ivars());212return true;213}214215bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {216// Skip function parameters.217if (isa<ParmVarDecl>(D))218return true;219220// Skip variables in records. They are handled separately for C++.221if (D->getDeclContext()->isRecord())222return true;223224// Skip anything inside functions or methods.225if (!D->isDefinedOutsideFunctionOrMethod())226return true;227228// If this is a template but not specialization or instantiation, skip.229if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&230D->getTemplateSpecializationKind() == TSK_Undeclared)231return true;232233// Skip over declarations that access could not collected for.234auto Access = getAccessForDecl(D);235if (!Access)236return true;237238const RecordLinkage Linkage =239isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;240const bool WeakDef = D->hasAttr<WeakAttr>();241const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;242const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);243auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage,244GlobalRecord::Kind::Variable, Avail, D,245*Access, getFlags(WeakDef, ThreadLocal));246Ctx.Verifier->verify(GR, FA);247return true;248}249250bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {251if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {252// Skip member function in class templates.253if (M->getParent()->getDescribedClassTemplate() != nullptr)254return true;255256// Skip methods in CXX RecordDecls.257for (const DynTypedNode &P : D->getASTContext().getParents(*M)) {258if (P.get<CXXRecordDecl>())259return true;260}261262// Skip CXX ConstructorDecls and DestructorDecls.263if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))264return true;265}266267// Skip templated functions.268switch (D->getTemplatedKind()) {269case FunctionDecl::TK_NonTemplate:270case FunctionDecl::TK_DependentNonTemplate:271break;272case FunctionDecl::TK_MemberSpecialization:273case FunctionDecl::TK_FunctionTemplateSpecialization:274if (auto *TempInfo = D->getTemplateSpecializationInfo()) {275if (!TempInfo->isExplicitInstantiationOrSpecialization())276return true;277}278break;279case FunctionDecl::TK_FunctionTemplate:280case FunctionDecl::TK_DependentFunctionTemplateSpecialization:281return true;282}283284auto Access = getAccessForDecl(D);285if (!Access)286return true;287auto Name = getMangledName(D);288const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);289const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==290TSK_ExplicitInstantiationDeclaration;291const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();292const bool Inlined = isInlined(D);293const RecordLinkage Linkage = (Inlined || !isExported(D))294? RecordLinkage::Internal295: RecordLinkage::Exported;296auto [GR, FA] =297Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail,298D, *Access, getFlags(WeakDef), Inlined);299Ctx.Verifier->verify(GR, FA);300return true;301}302303static bool hasVTable(const CXXRecordDecl *D) {304// Check if vtable symbols should be emitted, only dynamic classes need305// vtables.306if (!D->hasDefinition() || !D->isDynamicClass())307return false;308309assert(D->isExternallyVisible() && "Should be externally visible");310assert(D->isCompleteDefinition() && "Only works on complete definitions");311312const CXXMethodDecl *KeyFunctionD =313D->getASTContext().getCurrentKeyFunction(D);314// If this class has a key function, then there is a vtable, possibly internal315// though.316if (KeyFunctionD) {317switch (KeyFunctionD->getTemplateSpecializationKind()) {318case TSK_Undeclared:319case TSK_ExplicitSpecialization:320case TSK_ImplicitInstantiation:321case TSK_ExplicitInstantiationDefinition:322return true;323case TSK_ExplicitInstantiationDeclaration:324llvm_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.330return false;331}332333switch (D->getTemplateSpecializationKind()) {334case TSK_Undeclared:335case TSK_ExplicitSpecialization:336case TSK_ImplicitInstantiation:337return false;338339case TSK_ExplicitInstantiationDeclaration:340case TSK_ExplicitInstantiationDefinition:341return true;342}343344llvm_unreachable("Invalid TemplateSpecializationKind!");345}346347static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {348assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable");349assert(D->isExternallyVisible() && "Record should be externally visible");350if (D->getVisibility() == HiddenVisibility)351return CXXLinkage::PrivateLinkage;352353const CXXMethodDecl *KeyFunctionD =354D->getASTContext().getCurrentKeyFunction(D);355if (KeyFunctionD) {356// If this class has a key function, use that to determine the357// linkage of the vtable.358switch (KeyFunctionD->getTemplateSpecializationKind()) {359case TSK_Undeclared:360case TSK_ExplicitSpecialization:361if (isInlined(KeyFunctionD))362return CXXLinkage::LinkOnceODRLinkage;363return CXXLinkage::ExternalLinkage;364case TSK_ImplicitInstantiation:365llvm_unreachable("No external vtable for implicit instantiations");366case TSK_ExplicitInstantiationDefinition:367return CXXLinkage::WeakODRLinkage;368case TSK_ExplicitInstantiationDeclaration:369llvm_unreachable(370"Unexpected TemplateSpecializationKind for key function");371}372}373374switch (D->getTemplateSpecializationKind()) {375case TSK_Undeclared:376case TSK_ExplicitSpecialization:377case TSK_ImplicitInstantiation:378return CXXLinkage::LinkOnceODRLinkage;379case TSK_ExplicitInstantiationDeclaration:380case TSK_ExplicitInstantiationDefinition:381return CXXLinkage::WeakODRLinkage;382}383384llvm_unreachable("Invalid TemplateSpecializationKind!");385}386387static bool isRTTIWeakDef(const CXXRecordDecl *D) {388if (D->hasAttr<WeakAttr>())389return true;390391if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr)392return true;393394if (D->isDynamicClass())395return getVTableLinkage(D) != CXXLinkage::ExternalLinkage;396397return false;398}399400static bool hasRTTI(const CXXRecordDecl *D) {401if (!D->getASTContext().getLangOpts().RTTI)402return false;403404if (!D->hasDefinition())405return false;406407if (!D->isDynamicClass())408return false;409410// 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.417if (isRTTIWeakDef(D))418return false;419420return true;421}422423std::string424InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const {425SmallString<256> Name;426raw_svector_ostream NameStream(Name);427MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream);428429return getBackendMangledName(Name);430}431432std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const {433SmallString<256> Name;434raw_svector_ostream NameStream(Name);435MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream);436437return getBackendMangledName(Name);438}439440std::string441InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const {442SmallString<256> Name;443raw_svector_ostream NameStream(Name);444MC->mangleCXXVTable(D, NameStream);445446return getBackendMangledName(Name);447}448449std::string InstallAPIVisitor::getMangledCXXThunk(450const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const {451SmallString<256> Name;452raw_svector_ostream NameStream(Name);453const auto *Method = cast<CXXMethodDecl>(D.getDecl());454if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))455MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk, ElideOverrideInfo,456NameStream);457else458MC->mangleThunk(Method, Thunk, ElideOverrideInfo, NameStream);459460return getBackendMangledName(Name);461}462463std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D,464int Type) const {465SmallString<256> Name;466raw_svector_ostream NameStream(Name);467GlobalDecl GD;468if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D))469GD = GlobalDecl(Ctor, CXXCtorType(Type));470else {471const auto *Dtor = cast<CXXDestructorDecl>(D);472GD = GlobalDecl(Dtor, CXXDtorType(Type));473}474MC->mangleName(GD, NameStream);475return getBackendMangledName(Name);476}477478void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,479const AvailabilityInfo &Avail,480const HeaderType Access,481bool EmittedVTable) {482if (hasVTable(D)) {483EmittedVTable = true;484const CXXLinkage VTableLinkage = getVTableLinkage(D);485if (VTableLinkage == CXXLinkage::ExternalLinkage ||486VTableLinkage == CXXLinkage::WeakODRLinkage) {487const std::string Name = getMangledCXXVTableName(D);488const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;489auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,490GlobalRecord::Kind::Variable, Avail,491D, Access, getFlags(WeakDef));492Ctx.Verifier->verify(GR, FA);493if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {494VTableContextBase *VTable = D->getASTContext().getVTableContext();495auto AddThunk = [&](GlobalDecl GD) {496const ItaniumVTableContext::ThunkInfoVectorTy *Thunks =497VTable->getThunkInfo(GD);498if (!Thunks)499return;500501for (const auto &Thunk : *Thunks) {502const std::string Name =503getMangledCXXThunk(GD, Thunk, /*ElideOverrideInfo=*/true);504auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,505GlobalRecord::Kind::Function,506Avail, GD.getDecl(), Access);507Ctx.Verifier->verify(GR, FA);508}509};510511for (const auto *Method : D->methods()) {512if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual())513continue;514515if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) {516// Skip default destructor.517if (Dtor->isDefaulted())518continue;519AddThunk({Dtor, Dtor_Deleting});520AddThunk({Dtor, Dtor_Complete});521} else522AddThunk(Method);523}524}525}526}527528if (!EmittedVTable)529return;530531if (hasRTTI(D)) {532std::string Name = getMangledCXXRTTI(D);533auto [GR, FA] =534Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,535GlobalRecord::Kind::Variable, Avail, D, Access);536Ctx.Verifier->verify(GR, FA);537538Name = getMangledCXXRTTIName(D);539auto [NamedGR, NamedFA] =540Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,541GlobalRecord::Kind::Variable, Avail, D, Access);542Ctx.Verifier->verify(NamedGR, NamedFA);543}544545for (const auto &It : D->bases()) {546const CXXRecordDecl *Base =547cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl());548const auto BaseAccess = getAccessForDecl(Base);549if (!BaseAccess)550continue;551const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base);552emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true);553}554}555556bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {557if (!D->isCompleteDefinition())558return true;559560// Skip templated classes.561if (D->getDescribedClassTemplate() != nullptr)562return true;563564// Skip partial templated classes too.565if (isa<ClassTemplatePartialSpecializationDecl>(D))566return true;567568auto Access = getAccessForDecl(D);569if (!Access)570return true;571const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);572573// Check whether to emit the vtable/rtti symbols.574if (isExported(D))575emitVTableSymbols(D, Avail, *Access);576577TemplateSpecializationKind ClassSK = TSK_Undeclared;578bool KeepInlineAsWeak = false;579if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {580ClassSK = Templ->getTemplateSpecializationKind();581if (ClassSK == TSK_ExplicitInstantiationDeclaration)582KeepInlineAsWeak = true;583}584585// Record the class methods.586for (const auto *M : D->methods()) {587// Inlined methods are usually not emitted, except when it comes from a588// specialized template.589bool WeakDef = false;590if (isInlined(M)) {591if (!KeepInlineAsWeak)592continue;593594WeakDef = true;595}596597if (!isExported(M))598continue;599600switch (M->getTemplateSpecializationKind()) {601case TSK_Undeclared:602case TSK_ExplicitSpecialization:603break;604case TSK_ImplicitInstantiation:605continue;606case TSK_ExplicitInstantiationDeclaration:607if (ClassSK == TSK_ExplicitInstantiationDeclaration)608WeakDef = true;609break;610case TSK_ExplicitInstantiationDefinition:611WeakDef = true;612break;613}614615if (!M->isUserProvided())616continue;617618// Methods that are deleted are not exported.619if (M->isDeleted())620continue;621622const auto Access = getAccessForDecl(M);623if (!Access)624return true;625const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M);626627if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) {628// Defaulted constructors are not exported.629if (Ctor->isDefaulted())630continue;631632std::string Name = getMangledCtorDtor(M, Ctor_Base);633auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,634GlobalRecord::Kind::Function, Avail,635D, *Access, getFlags(WeakDef));636Ctx.Verifier->verify(GR, FA);637638if (!D->isAbstract()) {639std::string Name = getMangledCtorDtor(M, Ctor_Complete);640auto [GR, FA] = Ctx.Slice->addGlobal(641Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,642D, *Access, getFlags(WeakDef));643Ctx.Verifier->verify(GR, FA);644}645646continue;647}648649if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) {650// Defaulted destructors are not exported.651if (Dtor->isDefaulted())652continue;653654std::string Name = getMangledCtorDtor(M, Dtor_Base);655auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,656GlobalRecord::Kind::Function, Avail,657D, *Access, getFlags(WeakDef));658Ctx.Verifier->verify(GR, FA);659660Name = getMangledCtorDtor(M, Dtor_Complete);661auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(662Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,663*Access, getFlags(WeakDef));664Ctx.Verifier->verify(CompleteGR, CompleteFA);665666if (Dtor->isVirtual()) {667Name = getMangledCtorDtor(M, Dtor_Deleting);668auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(669Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,670D, *Access, getFlags(WeakDef));671Ctx.Verifier->verify(VirtualGR, VirtualFA);672}673674continue;675}676677// 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.680if (M->isPureVirtual())681continue;682683std::string Name = getMangledName(M);684auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,685GlobalRecord::Kind::Function, Avail, M,686*Access, getFlags(WeakDef));687Ctx.Verifier->verify(GR, FA);688}689690if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {691if (!Templ->isExplicitInstantiationOrSpecialization())692return true;693}694695using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>;696using var_range = iterator_range<var_iter>;697for (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// \endcode704if (Var->isStaticDataMember() && Var->hasInit())705continue;706707// Skip unexported var decls.708if (!isExported(Var))709continue;710711const std::string Name = getMangledName(Var);712const auto Access = getAccessForDecl(Var);713if (!Access)714return true;715const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);716const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;717718auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,719GlobalRecord::Kind::Variable, Avail, D,720*Access, getFlags(WeakDef));721Ctx.Verifier->verify(GR, FA);722}723724return true;725}726727} // namespace clang::installapi728729730