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. 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 auto [ObjCIVR, FA] = 160 Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC); 161 Ctx.Verifier->verify(ObjCIVR, FA, SuperClass); 162 } 163 } 164 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 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 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 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 303 static bool hasVTable(const CXXRecordDecl *D) { 304 // Check if vtable symbols should be emitted, only dynamic classes need 305 // vtables. 306 if (!D->hasDefinition() || !D->isDynamicClass()) 307 return false; 308 309 assert(D->isExternallyVisible() && "Should be externally visible"); 310 assert(D->isCompleteDefinition() && "Only works on complete definitions"); 311 312 const CXXMethodDecl *KeyFunctionD = 313 D->getASTContext().getCurrentKeyFunction(D); 314 // If this class has a key function, then there is a vtable, possibly internal 315 // though. 316 if (KeyFunctionD) { 317 switch (KeyFunctionD->getTemplateSpecializationKind()) { 318 case TSK_Undeclared: 319 case TSK_ExplicitSpecialization: 320 case TSK_ImplicitInstantiation: 321 case TSK_ExplicitInstantiationDefinition: 322 return true; 323 case TSK_ExplicitInstantiationDeclaration: 324 llvm_unreachable( 325 "Unexpected TemplateSpecializationKind for key function"); 326 } 327 } else if (D->isAbstract()) { 328 // If the class is abstract and it doesn't have a key function, it is a 329 // 'pure' virtual class. It doesn't need a vtable. 330 return false; 331 } 332 333 switch (D->getTemplateSpecializationKind()) { 334 case TSK_Undeclared: 335 case TSK_ExplicitSpecialization: 336 case TSK_ImplicitInstantiation: 337 return false; 338 339 case TSK_ExplicitInstantiationDeclaration: 340 case TSK_ExplicitInstantiationDefinition: 341 return true; 342 } 343 344 llvm_unreachable("Invalid TemplateSpecializationKind!"); 345 } 346 347 static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) { 348 assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable"); 349 assert(D->isExternallyVisible() && "Record should be externally visible"); 350 if (D->getVisibility() == HiddenVisibility) 351 return CXXLinkage::PrivateLinkage; 352 353 const CXXMethodDecl *KeyFunctionD = 354 D->getASTContext().getCurrentKeyFunction(D); 355 if (KeyFunctionD) { 356 // If this class has a key function, use that to determine the 357 // linkage of the vtable. 358 switch (KeyFunctionD->getTemplateSpecializationKind()) { 359 case TSK_Undeclared: 360 case TSK_ExplicitSpecialization: 361 if (isInlined(KeyFunctionD)) 362 return CXXLinkage::LinkOnceODRLinkage; 363 return CXXLinkage::ExternalLinkage; 364 case TSK_ImplicitInstantiation: 365 llvm_unreachable("No external vtable for implicit instantiations"); 366 case TSK_ExplicitInstantiationDefinition: 367 return CXXLinkage::WeakODRLinkage; 368 case TSK_ExplicitInstantiationDeclaration: 369 llvm_unreachable( 370 "Unexpected TemplateSpecializationKind for key function"); 371 } 372 } 373 374 switch (D->getTemplateSpecializationKind()) { 375 case TSK_Undeclared: 376 case TSK_ExplicitSpecialization: 377 case TSK_ImplicitInstantiation: 378 return CXXLinkage::LinkOnceODRLinkage; 379 case TSK_ExplicitInstantiationDeclaration: 380 case TSK_ExplicitInstantiationDefinition: 381 return CXXLinkage::WeakODRLinkage; 382 } 383 384 llvm_unreachable("Invalid TemplateSpecializationKind!"); 385 } 386 387 static bool isRTTIWeakDef(const CXXRecordDecl *D) { 388 if (D->hasAttr<WeakAttr>()) 389 return true; 390 391 if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr) 392 return true; 393 394 if (D->isDynamicClass()) 395 return getVTableLinkage(D) != CXXLinkage::ExternalLinkage; 396 397 return false; 398 } 399 400 static bool hasRTTI(const CXXRecordDecl *D) { 401 if (!D->getASTContext().getLangOpts().RTTI) 402 return false; 403 404 if (!D->hasDefinition()) 405 return false; 406 407 if (!D->isDynamicClass()) 408 return false; 409 410 // Don't emit weak-def RTTI information. InstallAPI cannot reliably determine 411 // if the final binary will have those weak defined RTTI symbols. This depends 412 // on the optimization level and if the class has been instantiated and used. 413 // 414 // Luckily, the Apple static linker doesn't need those weak defined RTTI 415 // symbols for linking. They are only needed by the runtime linker. That means 416 // they can be safely dropped. 417 if (isRTTIWeakDef(D)) 418 return false; 419 420 return true; 421 } 422 423 std::string 424 InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const { 425 SmallString<256> Name; 426 raw_svector_ostream NameStream(Name); 427 MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream); 428 429 return getBackendMangledName(Name); 430 } 431 432 std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const { 433 SmallString<256> Name; 434 raw_svector_ostream NameStream(Name); 435 MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream); 436 437 return getBackendMangledName(Name); 438 } 439 440 std::string 441 InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const { 442 SmallString<256> Name; 443 raw_svector_ostream NameStream(Name); 444 MC->mangleCXXVTable(D, NameStream); 445 446 return getBackendMangledName(Name); 447 } 448 449 std::string 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 463 std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D, 464 int Type) const { 465 SmallString<256> Name; 466 raw_svector_ostream NameStream(Name); 467 GlobalDecl GD; 468 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) 469 GD = GlobalDecl(Ctor, CXXCtorType(Type)); 470 else { 471 const auto *Dtor = cast<CXXDestructorDecl>(D); 472 GD = GlobalDecl(Dtor, CXXDtorType(Type)); 473 } 474 MC->mangleName(GD, NameStream); 475 return getBackendMangledName(Name); 476 } 477 478 void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D, 479 const AvailabilityInfo &Avail, 480 const HeaderType Access, 481 bool EmittedVTable) { 482 if (hasVTable(D)) { 483 EmittedVTable = true; 484 const CXXLinkage VTableLinkage = getVTableLinkage(D); 485 if (VTableLinkage == CXXLinkage::ExternalLinkage || 486 VTableLinkage == CXXLinkage::WeakODRLinkage) { 487 const std::string Name = getMangledCXXVTableName(D); 488 const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage; 489 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 490 GlobalRecord::Kind::Variable, Avail, 491 D, Access, getFlags(WeakDef)); 492 Ctx.Verifier->verify(GR, FA); 493 if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) { 494 VTableContextBase *VTable = D->getASTContext().getVTableContext(); 495 auto AddThunk = [&](GlobalDecl GD) { 496 const ItaniumVTableContext::ThunkInfoVectorTy *Thunks = 497 VTable->getThunkInfo(GD); 498 if (!Thunks) 499 return; 500 501 for (const auto &Thunk : *Thunks) { 502 const std::string Name = 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 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