1 //===- Visitor.cpp ---------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/InstallAPI/Visitor.h" 10 #include "clang/AST/Availability.h" 11 #include "clang/AST/ParentMapContext.h" 12 #include "clang/AST/VTableBuilder.h" 13 #include "clang/Basic/Linkage.h" 14 #include "clang/InstallAPI/Frontend.h" 15 #include "llvm/ADT/SmallString.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/IR/DataLayout.h" 18 #include "llvm/IR/Mangler.h" 19 20 using namespace llvm; 21 using namespace llvm::MachO; 22 23 namespace { 24 enum class CXXLinkage { 25 ExternalLinkage, 26 LinkOnceODRLinkage, 27 WeakODRLinkage, 28 PrivateLinkage, 29 }; 30 } 31 32 namespace clang::installapi { 33 34 // Exported NamedDecl needs to have external linkage and 35 // default visibility from LinkageComputer. 36 static bool isExported(const NamedDecl *D) { 37 auto LV = D->getLinkageAndVisibility(); 38 return isExternallyVisible(LV.getLinkage()) && 39 (LV.getVisibility() == DefaultVisibility); 40 } 41 42 static bool isInlined(const FunctionDecl *D) { 43 bool HasInlineAttribute = false; 44 bool NoCXXAttr = 45 (!D->getASTContext().getLangOpts().CPlusPlus && 46 !D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() && 47 !D->hasAttr<DLLExportAttr>()); 48 49 // Check all redeclarations to find an inline attribute or keyword. 50 for (const auto *RD : D->redecls()) { 51 if (!RD->isInlined()) 52 continue; 53 HasInlineAttribute = true; 54 if (!(NoCXXAttr || RD->hasAttr<GNUInlineAttr>())) 55 continue; 56 if (RD->doesThisDeclarationHaveABody() && 57 RD->isInlineDefinitionExternallyVisible()) 58 return false; 59 } 60 61 if (!HasInlineAttribute) 62 return false; 63 64 return true; 65 } 66 67 static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal = false) { 68 SymbolFlags Result = SymbolFlags::None; 69 if (WeakDef) 70 Result |= SymbolFlags::WeakDefined; 71 if (ThreadLocal) 72 Result |= SymbolFlags::ThreadLocalValue; 73 74 return Result; 75 } 76 77 void InstallAPIVisitor::HandleTranslationUnit(ASTContext &ASTCtx) { 78 if (ASTCtx.getDiagnostics().hasErrorOccurred()) 79 return; 80 81 auto *D = ASTCtx.getTranslationUnitDecl(); 82 TraverseDecl(D); 83 } 84 85 std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const { 86 SmallString<256> Name; 87 if (MC->shouldMangleDeclName(D)) { 88 raw_svector_ostream NStream(Name); 89 MC->mangleName(D, NStream); 90 } else 91 Name += D->getNameAsString(); 92 93 return getBackendMangledName(Name); 94 } 95 96 std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const { 97 SmallString<256> FinalName; 98 Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout)); 99 return std::string(FinalName); 100 } 101 102 std::optional<HeaderType> 103 InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const { 104 SourceLocation Loc = D->getLocation(); 105 if (Loc.isInvalid()) 106 return std::nullopt; 107 108 // If the loc refers to a macro expansion, InstallAPI needs to first get the 109 // file location of the expansion. 110 auto FileLoc = SrcMgr.getFileLoc(Loc); 111 FileID ID = SrcMgr.getFileID(FileLoc); 112 if (ID.isInvalid()) 113 return std::nullopt; 114 115 const FileEntry *FE = SrcMgr.getFileEntryForID(ID); 116 if (!FE) 117 return std::nullopt; 118 119 auto Header = Ctx.findAndRecordFile(FE, PP); 120 if (!Header.has_value()) 121 return std::nullopt; 122 123 HeaderType Access = Header.value(); 124 assert(Access != HeaderType::Unknown && "unexpected access level for global"); 125 return Access; 126 } 127 128 /// Check if the interface itself or any of its super classes have an 129 /// exception attribute. InstallAPI needs to export an additional symbol 130 /// ("OBJC_EHTYPE_$CLASS_NAME") if any of the classes have the exception 131 /// attribute. 132 static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D) { 133 for (; D != nullptr; D = D->getSuperClass()) 134 if (D->hasAttr<ObjCExceptionAttr>()) 135 return true; 136 137 return false; 138 } 139 void InstallAPIVisitor::recordObjCInstanceVariables( 140 const ASTContext &ASTCtx, ObjCContainerRecord *Record, StringRef SuperClass, 141 const llvm::iterator_range< 142 DeclContext::specific_decl_iterator<ObjCIvarDecl>> 143 Ivars) { 144 RecordLinkage Linkage = RecordLinkage::Exported; 145 const RecordLinkage ContainerLinkage = Record->getLinkage(); 146 // If fragile, set to unknown. 147 if (ASTCtx.getLangOpts().ObjCRuntime.isFragile()) 148 Linkage = RecordLinkage::Unknown; 149 // Linkage should be inherited from container. 150 else if (ContainerLinkage != RecordLinkage::Unknown) 151 Linkage = ContainerLinkage; 152 for (const auto *IV : Ivars) { 153 auto Access = getAccessForDecl(IV); 154 if (!Access) 155 continue; 156 StringRef Name = IV->getName(); 157 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(IV); 158 auto AC = IV->getCanonicalAccessControl(); 159 Ctx.Slice->addObjCIVar(Record, Name, Linkage, Avail, IV, *Access, AC); 160 } 161 } 162 163 bool InstallAPIVisitor::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { 164 // Skip forward declaration for classes (@class) 165 if (!D->isThisDeclarationADefinition()) 166 return true; 167 168 // Skip over declarations that access could not be collected for. 169 auto Access = getAccessForDecl(D); 170 if (!Access) 171 return true; 172 173 StringRef Name = D->getObjCRuntimeNameAsString(); 174 const RecordLinkage Linkage = 175 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal; 176 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 177 const bool IsEHType = 178 (!D->getASTContext().getLangOpts().ObjCRuntime.isFragile() && 179 hasObjCExceptionAttribute(D)); 180 181 ObjCInterfaceRecord *Class = 182 Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType); 183 184 // Get base class. 185 StringRef SuperClassName; 186 if (const auto *SuperClass = D->getSuperClass()) 187 SuperClassName = SuperClass->getObjCRuntimeNameAsString(); 188 189 recordObjCInstanceVariables(D->getASTContext(), Class, SuperClassName, 190 D->ivars()); 191 return true; 192 } 193 194 bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { 195 StringRef CategoryName = D->getName(); 196 // Skip over declarations that access could not be collected for. 197 auto Access = getAccessForDecl(D); 198 if (!Access) 199 return true; 200 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 201 const ObjCInterfaceDecl *InterfaceD = D->getClassInterface(); 202 const StringRef InterfaceName = InterfaceD->getName(); 203 204 ObjCCategoryRecord *Category = Ctx.Slice->addObjCCategory( 205 InterfaceName, CategoryName, Avail, D, *Access); 206 recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName, 207 D->ivars()); 208 return true; 209 } 210 211 bool InstallAPIVisitor::VisitVarDecl(const VarDecl *D) { 212 // Skip function parameters. 213 if (isa<ParmVarDecl>(D)) 214 return true; 215 216 // Skip variables in records. They are handled seperately for C++. 217 if (D->getDeclContext()->isRecord()) 218 return true; 219 220 // Skip anything inside functions or methods. 221 if (!D->isDefinedOutsideFunctionOrMethod()) 222 return true; 223 224 // If this is a template but not specialization or instantiation, skip. 225 if (D->getASTContext().getTemplateOrSpecializationInfo(D) && 226 D->getTemplateSpecializationKind() == TSK_Undeclared) 227 return true; 228 229 // Skip over declarations that access could not collected for. 230 auto Access = getAccessForDecl(D); 231 if (!Access) 232 return true; 233 234 const RecordLinkage Linkage = 235 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal; 236 const bool WeakDef = D->hasAttr<WeakAttr>(); 237 const bool ThreadLocal = D->getTLSKind() != VarDecl::TLS_None; 238 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 239 Ctx.Slice->addGlobal(getMangledName(D), Linkage, GlobalRecord::Kind::Variable, 240 Avail, D, *Access, getFlags(WeakDef, ThreadLocal)); 241 return true; 242 } 243 244 bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) { 245 if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(D)) { 246 // Skip member function in class templates. 247 if (M->getParent()->getDescribedClassTemplate() != nullptr) 248 return true; 249 250 // Skip methods in CXX RecordDecls. 251 for (auto P : D->getASTContext().getParents(*M)) { 252 if (P.get<CXXRecordDecl>()) 253 return true; 254 } 255 256 // Skip CXX ConstructorDecls and DestructorDecls. 257 if (isa<CXXConstructorDecl>(M) || isa<CXXDestructorDecl>(M)) 258 return true; 259 } 260 261 // Skip templated functions. 262 switch (D->getTemplatedKind()) { 263 case FunctionDecl::TK_NonTemplate: 264 case FunctionDecl::TK_DependentNonTemplate: 265 break; 266 case FunctionDecl::TK_MemberSpecialization: 267 case FunctionDecl::TK_FunctionTemplateSpecialization: 268 if (auto *TempInfo = D->getTemplateSpecializationInfo()) { 269 if (!TempInfo->isExplicitInstantiationOrSpecialization()) 270 return true; 271 } 272 break; 273 case FunctionDecl::TK_FunctionTemplate: 274 case FunctionDecl::TK_DependentFunctionTemplateSpecialization: 275 return true; 276 } 277 278 auto Access = getAccessForDecl(D); 279 if (!Access) 280 return true; 281 auto Name = getMangledName(D); 282 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 283 const bool ExplicitInstantiation = D->getTemplateSpecializationKind() == 284 TSK_ExplicitInstantiationDeclaration; 285 const bool WeakDef = ExplicitInstantiation || D->hasAttr<WeakAttr>(); 286 const bool Inlined = isInlined(D); 287 const RecordLinkage Linkage = (Inlined || !isExported(D)) 288 ? RecordLinkage::Internal 289 : RecordLinkage::Exported; 290 Ctx.Slice->addGlobal(Name, Linkage, GlobalRecord::Kind::Function, Avail, D, 291 *Access, getFlags(WeakDef), Inlined); 292 return true; 293 } 294 295 static bool hasVTable(const CXXRecordDecl *D) { 296 // Check if vtable symbols should be emitted, only dynamic classes need 297 // vtables. 298 if (!D->hasDefinition() || !D->isDynamicClass()) 299 return false; 300 301 assert(D->isExternallyVisible() && "Should be externally visible"); 302 assert(D->isCompleteDefinition() && "Only works on complete definitions"); 303 304 const CXXMethodDecl *KeyFunctionD = 305 D->getASTContext().getCurrentKeyFunction(D); 306 // If this class has a key function, then there is a vtable, possibly internal 307 // though. 308 if (KeyFunctionD) { 309 switch (KeyFunctionD->getTemplateSpecializationKind()) { 310 case TSK_Undeclared: 311 case TSK_ExplicitSpecialization: 312 case TSK_ImplicitInstantiation: 313 case TSK_ExplicitInstantiationDefinition: 314 return true; 315 case TSK_ExplicitInstantiationDeclaration: 316 llvm_unreachable( 317 "Unexpected TemplateSpecializationKind for key function"); 318 } 319 } else if (D->isAbstract()) { 320 // If the class is abstract and it doesn't have a key function, it is a 321 // 'pure' virtual class. It doesn't need a vtable. 322 return false; 323 } 324 325 switch (D->getTemplateSpecializationKind()) { 326 case TSK_Undeclared: 327 case TSK_ExplicitSpecialization: 328 case TSK_ImplicitInstantiation: 329 return false; 330 331 case TSK_ExplicitInstantiationDeclaration: 332 case TSK_ExplicitInstantiationDefinition: 333 return true; 334 } 335 336 llvm_unreachable("Invalid TemplateSpecializationKind!"); 337 } 338 339 static CXXLinkage getVTableLinkage(const CXXRecordDecl *D) { 340 assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable"); 341 assert(D->isExternallyVisible() && "Record should be externally visible"); 342 if (D->getVisibility() == HiddenVisibility) 343 return CXXLinkage::PrivateLinkage; 344 345 const CXXMethodDecl *KeyFunctionD = 346 D->getASTContext().getCurrentKeyFunction(D); 347 if (KeyFunctionD) { 348 // If this class has a key function, use that to determine the 349 // linkage of the vtable. 350 switch (KeyFunctionD->getTemplateSpecializationKind()) { 351 case TSK_Undeclared: 352 case TSK_ExplicitSpecialization: 353 if (isInlined(KeyFunctionD)) 354 return CXXLinkage::LinkOnceODRLinkage; 355 return CXXLinkage::ExternalLinkage; 356 case TSK_ImplicitInstantiation: 357 llvm_unreachable("No external vtable for implicit instantiations"); 358 case TSK_ExplicitInstantiationDefinition: 359 return CXXLinkage::WeakODRLinkage; 360 case TSK_ExplicitInstantiationDeclaration: 361 llvm_unreachable( 362 "Unexpected TemplateSpecializationKind for key function"); 363 } 364 } 365 366 switch (D->getTemplateSpecializationKind()) { 367 case TSK_Undeclared: 368 case TSK_ExplicitSpecialization: 369 case TSK_ImplicitInstantiation: 370 return CXXLinkage::LinkOnceODRLinkage; 371 case TSK_ExplicitInstantiationDeclaration: 372 case TSK_ExplicitInstantiationDefinition: 373 return CXXLinkage::WeakODRLinkage; 374 } 375 376 llvm_unreachable("Invalid TemplateSpecializationKind!"); 377 } 378 379 static bool isRTTIWeakDef(const CXXRecordDecl *D) { 380 if (D->hasAttr<WeakAttr>()) 381 return true; 382 383 if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr) 384 return true; 385 386 if (D->isDynamicClass()) 387 return getVTableLinkage(D) != CXXLinkage::ExternalLinkage; 388 389 return false; 390 } 391 392 static bool hasRTTI(const CXXRecordDecl *D) { 393 if (!D->getASTContext().getLangOpts().RTTI) 394 return false; 395 396 if (!D->hasDefinition()) 397 return false; 398 399 if (!D->isDynamicClass()) 400 return false; 401 402 // Don't emit weak-def RTTI information. InstallAPI cannot reliably determine 403 // if the final binary will have those weak defined RTTI symbols. This depends 404 // on the optimization level and if the class has been instantiated and used. 405 // 406 // Luckily, the Apple static linker doesn't need those weak defined RTTI 407 // symbols for linking. They are only needed by the runtime linker. That means 408 // they can be safely dropped. 409 if (isRTTIWeakDef(D)) 410 return false; 411 412 return true; 413 } 414 415 std::string 416 InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const { 417 SmallString<256> Name; 418 raw_svector_ostream NameStream(Name); 419 MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream); 420 421 return getBackendMangledName(Name); 422 } 423 424 std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const { 425 SmallString<256> Name; 426 raw_svector_ostream NameStream(Name); 427 MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream); 428 429 return getBackendMangledName(Name); 430 } 431 432 std::string 433 InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const { 434 SmallString<256> Name; 435 raw_svector_ostream NameStream(Name); 436 MC->mangleCXXVTable(D, NameStream); 437 438 return getBackendMangledName(Name); 439 } 440 441 std::string 442 InstallAPIVisitor::getMangledCXXThunk(const GlobalDecl &D, 443 const ThunkInfo &Thunk) const { 444 SmallString<256> Name; 445 raw_svector_ostream NameStream(Name); 446 const auto *Method = cast<CXXMethodDecl>(D.getDecl()); 447 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) 448 MC->mangleCXXDtorThunk(Dtor, D.getDtorType(), Thunk.This, NameStream); 449 else 450 MC->mangleThunk(Method, Thunk, NameStream); 451 452 return getBackendMangledName(Name); 453 } 454 455 std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D, 456 int Type) const { 457 SmallString<256> Name; 458 raw_svector_ostream NameStream(Name); 459 GlobalDecl GD; 460 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(D)) 461 GD = GlobalDecl(Ctor, CXXCtorType(Type)); 462 else { 463 const auto *Dtor = cast<CXXDestructorDecl>(D); 464 GD = GlobalDecl(Dtor, CXXDtorType(Type)); 465 } 466 MC->mangleName(GD, NameStream); 467 return getBackendMangledName(Name); 468 } 469 470 void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D, 471 const AvailabilityInfo &Avail, 472 const HeaderType Access, 473 bool EmittedVTable) { 474 if (hasVTable(D)) { 475 EmittedVTable = true; 476 const CXXLinkage VTableLinkage = getVTableLinkage(D); 477 if (VTableLinkage == CXXLinkage::ExternalLinkage || 478 VTableLinkage == CXXLinkage::WeakODRLinkage) { 479 const std::string Name = getMangledCXXVTableName(D); 480 const bool WeakDef = VTableLinkage == CXXLinkage::WeakODRLinkage; 481 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 482 GlobalRecord::Kind::Variable, Avail, D, Access, 483 getFlags(WeakDef)); 484 if (!D->getDescribedClassTemplate() && !D->isInvalidDecl()) { 485 VTableContextBase *VTable = D->getASTContext().getVTableContext(); 486 auto AddThunk = [&](GlobalDecl GD) { 487 const ItaniumVTableContext::ThunkInfoVectorTy *Thunks = 488 VTable->getThunkInfo(GD); 489 if (!Thunks) 490 return; 491 492 for (const auto &Thunk : *Thunks) { 493 const std::string Name = getMangledCXXThunk(GD, Thunk); 494 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 495 GlobalRecord::Kind::Function, Avail, 496 GD.getDecl(), Access); 497 } 498 }; 499 500 for (const auto *Method : D->methods()) { 501 if (isa<CXXConstructorDecl>(Method) || !Method->isVirtual()) 502 continue; 503 504 if (auto Dtor = dyn_cast<CXXDestructorDecl>(Method)) { 505 // Skip default destructor. 506 if (Dtor->isDefaulted()) 507 continue; 508 AddThunk({Dtor, Dtor_Deleting}); 509 AddThunk({Dtor, Dtor_Complete}); 510 } else 511 AddThunk(Method); 512 } 513 } 514 } 515 } 516 517 if (!EmittedVTable) 518 return; 519 520 if (hasRTTI(D)) { 521 std::string Name = getMangledCXXRTTI(D); 522 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 523 GlobalRecord::Kind::Variable, Avail, D, Access); 524 525 Name = getMangledCXXRTTIName(D); 526 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 527 GlobalRecord::Kind::Variable, Avail, D, Access); 528 } 529 530 for (const auto &It : D->bases()) { 531 const CXXRecordDecl *Base = 532 cast<CXXRecordDecl>(It.getType()->castAs<RecordType>()->getDecl()); 533 const auto BaseAccess = getAccessForDecl(Base); 534 if (!BaseAccess) 535 continue; 536 const AvailabilityInfo BaseAvail = AvailabilityInfo::createFromDecl(Base); 537 emitVTableSymbols(Base, BaseAvail, *BaseAccess, /*EmittedVTable=*/true); 538 } 539 } 540 541 bool InstallAPIVisitor::VisitCXXRecordDecl(const CXXRecordDecl *D) { 542 if (!D->isCompleteDefinition()) 543 return true; 544 545 // Skip templated classes. 546 if (D->getDescribedClassTemplate() != nullptr) 547 return true; 548 549 // Skip partial templated classes too. 550 if (isa<ClassTemplatePartialSpecializationDecl>(D)) 551 return true; 552 553 auto Access = getAccessForDecl(D); 554 if (!Access) 555 return true; 556 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(D); 557 558 // Check whether to emit the vtable/rtti symbols. 559 if (isExported(D)) 560 emitVTableSymbols(D, Avail, *Access); 561 562 TemplateSpecializationKind ClassSK = TSK_Undeclared; 563 bool KeepInlineAsWeak = false; 564 if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 565 ClassSK = Templ->getTemplateSpecializationKind(); 566 if (ClassSK == TSK_ExplicitInstantiationDeclaration) 567 KeepInlineAsWeak = true; 568 } 569 570 // Record the class methods. 571 for (const auto *M : D->methods()) { 572 // Inlined methods are usually not emitted, except when it comes from a 573 // specialized template. 574 bool WeakDef = false; 575 if (isInlined(M)) { 576 if (!KeepInlineAsWeak) 577 continue; 578 579 WeakDef = true; 580 } 581 582 if (!isExported(M)) 583 continue; 584 585 switch (M->getTemplateSpecializationKind()) { 586 case TSK_Undeclared: 587 case TSK_ExplicitSpecialization: 588 break; 589 case TSK_ImplicitInstantiation: 590 continue; 591 case TSK_ExplicitInstantiationDeclaration: 592 if (ClassSK == TSK_ExplicitInstantiationDeclaration) 593 WeakDef = true; 594 break; 595 case TSK_ExplicitInstantiationDefinition: 596 WeakDef = true; 597 break; 598 } 599 600 if (!M->isUserProvided()) 601 continue; 602 603 // Methods that are deleted are not exported. 604 if (M->isDeleted()) 605 continue; 606 607 const auto Access = getAccessForDecl(M); 608 if (!Access) 609 return true; 610 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(M); 611 612 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(M)) { 613 // Defaulted constructors are not exported. 614 if (Ctor->isDefaulted()) 615 continue; 616 617 std::string Name = getMangledCtorDtor(M, Ctor_Base); 618 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 619 GlobalRecord::Kind::Function, Avail, D, *Access, 620 getFlags(WeakDef)); 621 622 if (!D->isAbstract()) { 623 std::string Name = getMangledCtorDtor(M, Ctor_Complete); 624 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 625 GlobalRecord::Kind::Function, Avail, D, *Access, 626 getFlags(WeakDef)); 627 } 628 629 continue; 630 } 631 632 if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(M)) { 633 // Defaulted destructors are not exported. 634 if (Dtor->isDefaulted()) 635 continue; 636 637 std::string Name = getMangledCtorDtor(M, Dtor_Base); 638 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 639 GlobalRecord::Kind::Function, Avail, D, *Access, 640 getFlags(WeakDef)); 641 642 Name = getMangledCtorDtor(M, Dtor_Complete); 643 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 644 GlobalRecord::Kind::Function, Avail, D, *Access, 645 getFlags(WeakDef)); 646 647 if (Dtor->isVirtual()) { 648 Name = getMangledCtorDtor(M, Dtor_Deleting); 649 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 650 GlobalRecord::Kind::Function, Avail, D, *Access, 651 getFlags(WeakDef)); 652 } 653 654 continue; 655 } 656 657 // Though abstract methods can map to exports, this is generally unexpected. 658 // Except in the case of destructors. Only ignore pure virtuals after 659 // checking if the member function was a destructor. 660 if (M->isPureVirtual()) 661 continue; 662 663 std::string Name = getMangledName(M); 664 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 665 GlobalRecord::Kind::Function, Avail, D, *Access, 666 getFlags(WeakDef)); 667 } 668 669 if (auto *Templ = dyn_cast<ClassTemplateSpecializationDecl>(D)) { 670 if (!Templ->isExplicitInstantiationOrSpecialization()) 671 return true; 672 } 673 674 using var_iter = CXXRecordDecl::specific_decl_iterator<VarDecl>; 675 using var_range = iterator_range<var_iter>; 676 for (const auto *Var : var_range(D->decls())) { 677 // Skip const static member variables. 678 // \code 679 // struct S { 680 // static const int x = 0; 681 // }; 682 // \endcode 683 if (Var->isStaticDataMember() && Var->hasInit()) 684 continue; 685 686 // Skip unexported var decls. 687 if (!isExported(Var)) 688 continue; 689 690 const std::string Name = getMangledName(Var); 691 const auto Access = getAccessForDecl(Var); 692 if (!Access) 693 return true; 694 const AvailabilityInfo Avail = AvailabilityInfo::createFromDecl(Var); 695 const bool WeakDef = Var->hasAttr<WeakAttr>() || KeepInlineAsWeak; 696 697 Ctx.Slice->addGlobal(Name, RecordLinkage::Exported, 698 GlobalRecord::Kind::Variable, Avail, D, *Access, 699 getFlags(WeakDef)); 700 } 701 702 return true; 703 } 704 705 } // namespace clang::installapi 706