xref: /llvm-project/clang/lib/InstallAPI/Visitor.cpp (revision f2794ccede6d32a6b5ef7a376ced420331e2be27)
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   auto [Category, FA] = Ctx.Slice->addObjCCategory(InterfaceName, CategoryName,
209                                                    Avail, D, *Access);
210   recordObjCInstanceVariables(D->getASTContext(), Category, 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 seperately 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 (auto 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
450 InstallAPIVisitor::getMangledCXXThunk(const GlobalDecl &D,
451                                       const ThunkInfo &Thunk) const {
452   SmallString<256> Name;
453   raw_svector_ostream NameStream(Name);
454   const auto *Method = cast<CXXMethodDecl>(D.getDecl());
455   if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))
456     MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk.This, NameStream);
457   else
458     MC->mangleThunk(Method, Thunk, 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 = getMangledCXXThunk(GD, Thunk);
503             auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
504                                                  GlobalRecord::Kind::Function,
505                                                  Avail, GD.getDecl(), Access);
506             Ctx.Verifier->verify(GR, FA);
507           }
508         };
509 
510         for (const auto *Method : D->methods()) {
511           if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual())
512             continue;
513 
514           if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
515             // Skip default destructor.
516             if (Dtor->isDefaulted())
517               continue;
518             AddThunk({Dtor, Dtor_Deleting});
519             AddThunk({Dtor, Dtor_Complete});
520           } else
521             AddThunk(Method);
522         }
523       }
524     }
525   }
526 
527   if (!EmittedVTable)
528     return;
529 
530   if (hasRTTI(D)) {
531     std::string Name = getMangledCXXRTTI(D);
532     auto [GR, FA] =
533         Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
534                              GlobalRecord::Kind::Variable, Avail, D, Access);
535     Ctx.Verifier->verify(GR, FA);
536 
537     Name = getMangledCXXRTTIName(D);
538     auto [NamedGR, NamedFA] =
539         Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
540                              GlobalRecord::Kind::Variable, Avail, D, Access);
541     Ctx.Verifier->verify(NamedGR, NamedFA);
542   }
543 
544   for (const auto &It : D->bases()) {
545     const CXXRecordDecl *Base =
546         cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl());
547     const auto BaseAccess = getAccessForDecl(Base);
548     if (!BaseAccess)
549       continue;
550     const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base);
551     emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true);
552   }
553 }
554 
555 bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
556   if (!D->isCompleteDefinition())
557     return true;
558 
559   // Skip templated classes.
560   if (D->getDescribedClassTemplate() != nullptr)
561     return true;
562 
563   // Skip partial templated classes too.
564   if (isa<ClassTemplatePartialSpecializationDecl>(D))
565     return true;
566 
567   auto Access = getAccessForDecl(D);
568   if (!Access)
569     return true;
570   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
571 
572   // Check whether to emit the vtable/rtti symbols.
573   if (isExported(D))
574     emitVTableSymbols(D, Avail, *Access);
575 
576   TemplateSpecializationKind ClassSK = TSK_Undeclared;
577   bool KeepInlineAsWeak = false;
578   if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
579     ClassSK = Templ->getTemplateSpecializationKind();
580     if (ClassSK == TSK_ExplicitInstantiationDeclaration)
581       KeepInlineAsWeak = true;
582   }
583 
584   // Record the class methods.
585   for (const auto *M : D->methods()) {
586     // Inlined methods are usually not emitted, except when it comes from a
587     // specialized template.
588     bool WeakDef = false;
589     if (isInlined(M)) {
590       if (!KeepInlineAsWeak)
591         continue;
592 
593       WeakDef = true;
594     }
595 
596     if (!isExported(M))
597       continue;
598 
599     switch (M->getTemplateSpecializationKind()) {
600     case TSK_Undeclared:
601     case TSK_ExplicitSpecialization:
602       break;
603     case TSK_ImplicitInstantiation:
604       continue;
605     case TSK_ExplicitInstantiationDeclaration:
606       if (ClassSK == TSK_ExplicitInstantiationDeclaration)
607         WeakDef = true;
608       break;
609     case TSK_ExplicitInstantiationDefinition:
610       WeakDef = true;
611       break;
612     }
613 
614     if (!M->isUserProvided())
615       continue;
616 
617     // Methods that are deleted are not exported.
618     if (M->isDeleted())
619       continue;
620 
621     const auto Access = getAccessForDecl(M);
622     if (!Access)
623       return true;
624     const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M);
625 
626     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) {
627       // Defaulted constructors are not exported.
628       if (Ctor->isDefaulted())
629         continue;
630 
631       std::string Name = getMangledCtorDtor(M, Ctor_Base);
632       auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
633                                            GlobalRecord::Kind::Function, Avail,
634                                            D, *Access, getFlags(WeakDef));
635       Ctx.Verifier->verify(GR, FA);
636 
637       if (!D->isAbstract()) {
638         std::string Name = getMangledCtorDtor(M, Ctor_Complete);
639         auto [GR, FA] = Ctx.Slice->addGlobal(
640             Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
641             D, *Access, getFlags(WeakDef));
642         Ctx.Verifier->verify(GR, FA);
643       }
644 
645       continue;
646     }
647 
648     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) {
649       // Defaulted destructors are not exported.
650       if (Dtor->isDefaulted())
651         continue;
652 
653       std::string Name = getMangledCtorDtor(M, Dtor_Base);
654       auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
655                                            GlobalRecord::Kind::Function, Avail,
656                                            D, *Access, getFlags(WeakDef));
657       Ctx.Verifier->verify(GR, FA);
658 
659       Name = getMangledCtorDtor(M, Dtor_Complete);
660       auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(
661           Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,
662           *Access, getFlags(WeakDef));
663       Ctx.Verifier->verify(CompleteGR, CompleteFA);
664 
665       if (Dtor->isVirtual()) {
666         Name = getMangledCtorDtor(M, Dtor_Deleting);
667         auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(
668             Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
669             D, *Access, getFlags(WeakDef));
670         Ctx.Verifier->verify(VirtualGR, VirtualFA);
671       }
672 
673       continue;
674     }
675 
676     // Though abstract methods can map to exports, this is generally unexpected.
677     // Except in the case of destructors. Only ignore pure virtuals after
678     // checking if the member function was a destructor.
679     if (M->isPureVirtual())
680       continue;
681 
682     std::string Name = getMangledName(M);
683     auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
684                                          GlobalRecord::Kind::Function, Avail, D,
685                                          *Access, getFlags(WeakDef));
686     Ctx.Verifier->verify(GR, FA);
687   }
688 
689   if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
690     if (!Templ->isExplicitInstantiationOrSpecialization())
691       return true;
692   }
693 
694   using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>;
695   using var_range = iterator_range<var_iter>;
696   for (const auto *Var : var_range(D->decls())) {
697     // Skip const static member variables.
698     // \code
699     // struct S {
700     //   static const int x = 0;
701     // };
702     // \endcode
703     if (Var->isStaticDataMember() && Var->hasInit())
704       continue;
705 
706     // Skip unexported var decls.
707     if (!isExported(Var))
708       continue;
709 
710     const std::string Name = getMangledName(Var);
711     const auto Access = getAccessForDecl(Var);
712     if (!Access)
713       return true;
714     const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);
715     const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;
716 
717     auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
718                                          GlobalRecord::Kind::Variable, Avail, D,
719                                          *Access, getFlags(WeakDef));
720     Ctx.Verifier->verify(GR, FA);
721   }
722 
723   return true;
724 }
725 
726 } // namespace clang::installapi
727