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