clang: lib/InstallAPI/Visitor.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

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

21using namespace llvm;

23

24namespace {

25enum class CXXLinkage {

26 ExternalLinkage,

27 LinkOnceODRLinkage,

28 WeakODRLinkage,

29 PrivateLinkage,

30};

31}

32

34

35

36

38 auto LV = D->getLinkageAndVisibility();

41}

42

44 bool HasInlineAttribute = false;

45 bool NoCXXAttr =

46 (D->getASTContext().getLangOpts().CPlusPlus &&

47 D->getASTContext().getTargetInfo().getCXXABI().isMicrosoft() &&

48 D->hasAttr());

49

50

51 for (const auto *RD : D->redecls()) {

52 if (!RD->isInlined())

53 continue;

54 HasInlineAttribute = true;

55 if (!(NoCXXAttr || RD->hasAttr()))

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

70 if (WeakDef)

71 Result |= SymbolFlags::WeakDefined;

72 if (ThreadLocal)

73 Result |= SymbolFlags::ThreadLocalValue;

74

76}

77

80 return;

81

84}

85

86std::string InstallAPIVisitor::getMangledName(const NamedDecl *D) const {

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

97std::string InstallAPIVisitor::getBackendMangledName(Twine Name) const {

99 Mangler::getNameWithPrefix(FinalName, Name, DataLayout(Layout));

100 return std::string(FinalName);

101}

102

103std::optional

104InstallAPIVisitor::getAccessForDecl(const NamedDecl *D) const {

105 SourceLocation Loc = D->getLocation();

106 if (Loc.isInvalid())

107 return std::nullopt;

108

109

110

113 if (ID.isInvalid())

114 return std::nullopt;

115

117 if (!FE)

118 return std::nullopt;

119

121 if (!Header.has_value())

122 return std::nullopt;

123

125 assert(Access != HeaderType::Unknown && "unexpected access level for global");

126 return Access;

127}

128

129

130

131

132

134 for (; D != nullptr; D = D->getSuperClass())

135 if (D->hasAttr())

136 return true;

137

138 return false;

139}

140void InstallAPIVisitor::recordObjCInstanceVariables(

142 const llvm::iterator_range<

144 Ivars) {

147

149 Linkage = RecordLinkage::Unknown;

150

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();

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

167

168 if (D->isThisDeclarationADefinition())

169 return true;

170

171

172 auto Access = getAccessForDecl(D);

173 if (!Access)

174 return true;

175

176 StringRef Name = D->getObjCRuntimeNameAsString();

178 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;

180 const bool IsEHType =

181 (D->getASTContext().getLangOpts().ObjCRuntime.isFragile() &&

183

184 auto [Class, FA] =

185 Ctx.Slice->addObjCInterface(Name, Linkage, Avail, D, *Access, IsEHType);

187

188

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

199 StringRef CategoryName = D->getName();

200

201 auto Access = getAccessForDecl(D);

202 if (!Access)

203 return true;

206 const StringRef InterfaceName = InterfaceD->getName();

207

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

217

218 if (isa(D))

219 return true;

220

221

222 if (D->getDeclContext()->isRecord())

223 return true;

224

225

226 if (D->isDefinedOutsideFunctionOrMethod())

227 return true;

228

229

230 if (D->getASTContext().getTemplateOrSpecializationInfo(D) &&

232 return true;

233

234

235 auto Access = getAccessForDecl(D);

236 if (!Access)

237 return true;

238

240 isExported(D) ? RecordLinkage::Exported : RecordLinkage::Internal;

241 const bool WeakDef = D->hasAttr();

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

252 if (const CXXMethodDecl *M = dyn_cast(D)) {

253

254 if (M->getParent()->getDescribedClassTemplate() != nullptr)

255 return true;

256

257

258 for (const DynTypedNode &P : D->getASTContext().getParents(*M)) {

260 return true;

261 }

262

263

264 if (isa(M) || isa(M))

265 return true;

266 }

267

268

269 switch (D->getTemplatedKind()) {

272 break;

275 if (auto *TempInfo = D->getTemplateSpecializationInfo()) {

276 if (!TempInfo->isExplicitInstantiationOrSpecialization())

277 return true;

278 }

279 break;

282 return true;

283 }

284

285 auto Access = getAccessForDecl(D);

286 if (!Access)

287 return true;

288 auto Name = getMangledName(D);

290 const bool ExplicitInstantiation = D->getTemplateSpecializationKind() ==

292 const bool WeakDef = ExplicitInstantiation || D->hasAttr();

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

305

306

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

314 D->getASTContext().getCurrentKeyFunction(D);

315

316

317 if (KeyFunctionD) {

323 return true;

325 llvm_unreachable(

326 "Unexpected TemplateSpecializationKind for key function");

327 }

328 } else if (D->isAbstract()) {

329

330

331 return false;

332 }

333

334 switch (D->getTemplateSpecializationKind()) {

338 return false;

339

342 return true;

343 }

344

345 llvm_unreachable("Invalid TemplateSpecializationKind!");

346}

347

349 assert((D->hasDefinition() && D->isDynamicClass()) && "Record has no vtable");

350 assert(D->isExternallyVisible() && "Record should be externally visible");

352 return CXXLinkage::PrivateLinkage;

353

355 D->getASTContext().getCurrentKeyFunction(D);

356 if (KeyFunctionD) {

357

358

363 return CXXLinkage::LinkOnceODRLinkage;

364 return CXXLinkage::ExternalLinkage;

366 llvm_unreachable("No external vtable for implicit instantiations");

368 return CXXLinkage::WeakODRLinkage;

370 llvm_unreachable(

371 "Unexpected TemplateSpecializationKind for key function");

372 }

373 }

