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