xref: /freebsd/contrib/llvm-project/clang/lib/InstallAPI/Visitor.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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/StringRef.h"
17 #include "llvm/IR/DataLayout.h"
18 #include "llvm/IR/Mangler.h"
19 
20 using namespace llvm;
21 using namespace llvm::MachO;
22 
23 namespace {
24 enum class CXXLinkage {
25   ExternalLinkage,
26   LinkOnceODRLinkage,
27   WeakODRLinkage,
28   PrivateLinkage,
29 };
30 }
31 
32 namespace clang::installapi {
33 
34 // Exported NamedDecl needs to have external linkage and
35 // default visibility from LinkageComputer.
36 static bool isExported(const NamedDecl *D) {
37   auto LV = D->getLinkageAndVisibility();
38   return isExternallyVisible(LV.getLinkage()) &&
39          (LV.getVisibility() == DefaultVisibility);
40 }
41 
42 static bool isInlined(const FunctionDecl *D) {
43   bool HasInlineAttribute = false;
44   bool NoCXXAttr =
45       (!D->getASTContext().getLangOpts().CPlusPlus &&
46        !D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&
47        !D->hasAttr<DLLExportAttr>());
48 
49   // Check all redeclarations to find an inline attribute or keyword.
50   for (const auto *RD : D->redecls()) {
51     if (!RD->isInlined())
52       continue;
53     HasInlineAttribute = true;
54     if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>()))
55       continue;
56     if (RD->doesThisDeclarationHaveABody() &&
57         RD->isInlineDefinitionExternallyVisible())
58       return false;
59   }
60 
61   if (!HasInlineAttribute)
62     return false;
63 
64   return true;
65 }
66 
67 static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal = false) {
68   SymbolFlags Result = SymbolFlags::None;
69   if (WeakDef)
70     Result |= SymbolFlags::WeakDefined;
71   if (ThreadLocal)
72     Result |= SymbolFlags::ThreadLocalValue;
73 
74   return Result;
75 }
76 
77 void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) {
78   if (ASTCtx.getDiagnostics().hasErrorOccurred())
79     return;
80 
81   auto *D = ASTCtx.getTranslationUnitDecl();
82   TraverseDecl(D);
83 }
84 
85 std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const {
86   SmallString<256> Name;
87   if (MC->shouldMangleDeclName(D)) {
88     raw_svector_ostream NStream(Name);
89     MC->mangleName(D, NStream);
90   } else
91     Name += D->getNameAsString();
92 
93   return getBackendMangledName(Name);
94 }
95 
96 std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const {
97   SmallString<256> FinalName;
98   Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout));
99   return std::string(FinalName);
100 }
101 
102 std::optional<HeaderType>
103 InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const {
104   SourceLocation Loc = D->getLocation();
105   if (Loc.isInvalid())
106     return std::nullopt;
107 
108   // If the loc refers to a macro expansion, InstallAPI needs to first get the
109   // file location of the expansion.
110   auto FileLoc = SrcMgr.getFileLoc(Loc);
111   FileID ID = SrcMgr.getFileID(FileLoc);
112   if (ID.isInvalid())
113     return std::nullopt;
114 
115   const FileEntry *FE = SrcMgr.getFileEntryForID(ID);
116   if (!FE)
117     return std::nullopt;
118 
119   auto Header = Ctx.findAndRecordFile(FE, PP);
120   if (!Header.has_value())
121     return std::nullopt;
122 
123   HeaderType Access = Header.value();
124   assert(Access != HeaderType::Unknown && "unexpected access level for global");
125   return Access;
126 }
127 
128 /// Check if the interface itself or any of its super classes have an
129 /// exception attribute. InstallAPI needs to export an additional symbol
130 /// ("OBJC_EHTYPE_$CLASS_NAME") if any of the classes have the exception
131 /// attribute.
132 static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) {
133   for (; D != nullptr; D = D->getSuperClass())
134     if (D->hasAttr<ObjCExceptionAttr>())
135       return true;
136 
137   return false;
138 }
139 void InstallAPIVisitor::recordObjCInstanceVariables(
140     const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass,
141     const llvm::iterator_range<
142         DeclContext::specific_decl_iterator<ObjCIvarDecl>>
143         Ivars) {
144   RecordLinkage Linkage = RecordLinkage::Exported;
145   const RecordLinkage ContainerLinkage = Record->getLinkage();
146   // If fragile, set to unknown.
147   if (ASTCtx.getLangOpts().ObjCRuntime.isFragile())
148     Linkage = RecordLinkage::Unknown;
149   // Linkage should be inherited from container.
150   else if (ContainerLinkage != RecordLinkage::Unknown)
151     Linkage = ContainerLinkage;
152   for (const auto *IV : Ivars) {
153     auto Access = getAccessForDecl(IV);
154     if (!Access)
155       continue;
156     StringRef Name = IV->getName();
157     const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
158     auto AC = IV->getCanonicalAccessControl();
159     auto [ObjCIVR, FA] =
160         Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
161     Ctx.Verifier->verify(ObjCIVR, FA, SuperClass);
162   }
163 }
164 
165 bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
166   // Skip forward declaration for classes (@class)
167   if (!D->isThisDeclarationADefinition())
168     return true;
169 
170   // Skip over declarations that access could not be collected for.
171   auto Access = getAccessForDecl(D);
172   if (!Access)
173     return true;
174 
175   StringRef Name = D->getObjCRuntimeNameAsString();
176   const RecordLinkage Linkage =
177       isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
178   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
179   const bool IsEHType =
180       (!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
181        hasObjCExceptionAttribute(D));
182 
183   auto [Class, FA] =
184       Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
185   Ctx.Verifier->verify(Class, FA);
186 
187   // Get base class.
188   StringRef SuperClassName;
189   if (const auto *SuperClass = D->getSuperClass())
190     SuperClassName = SuperClass->getObjCRuntimeNameAsString();
191 
192   recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(),
193                               D->ivars());
194   return true;
195 }
196 
197 bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
198   StringRef CategoryName = D->getName();
199   // Skip over declarations that access could not be collected for.
200   auto Access = getAccessForDecl(D);
201   if (!Access)
202     return true;
203   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
204   const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
205   const StringRef InterfaceName = InterfaceD->getName();
206 
207   ObjCCategoryRecord *CategoryRecord =
208       Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, Avail, D, *Access)
209           .first;
210   recordObjCInstanceVariables(D->getASTContext(), CategoryRecord, InterfaceName,
211                               D->ivars());
212   return true;
213 }
214 
215 bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
216   // Skip function parameters.
217   if (isa<ParmVarDecl>(D))
218     return true;
219 
220   // Skip variables in records. They are handled separately for C++.
221   if (D->getDeclContext()->isRecord())
222     return true;
223 
224   // Skip anything inside functions or methods.
225   if (!D->isDefinedOutsideFunctionOrMethod())
226     return true;
227 
228   // If this is a template but not specialization or instantiation, skip.
229   if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&
230       D->getTemplateSpecializationKind() == TSK_Undeclared)
231     return true;
232 
233   // Skip over declarations that access could not collected for.
234   auto Access = getAccessForDecl(D);
235   if (!Access)
236     return true;
237 
238   const RecordLinkage Linkage =
239       isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
240   const bool WeakDef = D->hasAttr<WeakAttr>();
241   const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
242   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
243   auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage,
244                                        GlobalRecord::Kind::Variable, Avail, D,
245                                        *Access, getFlags(WeakDef, ThreadLocal));
246   Ctx.Verifier->verify(GR, FA);
247   return true;
248 }
249 
250 bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
251   if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {
252     // Skip member function in class templates.
253     if (M->getParent()->getDescribedClassTemplate() != nullptr)
254       return true;
255 
256     // Skip methods in CXX RecordDecls.
257     for (const DynTypedNode &P : D->getASTContext().getParents(*M)) {
258       if (P.get<CXXRecordDecl>())
259         return true;
260     }
261 
262     // Skip CXX ConstructorDecls and DestructorDecls.
263     if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))
264       return true;
265   }
266 
267   // Skip templated functions.
268   switch (D->getTemplatedKind()) {
269   case FunctionDecl::TK_NonTemplate:
270   case FunctionDecl::TK_DependentNonTemplate:
271     break;
272   case FunctionDecl::TK_MemberSpecialization:
273   case FunctionDecl::TK_FunctionTemplateSpecialization:
274     if (auto *TempInfo = D->getTemplateSpecializationInfo()) {
275       if (!TempInfo->isExplicitInstantiationOrSpecialization())
276         return true;
277     }
278     break;
279   case FunctionDecl::TK_FunctionTemplate:
280   case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
281     return true;
282   }
283 
284   auto Access = getAccessForDecl(D);
285   if (!Access)
286     return true;
287   auto Name = getMangledName(D);
288   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
289   const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==
290                                      TSK_ExplicitInstantiationDeclaration;
291   const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();
292   const bool Inlined = isInlined(D);
293   const RecordLinkage Linkage = (Inlined || !isExported(D))
294                                     ? RecordLinkage::Internal
295                                     : RecordLinkage::Exported;
296   auto [GR, FA] =
297       Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail,
298                            D, *Access, getFlags(WeakDef), Inlined);
299   Ctx.Verifier->verify(GR, FA);
300   return true;
301 }
302 
303 static bool hasVTable(const CXXRecordDecl *D) {
304   // Check if vtable symbols should be emitted, only dynamic classes need
305   // vtables.
306   if (!D->hasDefinition() || !D->isDynamicClass())
307     return false;
308 
309   assert(D->isExternallyVisible() && "Should be externally visible");
310   assert(D->isCompleteDefinition() && "Only works on complete definitions");
311 
312   const CXXMethodDecl *KeyFunctionD =
313       D->getASTContext().getCurrentKeyFunction(D);
314   // If this class has a key function, then there is a vtable, possibly internal
315   // though.
316   if (KeyFunctionD) {
317     switch (KeyFunctionD->getTemplateSpecializationKind()) {
318     case TSK_Undeclared:
319     case TSK_ExplicitSpecialization:
320     case TSK_ImplicitInstantiation:
321     case TSK_ExplicitInstantiationDefinition:
322       return true;
323     case TSK_ExplicitInstantiationDeclaration:
324       llvm_unreachable(
325           "Unexpected TemplateSpecializationKind for key function");
326     }
327   } else if (D->isAbstract()) {
328     // If the class is abstract and it doesn't have a key function, it is a
329     // 'pure' virtual class. It doesn't need a vtable.
330     return false;
331   }
332 
333   switch (D->getTemplateSpecializationKind()) {
334   case TSK_Undeclared:
335   case TSK_ExplicitSpecialization:
336   case TSK_ImplicitInstantiation:
337     return false;
338 
339   case TSK_ExplicitInstantiationDeclaration:
340   case TSK_ExplicitInstantiationDefinition:
341     return true;
342   }
343 
344   llvm_unreachable("Invalid TemplateSpecializationKind!");
345 }
346 
347 static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
348   assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable");
349   assert(D->isExternallyVisible() && "Record should be externally visible");
350   if (D->getVisibility() == HiddenVisibility)
351     return CXXLinkage::PrivateLinkage;
352 
353   const CXXMethodDecl *KeyFunctionD =
354       D->getASTContext().getCurrentKeyFunction(D);
355   if (KeyFunctionD) {
356     // If this class has a key function, use that to determine the
357     // linkage of the vtable.
358     switch (KeyFunctionD->getTemplateSpecializationKind()) {
359     case TSK_Undeclared:
360     case TSK_ExplicitSpecialization:
361       if (isInlined(KeyFunctionD))
362         return CXXLinkage::LinkOnceODRLinkage;
363       return CXXLinkage::ExternalLinkage;
364     case TSK_ImplicitInstantiation:
365       llvm_unreachable("No external vtable for implicit instantiations");
366     case TSK_ExplicitInstantiationDefinition:
367       return CXXLinkage::WeakODRLinkage;
368     case TSK_ExplicitInstantiationDeclaration:
369       llvm_unreachable(
370           "Unexpected TemplateSpecializationKind for key function");
371     }
372   }
373 
374   switch (D->getTemplateSpecializationKind()) {
375   case TSK_Undeclared:
376   case TSK_ExplicitSpecialization:
377   case TSK_ImplicitInstantiation:
378     return CXXLinkage::LinkOnceODRLinkage;
379   case TSK_ExplicitInstantiationDeclaration:
380   case TSK_ExplicitInstantiationDefinition:
381     return CXXLinkage::WeakODRLinkage;
382   }
383 
384   llvm_unreachable("Invalid TemplateSpecializationKind!");
385 }
386 
387 static bool isRTTIWeakDef(const CXXRecordDecl *D) {
388   if (D->hasAttr<WeakAttr>())
389     return true;
390 
391   if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr)
392     return true;
393 
394   if (D->isDynamicClass())
395     return getVTableLinkage(D) != CXXLinkage::ExternalLinkage;
396 
397   return false;
398 }
399 
400 static bool hasRTTI(const CXXRecordDecl *D) {
401   if (!D->getASTContext().getLangOpts().RTTI)
402     return false;
403 
404   if (!D->hasDefinition())
405     return false;
406 
407   if (!D->isDynamicClass())
408     return false;
409 
410   // Don't emit weak-def RTTI information. InstallAPI cannot reliably determine
411   // if the final binary will have those weak defined RTTI symbols. This depends
412   // on the optimization level and if the class has been instantiated and used.
413   //
414   // Luckily, the Apple static linker doesn't need those weak defined RTTI
415   // symbols for linking. They are only needed by the runtime linker. That means
416   // they can be safely dropped.
417   if (isRTTIWeakDef(D))
418     return false;
419 
420   return true;
421 }
422 
423 std::string
424 InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const {
425   SmallString<256> Name;
426   raw_svector_ostream NameStream(Name);
427   MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream);
428 
429   return getBackendMangledName(Name);
430 }
431 
432 std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const {
433   SmallString<256> Name;
434   raw_svector_ostream NameStream(Name);
435   MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream);
436 
437   return getBackendMangledName(Name);
438 }
439 
440 std::string
441 InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const {
442   SmallString<256> Name;
443   raw_svector_ostream NameStream(Name);
444   MC->mangleCXXVTable(D, NameStream);
445 
446   return getBackendMangledName(Name);
447 }
448 
449 std::string InstallAPIVisitor::getMangledCXXThunk(
450     const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const {
451   SmallString<256> Name;
452   raw_svector_ostream NameStream(Name);
453   const auto *Method = cast<CXXMethodDecl>(D.getDecl());
454   if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))
455     MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk, ElideOverrideInfo,
456                            NameStream);
457   else
458     MC->mangleThunk(Method, Thunk, ElideOverrideInfo, NameStream);
459 
460   return getBackendMangledName(Name);
461 }
462 
463 std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D,
464                                                   int Type) const {
465   SmallString<256> Name;
466   raw_svector_ostream NameStream(Name);
467   GlobalDecl GD;
468   if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D))
469     GD = GlobalDecl(Ctor, CXXCtorType(Type));
470   else {
471     const auto *Dtor = cast<CXXDestructorDecl>(D);
472     GD = GlobalDecl(Dtor, CXXDtorType(Type));
473   }
474   MC->mangleName(GD, NameStream);
475   return getBackendMangledName(Name);
476 }
477 
478 void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
479                                           const AvailabilityInfo &Avail,
480                                           const HeaderType Access,
481                                           bool EmittedVTable) {
482   if (hasVTable(D)) {
483     EmittedVTable = true;
484     const CXXLinkage VTableLinkage = getVTableLinkage(D);
485     if (VTableLinkage == CXXLinkage::ExternalLinkage ||
486         VTableLinkage == CXXLinkage::WeakODRLinkage) {
487       const std::string Name = getMangledCXXVTableName(D);
488       const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;
489       auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
490                                            GlobalRecord::Kind::Variable, Avail,
491                                            D, Access, getFlags(WeakDef));
492       Ctx.Verifier->verify(GR, FA);
493       if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {
494         VTableContextBase *VTable = D->getASTContext().getVTableContext();
495         auto AddThunk = [&](GlobalDecl GD) {
496           const ItaniumVTableContext::ThunkInfoVectorTy *Thunks =
497               VTable->getThunkInfo(GD);
498           if (!Thunks)
499             return;
500 
501           for (const auto &Thunk : *Thunks) {
502             const std::string Name =
503                 getMangledCXXThunk(GD, Thunk, /*ElideOverrideInfo=*/true);
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