374

375 switch (D->getTemplateSpecializationKind()) {

379 return CXXLinkage::LinkOnceODRLinkage;

382 return CXXLinkage::WeakODRLinkage;

383 }

384

385 llvm_unreachable("Invalid TemplateSpecializationKind!");

386}

387

389 if (D->hasAttr())

390 return true;

391

392 if (D->isAbstract() && D->getASTContext().getCurrentKeyFunction(D) == nullptr)

393 return true;

394

395 if (D->isDynamicClass())

397

398 return false;

399}

400

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

412

413

414

415

416

417

419 return false;

420

421 return true;

422}

423

424std::string

425InstallAPIVisitor::getMangledCXXRTTIName(const CXXRecordDecl *D) const {

427 raw_svector_ostream NameStream(Name);

428 MC->mangleCXXRTTIName(QualType(D->getTypeForDecl(), 0), NameStream);

429

430 return getBackendMangledName(Name);

431}

432

433std::string InstallAPIVisitor::getMangledCXXRTTI(const CXXRecordDecl *D) const {

435 raw_svector_ostream NameStream(Name);

436 MC->mangleCXXRTTI(QualType(D->getTypeForDecl(), 0), NameStream);

437

438 return getBackendMangledName(Name);

439}

440

441std::string

442InstallAPIVisitor::getMangledCXXVTableName(const CXXRecordDecl *D) const {

444 raw_svector_ostream NameStream(Name);

445 MC->mangleCXXVTable(D, NameStream);

446

447 return getBackendMangledName(Name);

448}

449

450std::string InstallAPIVisitor::getMangledCXXThunk(

451 const GlobalDecl &D, const ThunkInfo &Thunk, bool ElideOverrideInfo) const {

453 raw_svector_ostream NameStream(Name);

454 const auto *Method = cast(D.getDecl());

455 if (const auto *Dtor = dyn_cast(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

464std::string InstallAPIVisitor::getMangledCtorDtor(const CXXMethodDecl *D,

465 int Type) const {

467 raw_svector_ostream NameStream(Name);

468 GlobalDecl GD;

469 if (const auto *Ctor = dyn_cast(D))

470 GD = GlobalDecl(Ctor, CXXCtorType(Type));

471 else {

472 const auto *Dtor = cast(D);

473 GD = GlobalDecl(Dtor, CXXDtorType(Type));

474 }

475 MC->mangleName(GD, NameStream);

476 return getBackendMangledName(Name);

477}

478

479void InstallAPIVisitor::emitVTableSymbols(const CXXRecordDecl *D,

480 const AvailabilityInfo &Avail,

482 bool EmittedVTable) {

484 EmittedVTable = true;

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,

493 Ctx.Verifier->verify(GR, FA);

494 if (D->getDescribedClassTemplate() && D->isInvalidDecl()) {

495 VTableContextBase *VTable = D->getASTContext().getVTableContext();

496 auto AddThunk = [&](GlobalDecl GD) {

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, 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(Method) || !Method->isVirtual())

514 continue;

515

516 if (auto Dtor = dyn_cast(Method)) {

517

518 if (Dtor->isDefaulted())

519 continue;

522 } else

523 AddThunk(Method);

524 }

525 }

526 }

527 }

528

529 if (!EmittedVTable)

530 return;

531

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(It.getType()->castAs()->getDecl());

549 const auto BaseAccess = getAccessForDecl(Base);

550 if (!BaseAccess)

551 continue;

553 emitVTableSymbols(Base, BaseAvail, *BaseAccess, true);

554 }

