1 //===- Visitor.cpp ---------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "clang/InstallAPI/Visitor.h"
10 #include "clang/AST/Availability.h"
11 #include "clang/AST/ParentMapContext.h"
12 #include "clang/AST/VTableBuilder.h"
13 #include "clang/Basic/Linkage.h"
14 #include "clang/InstallAPI/DylibVerifier.h"
15 #include "clang/InstallAPI/FrontendRecords.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/IR/DataLayout.h"
18 #include "llvm/IR/Mangler.h"
19
20 using namespace llvm;
21 using namespace llvm::MachO;
22
23 namespace {
24 enum class CXXLinkage {
25 ExternalLinkage,
26 LinkOnceODRLinkage,
27 WeakODRLinkage,
28 PrivateLinkage,
29 };
30 }
31
32 namespace clang::installapi {
33
34 // Exported NamedDecl needs to have external linkage and
35 // default visibility from LinkageComputer.
isExported(const NamedDecl * D)36 static bool isExported(const NamedDecl *D) {
37 auto LV = D->getLinkageAndVisibility();
38 return isExternallyVisible(LV.getLinkage()) &&
39 (LV.getVisibility() == DefaultVisibility);
40 }
41
isInlined(const FunctionDecl * D)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
getFlags(bool WeakDef,bool ThreadLocal=false)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
HandleTranslationUnit(ASTContext & ASTCtx)77 void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) {
78 if (ASTCtx.getDiagnostics().hasErrorOccurred())
79 return;
80
81 auto *D = ASTCtx.getTranslationUnitDecl();
82 TraverseDecl(D);
83 }
84
getMangledName(const NamedDecl * D) const85 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
getBackendMangledName(Twine Name) const96 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>
getAccessForDecl(const NamedDecl * D) const103 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.
hasObjCExceptionAttribute(const ObjCInterfaceDecl * D)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 }
recordObjCInstanceVariables(const ASTContext & ASTCtx,ObjCContainerRecord * Record,StringRef SuperClass,const llvm::iterator_range<DeclContext::specific_decl_iterator<ObjCIvarDecl>> Ivars)139 void InstallAPIVisitor::recordObjCInstanceVariables(
140 const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass,
141 const llvm::iterator_range<
142 DeclContext::specific_decl_iterator<ObjCIvarDecl>>
143 Ivars) {
144 RecordLinkage Linkage = RecordLinkage::Exported;
145 const RecordLinkage ContainerLinkage = Record->getLinkage();
146 // If fragile, set to unknown.
147 if (ASTCtx.getLangOpts().ObjCRuntime.isFragile())
148 Linkage = RecordLinkage::Unknown;
149 // Linkage should be inherited from container.
150 else if (ContainerLinkage != RecordLinkage::Unknown)
151 Linkage = ContainerLinkage;
152 for (const auto *IV : Ivars) {
153 auto Access = getAccessForDecl(IV);
154 if (!Access)
155 continue;
156 StringRef Name = IV->getName();
157 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV);
158 auto AC = IV->getCanonicalAccessControl();
159 auto [ObjCIVR, FA] =
160 Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC);
161 Ctx.Verifier->verify(ObjCIVR, FA, SuperClass);
162 }
163 }
164
VisitObjCInterfaceDecl(const ObjCInterfaceDecl * D)165 bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) {
166 // Skip forward declaration for classes (@class)
167 if (!D->isThisDeclarationADefinition())
168 return true;
169
170 // Skip over declarations that access could not be collected for.
171 auto Access = getAccessForDecl(D);
172 if (!Access)
173 return true;
174
175 StringRef Name = D->getObjCRuntimeNameAsString();
176 const RecordLinkage Linkage =
177 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
178 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
179 const bool IsEHType =
180 (!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&
181 hasObjCExceptionAttribute(D));
182
183 auto [Class, FA] =
184 Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);
185 Ctx.Verifier->verify(Class, FA);
186
187 // Get base class.
188 StringRef SuperClassName;
189 if (const auto *SuperClass = D->getSuperClass())
190 SuperClassName = SuperClass->getObjCRuntimeNameAsString();
191
192 recordObjCInstanceVariables(D->getASTContext(), Class, Class->getName(),
193 D->ivars());
194 return true;
195 }
196
VisitObjCCategoryDecl(const ObjCCategoryDecl * D)197 bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) {
198 StringRef CategoryName = D->getName();
199 // Skip over declarations that access could not be collected for.
200 auto Access = getAccessForDecl(D);
201 if (!Access)
202 return true;
203 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
204 const ObjCInterfaceDecl *InterfaceD = D->getClassInterface();
205 const StringRef InterfaceName = InterfaceD->getName();
206
207 ObjCCategoryRecord *CategoryRecord =
208 Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, Avail, D, *Access)
209 .first;
210 recordObjCInstanceVariables(D->getASTContext(), CategoryRecord, InterfaceName,
211 D->ivars());
212 return true;
213 }
214
VisitVarDecl(const VarDecl * D)215 bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) {
216 // Skip function parameters.
217 if (isa<ParmVarDecl>(D))
218 return true;
219
220 // Skip variables in records. They are handled separately for C++.
221 if (D->getDeclContext()->isRecord())
222 return true;
223
224 // Skip anything inside functions or methods.
225 if (!D->isDefinedOutsideFunctionOrMethod())
226 return true;
227
228 // If this is a template but not specialization or instantiation, skip.
229 if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&
230 D->getTemplateSpecializationKind() == TSK_Undeclared)
231 return true;
232
233 // Skip over declarations that access could not collected for.
234 auto Access = getAccessForDecl(D);
235 if (!Access)
236 return true;
237
238 const RecordLinkage Linkage =
239 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;
240 const bool WeakDef = D->hasAttr<WeakAttr>();
241 const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None;
242 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
243 auto [GR, FA] = Ctx.Slice->addGlobal(getMangledName(D), Linkage,
244 GlobalRecord::Kind::Variable, Avail, D,
245 *Access, getFlags(WeakDef, ThreadLocal));
246 Ctx.Verifier->verify(GR, FA);
247 return true;
248 }
249
VisitFunctionDecl(const FunctionDecl * D)250 bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) {
251 if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) {
252 // Skip member function in class templates.
253 if (M->getParent()->getDescribedClassTemplate() != nullptr)
254 return true;
255
256 // Skip methods in CXX RecordDecls.
257 for (const DynTypedNode &P : D->getASTContext().getParents(*M)) {
258 if (P.get<CXXRecordDecl>())
259 return true;
260 }
261
262 // Skip CXX ConstructorDecls and DestructorDecls.
263 if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M))
264 return true;
265 }
266
267 // Skip templated functions.
268 switch (D->getTemplatedKind()) {
269 case FunctionDecl::TK_NonTemplate:
270 case FunctionDecl::TK_DependentNonTemplate:
271 break;
272 case FunctionDecl::TK_MemberSpecialization:
273 case FunctionDecl::TK_FunctionTemplateSpecialization:
274 if (auto *TempInfo = D->getTemplateSpecializationInfo()) {
275 if (!TempInfo->isExplicitInstantiationOrSpecialization())
276 return true;
277 }
278 break;
279 case FunctionDecl::TK_FunctionTemplate:
280 case FunctionDecl::TK_DependentFunctionTemplateSpecialization:
281 return true;
282 }
283
284 auto Access = getAccessForDecl(D);
285 if (!Access)
286 return true;
287 auto Name = getMangledName(D);
288 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
289 const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==
290 TSK_ExplicitInstantiationDeclaration;
291 const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>();
292 const bool Inlined = isInlined(D);
293 const RecordLinkage Linkage = (Inlined || !isExported(D))
294 ? RecordLinkage::Internal
295 : RecordLinkage::Exported;
296 auto [GR, FA] =
297 Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail,
298 D, *Access, getFlags(WeakDef), Inlined);
299 Ctx.Verifier->verify(GR, FA);
300 return true;
301 }
302
hasVTable(const CXXRecordDecl * D)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
getVTableLinkage(const CXXRecordDecl * D)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
isRTTIWeakDef(const CXXRecordDecl * D)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
hasRTTI(const CXXRecordDecl * D)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
getMangledCXXRTTIName(const CXXRecordDecl * D) const424 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
getMangledCXXRTTI(const CXXRecordDecl * D) const432 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
getMangledCXXVTableName(const CXXRecordDecl * D) const441 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
getMangledCXXThunk(const GlobalDecl & D,const ThunkInfo & Thunk,bool ElideOverrideInfo) const449 std::string InstallAPIVisitor::getMangledCXXThunk(
450 const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const {
451 SmallString<256> Name;
452 raw_svector_ostream NameStream(Name);
453 const auto *Method = cast<CXXMethodDecl>(D.getDecl());
454 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method))
455 MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk, ElideOverrideInfo,
456 NameStream);
457 else
458 MC->mangleThunk(Method, Thunk, ElideOverrideInfo, NameStream);
459
460 return getBackendMangledName(Name);
461 }
462
getMangledCtorDtor(const CXXMethodDecl * D,int Type) const463 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
emitVTableSymbols(const CXXRecordDecl * D,const AvailabilityInfo & Avail,const HeaderType Access,bool EmittedVTable)478 void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,
479 const AvailabilityInfo &Avail,
480 const HeaderType Access,
481 bool EmittedVTable) {
482 if (hasVTable(D)) {
483 EmittedVTable = true;
484 const CXXLinkage VTableLinkage = getVTableLinkage(D);
485 if (VTableLinkage == CXXLinkage::ExternalLinkage ||
486 VTableLinkage == CXXLinkage::WeakODRLinkage) {
487 const std::string Name = getMangledCXXVTableName(D);
488 const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage;
489 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
490 GlobalRecord::Kind::Variable, Avail,
491 D, Access, getFlags(WeakDef));
492 Ctx.Verifier->verify(GR, FA);
493 if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) {
494 VTableContextBase *VTable = D->getASTContext().getVTableContext();
495 auto AddThunk = [&](GlobalDecl GD) {
496 const ItaniumVTableContext::ThunkInfoVectorTy *Thunks =
497 VTable->getThunkInfo(GD);
498 if (!Thunks)
499 return;
500
501 for (const auto &Thunk : *Thunks) {
502 const std::string Name =
503 getMangledCXXThunk(GD, Thunk, /*ElideOverrideInfo=*/true);
504 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
505 GlobalRecord::Kind::Function,
506 Avail, GD.getDecl(), Access);
507 Ctx.Verifier->verify(GR, FA);
508 }
509 };
510
511 for (const auto *Method : D->methods()) {
512 if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual())
513 continue;
514
515 if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) {
516 // Skip default destructor.
517 if (Dtor->isDefaulted())
518 continue;
519 AddThunk({Dtor, Dtor_Deleting});
520 AddThunk({Dtor, Dtor_Complete});
521 } else
522 AddThunk(Method);
523 }
524 }
525 }
526 }
527
528 if (!EmittedVTable)
529 return;
530
531 if (hasRTTI(D)) {
532 std::string Name = getMangledCXXRTTI(D);
533 auto [GR, FA] =
534 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
535 GlobalRecord::Kind::Variable, Avail, D, Access);
536 Ctx.Verifier->verify(GR, FA);
537
538 Name = getMangledCXXRTTIName(D);
539 auto [NamedGR, NamedFA] =
540 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
541 GlobalRecord::Kind::Variable, Avail, D, Access);
542 Ctx.Verifier->verify(NamedGR, NamedFA);
543 }
544
545 for (const auto &It : D->bases()) {
546 const CXXRecordDecl *Base =
547 cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl());
548 const auto BaseAccess = getAccessForDecl(Base);
549 if (!BaseAccess)
550 continue;
551 const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base);
552 emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true);
553 }
554 }
555
VisitCXXRecordDecl(const CXXRecordDecl * D)556 bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) {
557 if (!D->isCompleteDefinition())
558 return true;
559
560 // Skip templated classes.
561 if (D->getDescribedClassTemplate() != nullptr)
562 return true;
563
564 // Skip partial templated classes too.
565 if (isa<ClassTemplatePartialSpecializationDecl>(D))
566 return true;
567
568 auto Access = getAccessForDecl(D);
569 if (!Access)
570 return true;
571 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D);
572
573 // Check whether to emit the vtable/rtti symbols.
574 if (isExported(D))
575 emitVTableSymbols(D, Avail, *Access);
576
577 TemplateSpecializationKind ClassSK = TSK_Undeclared;
578 bool KeepInlineAsWeak = false;
579 if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
580 ClassSK = Templ->getTemplateSpecializationKind();
581 if (ClassSK == TSK_ExplicitInstantiationDeclaration)
582 KeepInlineAsWeak = true;
583 }
584
585 // Record the class methods.
586 for (const auto *M : D->methods()) {
587 // Inlined methods are usually not emitted, except when it comes from a
588 // specialized template.
589 bool WeakDef = false;
590 if (isInlined(M)) {
591 if (!KeepInlineAsWeak)
592 continue;
593
594 WeakDef = true;
595 }
596
597 if (!isExported(M))
598 continue;
599
600 switch (M->getTemplateSpecializationKind()) {
601 case TSK_Undeclared:
602 case TSK_ExplicitSpecialization:
603 break;
604 case TSK_ImplicitInstantiation:
605 continue;
606 case TSK_ExplicitInstantiationDeclaration:
607 if (ClassSK == TSK_ExplicitInstantiationDeclaration)
608 WeakDef = true;
609 break;
610 case TSK_ExplicitInstantiationDefinition:
611 WeakDef = true;
612 break;
613 }
614
615 if (!M->isUserProvided())
616 continue;
617
618 // Methods that are deleted are not exported.
619 if (M->isDeleted())
620 continue;
621
622 const auto Access = getAccessForDecl(M);
623 if (!Access)
624 return true;
625 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M);
626
627 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) {
628 // Defaulted constructors are not exported.
629 if (Ctor->isDefaulted())
630 continue;
631
632 std::string Name = getMangledCtorDtor(M, Ctor_Base);
633 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
634 GlobalRecord::Kind::Function, Avail,
635 D, *Access, getFlags(WeakDef));
636 Ctx.Verifier->verify(GR, FA);
637
638 if (!D->isAbstract()) {
639 std::string Name = getMangledCtorDtor(M, Ctor_Complete);
640 auto [GR, FA] = Ctx.Slice->addGlobal(
641 Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
642 D, *Access, getFlags(WeakDef));
643 Ctx.Verifier->verify(GR, FA);
644 }
645
646 continue;
647 }
648
649 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) {
650 // Defaulted destructors are not exported.
651 if (Dtor->isDefaulted())
652 continue;
653
654 std::string Name = getMangledCtorDtor(M, Dtor_Base);
655 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
656 GlobalRecord::Kind::Function, Avail,
657 D, *Access, getFlags(WeakDef));
658 Ctx.Verifier->verify(GR, FA);
659
660 Name = getMangledCtorDtor(M, Dtor_Complete);
661 auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(
662 Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,
663 *Access, getFlags(WeakDef));
664 Ctx.Verifier->verify(CompleteGR, CompleteFA);
665
666 if (Dtor->isVirtual()) {
667 Name = getMangledCtorDtor(M, Dtor_Deleting);
668 auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(
669 Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,
670 D, *Access, getFlags(WeakDef));
671 Ctx.Verifier->verify(VirtualGR, VirtualFA);
672 }
673
674 continue;
675 }
676
677 // Though abstract methods can map to exports, this is generally unexpected.
678 // Except in the case of destructors. Only ignore pure virtuals after
679 // checking if the member function was a destructor.
680 if (M->isPureVirtual())
681 continue;
682
683 std::string Name = getMangledName(M);
684 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
685 GlobalRecord::Kind::Function, Avail, M,
686 *Access, getFlags(WeakDef));
687 Ctx.Verifier->verify(GR, FA);
688 }
689
690 if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
691 if (!Templ->isExplicitInstantiationOrSpecialization())
692 return true;
693 }
694
695 using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>;
696 using var_range = iterator_range<var_iter>;
697 for (const auto *Var : var_range(D->decls())) {
698 // Skip const static member variables.
699 // \code
700 // struct S {
701 // static const int x = 0;
702 // };
703 // \endcode
704 if (Var->isStaticDataMember() && Var->hasInit())
705 continue;
706
707 // Skip unexported var decls.
708 if (!isExported(Var))
709 continue;
710
711 const std::string Name = getMangledName(Var);
712 const auto Access = getAccessForDecl(Var);
713 if (!Access)
714 return true;
715 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var);
716 const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak;
717
718 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,
719 GlobalRecord::Kind::Variable, Avail, D,
720 *Access, getFlags(WeakDef));
721 Ctx.Verifier->verify(GR, FA);
722 }
723
724 return true;
725 }
726
727 } // namespace clang::installapi
728