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