555}

556

558 if (D->isCompleteDefinition())

559 return true;

560

561

562 if (D->getDescribedClassTemplate() != nullptr)

563 return true;

564

565

566 if (isa(D))

567 return true;

568

569 auto Access = getAccessForDecl(D);

570 if (!Access)

571 return true;

573

574

576 emitVTableSymbols(D, Avail, *Access);

577

579 bool KeepInlineAsWeak = false;

580 if (auto *Templ = dyn_cast(D)) {

581 ClassSK = Templ->getTemplateSpecializationKind();

583 KeepInlineAsWeak = true;

584 }

585

586

587 for (const auto *M : D->methods()) {

588

589

590 bool WeakDef = false;

592 if (!KeepInlineAsWeak)

593 continue;

594

595 WeakDef = true;

596 }

597

599 continue;

600

601 switch (M->getTemplateSpecializationKind()) {

604 break;

606 continue;

609 WeakDef = true;

610 break;

612 WeakDef = true;

613 break;

614 }

615

616 if (!M->isUserProvided())

617 continue;

618

619

620 if (M->isDeleted())

621 continue;

622

623 const auto Access = getAccessForDecl(M);

624 if (!Access)

625 return true;

627

628 if (const auto *Ctor = dyn_cast(M)) {

629

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,

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,

644 Ctx.Verifier->verify(GR, FA);

645 }

646

647 continue;

648 }

649

650 if (const auto *Dtor = dyn_cast(M)) {

651

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,

659 Ctx.Verifier->verify(GR, FA);

660

662 auto [CompleteGR, CompleteFA] = Ctx.Slice->addGlobal(

663 Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail, D,

665 Ctx.Verifier->verify(CompleteGR, CompleteFA);

666

667 if (Dtor->isVirtual()) {

669 auto [VirtualGR, VirtualFA] = Ctx.Slice->addGlobal(

670 Name, RecordLinkage::Exported, GlobalRecord::Kind::Function, Avail,

672 Ctx.Verifier->verify(VirtualGR, VirtualFA);

673 }

674

675 continue;

676 }

677

678

679

680

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,

688 Ctx.Verifier->verify(GR, FA);

689 }

690

691 if (auto *Templ = dyn_cast(D)) {

692 if (!Templ->isExplicitInstantiationOrSpecialization())

693 return true;

694 }

695

697 using var_range = iterator_range<var_iter>;

698 for (const auto *Var : var_range(D->decls())) {

699

700

701

702

703

704

705 if (Var->isStaticDataMember() && Var->hasInit())

706 continue;

707

708

710 continue;

711

712 const std::string Name = getMangledName(Var);

713 const auto Access = getAccessForDecl(Var);

714 if (!Access)

715 return true;

717 const bool WeakDef = Var->hasAttr() || KeepInlineAsWeak;

718

719 auto [GR, FA] = Ctx.Slice->addGlobal(Name, RecordLinkage::Exported,

720 GlobalRecord::Kind::Variable, Avail, D,

722 Ctx.Verifier->verify(GR, FA);

723 }

724

725 return true;

726}

727

728}

llvm::MachO::SymbolFlags SymbolFlags

llvm::MachO::ObjCCategoryRecord ObjCCategoryRecord

llvm::MachO::RecordLinkage RecordLinkage

llvm::MachO::Record Record

llvm::MachO::ObjCContainerRecord ObjCContainerRecord

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

TranslationUnitDecl * getTranslationUnitDecl() const

const LangOptions & getLangOpts() const

DiagnosticsEngine & getDiagnostics() const

Represents a static or instance method of a struct/union/class.

Represents a C++ struct/union/class.

specific_decl_iterator - Iterates over a subrange of declarations stored in a DeclContext,...

bool hasErrorOccurred() const

A dynamically typed AST node container.

Represents a function declaration or definition.

@ TK_MemberSpecialization

@ TK_DependentNonTemplate

