xref: /src/contrib/llvm-project/clang/lib/InstallAPI/Visitor.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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