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