@ TK_FunctionTemplateSpecialization

@ TK_DependentFunctionTemplateSpecialization

TemplateSpecializationKind getTemplateSpecializationKind() const

Determine what kind of template instantiation this function represents.

clang::ObjCRuntime ObjCRuntime

This represents a decl that may have a name.

StringRef getName() const

Get the name of identifier for this declaration as a StringRef.

ObjCCategoryDecl - Represents a category declaration.

Represents an ObjC class declaration.

bool isFragile() const

The inverse of isNonFragile(): does this runtime follow the set of implied behaviors for a "fragile" ...

A (possibly-)qualified type.

bool TraverseDecl(Decl *D)

Recursively visit a declaration, by dispatching to Traverse*Decl() based on the argument's dynamic ty...

FileID getFileID(SourceLocation SpellingLoc) const

Return the FileID for a SourceLocation.

SourceLocation getFileLoc(SourceLocation Loc) const

Given Loc, if it is a macro location return the expansion location or the spelling location,...

const FileEntry * getFileEntryForID(FileID FID) const

Returns the FileEntry record for the provided FileID.

SmallVector< ThunkInfo, 1 > ThunkInfoVectorTy

Represents a variable declaration or definition.

@ TLS_None

Not a TLS variable.

void HandleTranslationUnit(ASTContext &ASTCtx) override

HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...

bool VisitCXXRecordDecl(const CXXRecordDecl *D)

Collect global c++ declarations.

bool VisitFunctionDecl(const FunctionDecl *D)

Collect global functions.

bool VisitVarDecl(const VarDecl *D)

Collect global variables.

bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D)

Collect Objective-C Category/Extension declarations.

bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D)

Collect Objective-C Interface declarations.

Defines the Linkage enumeration and various utility functions.

The DirectoryScanner for collecting library files on the file system.

static bool isInlined(const FunctionDecl *D)

static CXXLinkage getVTableLinkage(const CXXRecordDecl *D)

@ Unknown

Unset or unknown type.

static bool hasObjCExceptionAttribute(const ObjCInterfaceDecl *D)

Check if the interface itself or any of its super classes have an exception attribute.

static bool hasVTable(const CXXRecordDecl *D)

static bool isRTTIWeakDef(const CXXRecordDecl *D)

static bool hasRTTI(const CXXRecordDecl *D)

static SymbolFlags getFlags(bool WeakDef, bool ThreadLocal=false)

static bool isExported(const NamedDecl *D)

CXXCtorType

C++ constructor types.

@ Ctor_Base

Base object ctor.

@ Ctor_Complete

Complete object ctor.

Linkage

Describes the different kinds of linkage (C++ [basic.link], C99 6.2.2) that an entity may have.

@ Result

The result type of a method or function.

CXXDtorType

C++ destructor types.

@ Dtor_Base

Base object dtor.

@ Dtor_Complete

Complete object dtor.

@ Dtor_Deleting

Deleting dtor.

TemplateSpecializationKind

Describes the kind of template specialization that a particular template specialization declaration r...

@ TSK_ExplicitInstantiationDefinition

This template specialization was instantiated from a template due to an explicit instantiation defini...

@ TSK_ExplicitInstantiationDeclaration

This template specialization was instantiated from a template due to an explicit instantiation declar...

@ TSK_ExplicitSpecialization

This template specialization was declared or defined by an explicit specialization (C++ [temp....

@ TSK_ImplicitInstantiation

This template specialization was implicitly instantiated from a template.

@ TSK_Undeclared

This template specialization was formed from a template-id but has not yet been declared,...

@ Class

The "class" keyword introduces the elaborated-type-specifier.

bool isExternallyVisible(Linkage L)

@ HiddenVisibility

Objects with "hidden" visibility are not seen by the dynamic linker.

@ DefaultVisibility

Objects with "default" visibility are seen by the dynamic linker and act like normal objects.

Diagnostic wrappers for TextAPI types for error reporting.

Storage of availability attributes for a declaration.

static AvailabilityInfo createFromDecl(const Decl *Decl)

std::optional< HeaderType > findAndRecordFile(const FileEntry *FE, const Preprocessor &PP)

Record visited files during frontend actions to determine whether to include their declarations for T...

std::shared_ptr< FrontendRecordsSlice > Slice

Active TargetSlice for symbol record collection.

std::unique_ptr< DylibVerifier > Verifier

Verifier when binary dylib is passed as input.