Path: blob/main/contrib/llvm-project/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp
35232 views
//===--- InterfaceStubFunctionsConsumer.cpp -------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/AST/Mangle.h"9#include "clang/AST/RecursiveASTVisitor.h"10#include "clang/Basic/TargetInfo.h"11#include "clang/Frontend/CompilerInstance.h"12#include "clang/Frontend/FrontendActions.h"13#include "clang/Sema/TemplateInstCallback.h"14#include "llvm/BinaryFormat/ELF.h"1516using namespace clang;1718namespace {19class InterfaceStubFunctionsConsumer : public ASTConsumer {20CompilerInstance &Instance;21StringRef InFile;22StringRef Format;23std::set<std::string> ParsedTemplates;2425enum RootDeclOrigin { TopLevel = 0, FromTU = 1, IsLate = 2 };26struct MangledSymbol {27std::string ParentName;28uint8_t Type;29uint8_t Binding;30std::vector<std::string> Names;31MangledSymbol() = delete;3233MangledSymbol(const std::string &ParentName, uint8_t Type, uint8_t Binding,34std::vector<std::string> Names)35: ParentName(ParentName), Type(Type), Binding(Binding),36Names(std::move(Names)) {}37};38using MangledSymbols = std::map<const NamedDecl *, MangledSymbol>;3940bool WriteNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {41// Here we filter out anything that's not set to DefaultVisibility.42// DefaultVisibility is set on a decl when -fvisibility is not specified on43// the command line (or specified as default) and the decl does not have44// __attribute__((visibility("hidden"))) set or when the command line45// argument is set to hidden but the decl explicitly has46// __attribute__((visibility ("default"))) set. We do this so that the user47// can have fine grain control of what they want to expose in the stub.48auto isVisible = [](const NamedDecl *ND) -> bool {49return ND->getVisibility() == DefaultVisibility;50};5152auto ignoreDecl = [this, isVisible](const NamedDecl *ND) -> bool {53if (!isVisible(ND))54return true;5556if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {57if (const auto *Parent = VD->getParentFunctionOrMethod())58if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent))59return true;6061if ((VD->getStorageClass() == StorageClass::SC_Extern) ||62(VD->getStorageClass() == StorageClass::SC_Static &&63VD->getParentFunctionOrMethod() == nullptr))64return true;65}6667if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {68if (FD->isInlined() && !isa<CXXMethodDecl>(FD) &&69!Instance.getLangOpts().GNUInline)70return true;71if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {72if (const auto *RC = dyn_cast<CXXRecordDecl>(MD->getParent()))73if (isa<ClassTemplateDecl>(RC->getParent()) || !isVisible(RC))74return true;75if (MD->isDependentContext() || !MD->hasBody())76return true;77}78if (FD->getStorageClass() == StorageClass::SC_Static)79return true;80}81return false;82};8384auto getParentFunctionDecl = [](const NamedDecl *ND) -> const NamedDecl * {85if (const VarDecl *VD = dyn_cast<VarDecl>(ND))86if (const auto *FD =87dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod()))88return FD;89return nullptr;90};9192auto getMangledNames = [](const NamedDecl *ND) -> std::vector<std::string> {93if (!ND)94return {""};95ASTNameGenerator NameGen(ND->getASTContext());96std::vector<std::string> MangledNames = NameGen.getAllManglings(ND);97if (isa<CXXConstructorDecl>(ND) || isa<CXXDestructorDecl>(ND))98return MangledNames;99#ifdef EXPENSIVE_CHECKS100assert(MangledNames.size() <= 1 && "Expected only one name mangling.");101#endif102return {NameGen.getName(ND)};103};104105if (!(RDO & FromTU))106return true;107if (Symbols.find(ND) != Symbols.end())108return true;109// - Currently have not figured out how to produce the names for FieldDecls.110// - Do not want to produce symbols for function paremeters.111if (isa<FieldDecl>(ND) || isa<ParmVarDecl>(ND))112return true;113114const NamedDecl *ParentDecl = getParentFunctionDecl(ND);115if ((ParentDecl && ignoreDecl(ParentDecl)) || ignoreDecl(ND))116return true;117118if (RDO & IsLate) {119Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)120<< "Generating Interface Stubs is not supported with "121"delayed template parsing.";122} else {123if (const auto *FD = dyn_cast<FunctionDecl>(ND))124if (FD->isDependentContext())125return true;126127const bool IsWeak = (ND->hasAttr<WeakAttr>() ||128ND->hasAttr<WeakRefAttr>() || ND->isWeakImported());129130Symbols.insert(std::make_pair(131ND,132MangledSymbol(getMangledNames(ParentDecl).front(),133// Type:134isa<VarDecl>(ND) ? llvm::ELF::STT_OBJECT135: llvm::ELF::STT_FUNC,136// Binding:137IsWeak ? llvm::ELF::STB_WEAK : llvm::ELF::STB_GLOBAL,138getMangledNames(ND))));139}140return true;141}142143void144HandleDecls(const llvm::iterator_range<DeclContext::decl_iterator> &Decls,145MangledSymbols &Symbols, int RDO) {146for (const auto *D : Decls)147HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);148}149150void HandleTemplateSpecializations(const FunctionTemplateDecl &FTD,151MangledSymbols &Symbols, int RDO) {152for (const auto *D : FTD.specializations())153HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);154}155156void HandleTemplateSpecializations(const ClassTemplateDecl &CTD,157MangledSymbols &Symbols, int RDO) {158for (const auto *D : CTD.specializations())159HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);160}161162bool HandleNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {163if (!ND)164return false;165166switch (ND->getKind()) {167default:168break;169case Decl::Kind::Namespace:170HandleDecls(cast<NamespaceDecl>(ND)->decls(), Symbols, RDO);171return true;172case Decl::Kind::CXXRecord:173HandleDecls(cast<CXXRecordDecl>(ND)->decls(), Symbols, RDO);174return true;175case Decl::Kind::ClassTemplateSpecialization:176HandleDecls(cast<ClassTemplateSpecializationDecl>(ND)->decls(), Symbols,177RDO);178return true;179case Decl::Kind::ClassTemplate:180HandleTemplateSpecializations(*cast<ClassTemplateDecl>(ND), Symbols, RDO);181return true;182case Decl::Kind::FunctionTemplate:183HandleTemplateSpecializations(*cast<FunctionTemplateDecl>(ND), Symbols,184RDO);185return true;186case Decl::Kind::Record:187case Decl::Kind::Typedef:188case Decl::Kind::Enum:189case Decl::Kind::EnumConstant:190case Decl::Kind::TemplateTypeParm:191case Decl::Kind::NonTypeTemplateParm:192case Decl::Kind::CXXConversion:193case Decl::Kind::UnresolvedUsingValue:194case Decl::Kind::Using:195case Decl::Kind::UsingShadow:196case Decl::Kind::TypeAliasTemplate:197case Decl::Kind::TypeAlias:198case Decl::Kind::VarTemplate:199case Decl::Kind::VarTemplateSpecialization:200case Decl::Kind::UsingDirective:201case Decl::Kind::TemplateTemplateParm:202case Decl::Kind::ClassTemplatePartialSpecialization:203case Decl::Kind::IndirectField:204case Decl::Kind::ConstructorUsingShadow:205case Decl::Kind::CXXDeductionGuide:206case Decl::Kind::NamespaceAlias:207case Decl::Kind::UnresolvedUsingTypename:208return true;209case Decl::Kind::Var: {210// Bail on any VarDecl that either has no named symbol.211if (!ND->getIdentifier())212return true;213const auto *VD = cast<VarDecl>(ND);214// Bail on any VarDecl that is a dependent or templated type.215if (VD->isTemplated() || VD->getType()->isDependentType())216return true;217if (WriteNamedDecl(ND, Symbols, RDO))218return true;219break;220}221case Decl::Kind::ParmVar:222case Decl::Kind::CXXMethod:223case Decl::Kind::CXXConstructor:224case Decl::Kind::CXXDestructor:225case Decl::Kind::Function:226case Decl::Kind::Field:227if (WriteNamedDecl(ND, Symbols, RDO))228return true;229}230231// While interface stubs are in the development stage, it's probably best to232// catch anything that's not a VarDecl or Template/FunctionDecl.233Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)234<< "Expected a function or function template decl.";235return false;236}237238public:239InterfaceStubFunctionsConsumer(CompilerInstance &Instance, StringRef InFile,240StringRef Format)241: Instance(Instance), InFile(InFile), Format(Format) {}242243void HandleTranslationUnit(ASTContext &context) override {244struct Visitor : public RecursiveASTVisitor<Visitor> {245bool VisitNamedDecl(NamedDecl *ND) {246if (const auto *FD = dyn_cast<FunctionDecl>(ND))247if (FD->isLateTemplateParsed()) {248LateParsedDecls.insert(FD);249return true;250}251252if (const auto *VD = dyn_cast<ValueDecl>(ND)) {253ValueDecls.insert(VD);254return true;255}256257NamedDecls.insert(ND);258return true;259}260261std::set<const NamedDecl *> LateParsedDecls;262std::set<NamedDecl *> NamedDecls;263std::set<const ValueDecl *> ValueDecls;264} v;265266v.TraverseDecl(context.getTranslationUnitDecl());267268MangledSymbols Symbols;269auto OS = Instance.createDefaultOutputFile(/*Binary=*/false, InFile, "ifs");270if (!OS)271return;272273if (Instance.getLangOpts().DelayedTemplateParsing) {274clang::Sema &S = Instance.getSema();275for (const auto *FD : v.LateParsedDecls) {276clang::LateParsedTemplate &LPT =277*S.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second;278S.LateTemplateParser(S.OpaqueParser, LPT);279HandleNamedDecl(FD, Symbols, (FromTU | IsLate));280}281}282283for (const NamedDecl *ND : v.ValueDecls)284HandleNamedDecl(ND, Symbols, FromTU);285for (const NamedDecl *ND : v.NamedDecls)286HandleNamedDecl(ND, Symbols, FromTU);287288auto writeIfsV1 = [this](const llvm::Triple &T,289const MangledSymbols &Symbols,290const ASTContext &context, StringRef Format,291raw_ostream &OS) -> void {292OS << "--- !" << Format << "\n";293OS << "IfsVersion: 3.0\n";294OS << "Target: " << T.str() << "\n";295OS << "Symbols:\n";296for (const auto &E : Symbols) {297const MangledSymbol &Symbol = E.second;298for (const auto &Name : Symbol.Names) {299OS << " - { Name: \""300<< (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus301? ""302: (Symbol.ParentName + "."))303<< Name << "\", Type: ";304switch (Symbol.Type) {305default:306llvm_unreachable(307"clang -emit-interface-stubs: Unexpected symbol type.");308case llvm::ELF::STT_NOTYPE:309OS << "NoType";310break;311case llvm::ELF::STT_OBJECT: {312auto VD = cast<ValueDecl>(E.first)->getType();313OS << "Object, Size: "314<< context.getTypeSizeInChars(VD).getQuantity();315break;316}317case llvm::ELF::STT_FUNC:318OS << "Func";319break;320}321if (Symbol.Binding == llvm::ELF::STB_WEAK)322OS << ", Weak: true";323OS << " }\n";324}325}326OS << "...\n";327OS.flush();328};329330assert(Format == "ifs-v1" && "Unexpected IFS Format.");331writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS);332}333};334} // namespace335336std::unique_ptr<ASTConsumer>337GenerateInterfaceStubsAction::CreateASTConsumer(CompilerInstance &CI,338StringRef InFile) {339return std::make_unique<InterfaceStubFunctionsConsumer>(CI, InFile, "ifs-v1");340}341342343