xref: /llvm-project/clang/lib/InstallAPI/Visitor.cpp (revision 2c93beccdf8e026534a737eddaf8f5f26f3a23c3)
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/Frontend.h"
15 #include "llvm/ADT/SmallString.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     Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
160   }
161 }
162 
163 bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
164   // Skip forward declaration for classes (@class)
165   if (!D->isThisDeclarationADefinition())
166     return true;
167 
168   // Skip over declarations that access could not be collected for.
169   auto Access = getAccessForDecl(D);
170   if (!Access)
171     return true;
172 
173   StringRef Name = D->getObjCRuntimeNameAsString();
174   const RecordLinkage Linkage =
175       isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
176   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
177   const bool IsEHType =
178       (!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
179        hasObjCExceptionAttribute(D));
180 
181   ObjCInterfaceRecord *Class =
182       Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
183 
184   // Get base class.
185   StringRef SuperClassName;
186   if (const auto *SuperClass = D->getSuperClass())
187     SuperClassName = SuperClass->getObjCRuntimeNameAsString();
188 
189   recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName,
190                               D->ivars());
191   return true;
192 }
193 
194 bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
195   StringRef CategoryName = D->getName();
196   // Skip over declarations that access could not be collected for.
197   auto Access = getAccessForDecl(D);
198   if (!Access)
199     return true;
200   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
201   const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
202   const StringRef InterfaceName = InterfaceD->getName();
203 
204   ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory(
205       InterfaceName, CategoryName, Avail, D, *Access);
206   recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName,
207                               D->ivars());
208   return true;
209 }
210 
211 bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
212   // Skip function parameters.
213   if (isa<ParmVarDecl>(D))
214     return true;
215 
216   // Skip variables in records. They are handled seperately for C++.
217   if (D->getDeclContext()->isRecord())
218     return true;
219 
220   // Skip anything inside functions or methods.
221   if (!D->isDefinedOutsideFunctionOrMethod())
222     return true;
223 
224   // If this is a template but not specialization or instantiation, skip.
225   if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&
226       D->getTemplateSpecializationKind() == TSK_Undeclared)
227     return true;
228 
229   // Skip over declarations that access could not collected for.
230   auto Access = getAccessForDecl(D);
231   if (!Access)
232     return true;
233 
234   const RecordLinkage Linkage =
235       isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
236   const bool WeakDef = D->hasAttr<WeakAttr>();
237   const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
238   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
239   Ctx.Slice->addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable,
240                        Avail, D, *Access, getFlags(WeakDef, ThreadLocal));
241   return true;
242 }
243 
244 bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
245   if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {
246     // Skip member function in class templates.
247     if (M->getParent()->getDescribedClassTemplate() != nullptr)
248       return true;
249 
250     // Skip methods in CXX RecordDecls.
251     for (auto P : D->getASTContext().getParents(*M)) {
252       if (P.get<CXXRecordDecl>())
253         return true;
254     }
255 
256     // Skip CXX ConstructorDecls and DestructorDecls.
257     if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))
258       return true;
259   }
260 
261   // Skip templated functions.
262   switch (D->getTemplatedKind()) {
263   case FunctionDecl::TK_NonTemplate:
264   case FunctionDecl::TK_DependentNonTemplate:
265     break;
266   case FunctionDecl::TK_MemberSpecialization:
267   case FunctionDecl::TK_FunctionTemplateSpecialization:
268     if (auto *TempInfo = D->getTemplateSpecializationInfo()) {
269       if (!TempInfo->isExplicitInstantiationOrSpecialization())
270         return true;
271     }
272     break;
273   case FunctionDecl::TK_FunctionTemplate:
274   case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
275     return true;
276   }
277 
278   auto Access = getAccessForDecl(D);
279   if (!Access)
280     return true;
281   auto Name = getMangledName(D);
282   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
283   const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==
284                                      TSK_ExplicitInstantiationDeclaration;
285   const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();
286   const bool Inlined = isInlined(D);
287   const RecordLinkage Linkage = (Inlined || !isExported(D))
288                                     ? RecordLinkage::Internal
289                                     : RecordLinkage::Exported;
290   Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D,
291                        *Access, getFlags(WeakDef), Inlined);
292   return true;
293 }
294 
295 static bool hasVTable(const CXXRecordDecl *D) {
296   // Check if vtable symbols should be emitted, only dynamic classes need
297   // vtables.
298   if (!D->hasDefinition() || !D->isDynamicClass())
299     return false;
300 
301   assert(D->isExternallyVisible() && "Should be externally visible");
302   assert(D->isCompleteDefinition() && "Only works on complete definitions");
303 
304   const CXXMethodDecl *KeyFunctionD =
305       D->getASTContext().getCurrentKeyFunction(D);
306   // If this class has a key function, then there is a vtable, possibly internal
307   // though.
308   if (KeyFunctionD) {
309     switch (KeyFunctionD->getTemplateSpecializationKind()) {
310     case TSK_Undeclared:
311     case TSK_ExplicitSpecialization:
312     case TSK_ImplicitInstantiation:
313     case TSK_ExplicitInstantiationDefinition:
314       return true;
315     case TSK_ExplicitInstantiationDeclaration:
316       llvm_unreachable(
317           "Unexpected TemplateSpecializationKind for key function");
318     }
319   } else if (D->isAbstract()) {
320     // If the class is abstract and it doesn't have a key function, it is a
321     // 'pure' virtual class. It doesn't need a vtable.
322     return false;
323   }
324 
325   switch (D->getTemplateSpecializationKind()) {
326   case TSK_Undeclared:
327   case TSK_ExplicitSpecialization:
328   case TSK_ImplicitInstantiation:
329     return false;
330 
331   case TSK_ExplicitInstantiationDeclaration:
332   case TSK_ExplicitInstantiationDefinition:
333     return true;
334   }
335 
336   llvm_unreachable("Invalid TemplateSpecializationKind!");
337 }
338 
339 static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) {
340   assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable");
341   assert(D->isExternallyVisible() && "Record should be externally visible");
342   if (D->getVisibility() == HiddenVisibility)
343     return CXXLinkage::PrivateLinkage;
344 
345   const CXXMethodDecl *KeyFunctionD =
346       D->getASTContext().getCurrentKeyFunction(D);
347   if (KeyFunctionD) {
348     // If this class has a key function, use that to determine the
349     // linkage of the vtable.
350     switch (KeyFunctionD->getTemplateSpecializationKind()) {
351     case TSK_Undeclared:
352     case TSK_ExplicitSpecialization:
353       if (isInlined(KeyFunctionD))
354         return CXXLinkage::LinkOnceODRLinkage;
355       return CXXLinkage::ExternalLinkage;
356     case TSK_ImplicitInstantiation:
357       llvm_unreachable("No external vtable for implicit instantiations");
358     case TSK_ExplicitInstantiationDefinition:
359       return CXXLinkage::WeakODRLinkage;
360     case TSK_ExplicitInstantiationDeclaration:
361       llvm_unreachable(
362           "Unexpected TemplateSpecializationKind for key function");
363     }
364   }
365 
366   switch (D->getTemplateSpecializationKind()) {
367   case TSK_Undeclared:
368   case TSK_ExplicitSpecialization:
369   case TSK_ImplicitInstantiation:
370     return CXXLinkage::LinkOnceODRLinkage;
371   case TSK_ExplicitInstantiationDeclaration:
372   case TSK_ExplicitInstantiationDefinition:
373     return CXXLinkage::WeakODRLinkage;
374   }
375 
376   llvm_unreachable("Invalid TemplateSpecializationKind!");
377 }
378 
379 static bool isRTTIWeakDef(const CXXRecordDecl *D) {
380   if (D->hasAttr<WeakAttr>())
381     return true;
382 
383   if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr)
384     return true;
385 
386   if (D->isDynamicClass())
387     return getVTableLinkage(D) != CXXLinkage::ExternalLinkage;
388 
389   return false;
390 }
391 
392 static bool hasRTTI(const CXXRecordDecl *D) {
393   if (!D->getASTContext().getLangOpts().RTTI)
394     return false;
395 
396   if (!D->hasDefinition())
397     return false;
398 
399   if (!D->isDynamicClass())
400     return false;
401 
402   // Don't emit weak-def RTTI information. InstallAPI cannot reliably determine
403   // if the final binary will have those weak defined RTTI symbols. This depends
404   // on the optimization level and if the class has been instantiated and used.
405   //
406   // Luckily, the Apple static linker doesn't need those weak defined RTTI
407   // symbols for linking. They are only needed by the runtime linker. That means
408   // they can be safely dropped.
409   if (isRTTIWeakDef(D))
410     return false;
411 
412   return true;
413 }
414 
415 std::string
416 InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const {
417   SmallString<256> Name;
418   raw_svector_ostream NameStream(Name);
419   MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream);
420 
421   return getBackendMangledName(Name);
422 }
423 
424 std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const {
425   SmallString<256> Name;
426   raw_svector_ostream NameStream(Name);
427   MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream);
428 
429   return getBackendMangledName(Name);
430 }
431 
432 std::string
433 InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const {
434   SmallString<256> Name;
435   raw_svector_ostream NameStream(Name);
436   MC->mangleCXXVTable(D, NameStream);
437 
438   return getBackendMangledName(Name);
439 }
440 
441 std::string
442 InstallAPIVisitor::getMangledCXXThunk(const GlobalDecl &D,
443                                       const ThunkInfo &Thunk) const {
444   SmallString<256> Name;
445   raw_svector_ostream NameStream(Name);
446   const auto *Method = cast<CXXMethodDecl>(D.getDecl());
447   if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))
448     MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk.This, NameStream);
449   else
450     MC->mangleThunk(Method, Thunk, NameStream);
451 
452   return getBackendMangledName(Name);
453 }
454 
455 std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D,
456                                                   int Type) const {
457   SmallString<256> Name;
458   raw_svector_ostream NameStream(Name);
459   GlobalDecl GD;
460   if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D))
461     GD = GlobalDecl(Ctor, CXXCtorType(Type));
462   else {
463     const auto *Dtor = cast<CXXDestructorDecl>(D);
464     GD = GlobalDecl(Dtor, CXXDtorType(Type));
465   }
466   MC->mangleName(GD, NameStream);
467   return getBackendMangledName(Name);
468 }
469 
470 void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
471                                           const AvailabilityInfo &Avail,
472                                           const HeaderType Access,
473                                           bool EmittedVTable) {
474   if (hasVTable(D)) {
475     EmittedVTable = true;
476     const CXXLinkage VTableLinkage = getVTableLinkage(D);
477     if (VTableLinkage == CXXLinkage::ExternalLinkage ||
478         VTableLinkage == CXXLinkage::WeakODRLinkage) {
479       const std::string Name = getMangledCXXVTableName(D);
480       const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;
481       Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
482                            GlobalRecord::Kind::Variable, Avail, D, Access,
483                            getFlags(WeakDef));
484       if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {
485         VTableContextBase *VTable = D->getASTContext().getVTableContext();
486         auto AddThunk = [&](GlobalDecl GD) {
487           const ItaniumVTableContext::ThunkInfoVectorTy *Thunks =
488               VTable->getThunkInfo(GD);
489           if (!Thunks)
490             return;
491 
492           for (const auto &Thunk : *Thunks) {
493             const std::string Name = getMangledCXXThunk(GD, Thunk);
494             Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
495                                  GlobalRecord::Kind::Function, Avail,
496                                  GD.getDecl(), Access);
497           }
498         };
499 
500         for (const auto *Method : D->methods()) {
501           if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual())
502             continue;
503 
504           if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
505             // Skip default destructor.
506             if (Dtor->isDefaulted())
507               continue;
508             AddThunk({Dtor, Dtor_Deleting});
509             AddThunk({Dtor, Dtor_Complete});
510           } else
511             AddThunk(Method);
512         }
513       }
514     }
515   }
516 
517   if (!EmittedVTable)
518     return;
519 
520   if (hasRTTI(D)) {
521     std::string Name = getMangledCXXRTTI(D);
522     Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
523                          GlobalRecord::Kind::Variable, Avail, D, Access);
524 
525     Name = getMangledCXXRTTIName(D);
526     Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
527                          GlobalRecord::Kind::Variable, Avail, D, Access);
528   }
529 
530   for (const auto &It : D->bases()) {
531     const CXXRecordDecl *Base =
532         cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl());
533     const auto BaseAccess = getAccessForDecl(Base);
534     if (!BaseAccess)
535       continue;
536     const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base);
537     emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true);
538   }
539 }
540 
541 bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
542   if (!D->isCompleteDefinition())
543     return true;
544 
545   // Skip templated classes.
546   if (D->getDescribedClassTemplate() != nullptr)
547     return true;
548 
549   // Skip partial templated classes too.
550   if (isa<ClassTemplatePartialSpecializationDecl>(D))
551     return true;
552 
553   auto Access = getAccessForDecl(D);
554   if (!Access)
555     return true;
556   const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
557 
558   // Check whether to emit the vtable/rtti symbols.
559   if (isExported(D))
560     emitVTableSymbols(D, Avail, *Access);
561 
562   TemplateSpecializationKind ClassSK = TSK_Undeclared;
563   bool KeepInlineAsWeak = false;
564   if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
565     ClassSK = Templ->getTemplateSpecializationKind();
566     if (ClassSK == TSK_ExplicitInstantiationDeclaration)
567       KeepInlineAsWeak = true;
568   }
569 
570   // Record the class methods.
571   for (const auto *M : D->methods()) {
572     // Inlined methods are usually not emitted, except when it comes from a
573     // specialized template.
574     bool WeakDef = false;
575     if (isInlined(M)) {
576       if (!KeepInlineAsWeak)
577         continue;
578 
579       WeakDef = true;
580     }
581 
582     if (!isExported(M))
583       continue;
584 
585     switch (M->getTemplateSpecializationKind()) {
586     case TSK_Undeclared:
587     case TSK_ExplicitSpecialization:
588       break;
589     case TSK_ImplicitInstantiation:
590       continue;
591     case TSK_ExplicitInstantiationDeclaration:
592       if (ClassSK == TSK_ExplicitInstantiationDeclaration)
593         WeakDef = true;
594       break;
595     case TSK_ExplicitInstantiationDefinition:
596       WeakDef = true;
597       break;
598     }
599 
600     if (!M->isUserProvided())
601       continue;
602 
603     // Methods that are deleted are not exported.
604     if (M->isDeleted())
605       continue;
606 
607     const auto Access = getAccessForDecl(M);
608     if (!Access)
609       return true;
610     const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M);
611 
612     if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) {
613       // Defaulted constructors are not exported.
614       if (Ctor->isDefaulted())
615         continue;
616 
617       std::string Name = getMangledCtorDtor(M, Ctor_Base);
618       Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
619                            GlobalRecord::Kind::Function, Avail, D, *Access,
620                            getFlags(WeakDef));
621 
622       if (!D->isAbstract()) {
623         std::string Name = getMangledCtorDtor(M, Ctor_Complete);
624         Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
625                              GlobalRecord::Kind::Function, Avail, D, *Access,
626                              getFlags(WeakDef));
627       }
628 
629       continue;
630     }
631 
632     if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) {
633       // Defaulted destructors are not exported.
634       if (Dtor->isDefaulted())
635         continue;
636 
637       std::string Name = getMangledCtorDtor(M, Dtor_Base);
638       Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
639                            GlobalRecord::Kind::Function, Avail, D, *Access,
640                            getFlags(WeakDef));
641 
642       Name = getMangledCtorDtor(M, Dtor_Complete);
643       Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
644                            GlobalRecord::Kind::Function, Avail, D, *Access,
645                            getFlags(WeakDef));
646 
647       if (Dtor->isVirtual()) {
648         Name = getMangledCtorDtor(M, Dtor_Deleting);
649         Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
650                              GlobalRecord::Kind::Function, Avail, D, *Access,
651                              getFlags(WeakDef));
652       }
653 
654       continue;
655     }
656 
657     // Though abstract methods can map to exports, this is generally unexpected.
658     // Except in the case of destructors. Only ignore pure virtuals after
659     // checking if the member function was a destructor.
660     if (M->isPureVirtual())
661       continue;
662 
663     std::string Name = getMangledName(M);
664     Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
665                          GlobalRecord::Kind::Function, Avail, D, *Access,
666                          getFlags(WeakDef));
667   }
668 
669   if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
670     if (!Templ->isExplicitInstantiationOrSpecialization())
671       return true;
672   }
673 
674   using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>;
675   using var_range = iterator_range<var_iter>;
676   for (const auto *Var : var_range(D->decls())) {
677     // Skip const static member variables.
678     // \code
679     // struct S {
680     //   static const int x = 0;
681     // };
682     // \endcode
683     if (Var->isStaticDataMember() && Var->hasInit())
684       continue;
685 
686     // Skip unexported var decls.
687     if (!isExported(Var))
688       continue;
689 
690     const std::string Name = getMangledName(Var);
691     const auto Access = getAccessForDecl(Var);
692     if (!Access)
693       return true;
694     const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);
695     const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;
696 
697     Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
698                          GlobalRecord::Kind::Variable, Avail, D, *Access,
699                          getFlags(WeakDef));
700   }
701 
702   return true;
703 }
704 
705 } // namespace clang::installapi
706