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