10b57cec5SDimitry Andric //===--- InterfaceStubFunctionsConsumer.cpp -------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "clang/AST/Mangle.h"
100b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
115ffd83dbSDimitry Andric #include "clang/Basic/TargetInfo.h"
120b57cec5SDimitry Andric #include "clang/Frontend/CompilerInstance.h"
130b57cec5SDimitry Andric #include "clang/Frontend/FrontendActions.h"
140b57cec5SDimitry Andric #include "clang/Sema/TemplateInstCallback.h"
150b57cec5SDimitry Andric #include "llvm/BinaryFormat/ELF.h"
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric using namespace clang;
180b57cec5SDimitry Andric
19a7dea167SDimitry Andric namespace {
200b57cec5SDimitry Andric class InterfaceStubFunctionsConsumer : public ASTConsumer {
210b57cec5SDimitry Andric CompilerInstance &Instance;
220b57cec5SDimitry Andric StringRef InFile;
230b57cec5SDimitry Andric StringRef Format;
240b57cec5SDimitry Andric std::set<std::string> ParsedTemplates;
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric enum RootDeclOrigin { TopLevel = 0, FromTU = 1, IsLate = 2 };
270b57cec5SDimitry Andric struct MangledSymbol {
280b57cec5SDimitry Andric std::string ParentName;
290b57cec5SDimitry Andric uint8_t Type;
300b57cec5SDimitry Andric uint8_t Binding;
310b57cec5SDimitry Andric std::vector<std::string> Names;
320b57cec5SDimitry Andric MangledSymbol() = delete;
330b57cec5SDimitry Andric
MangledSymbol__anonddb1d4dd0111::InterfaceStubFunctionsConsumer::MangledSymbol340b57cec5SDimitry Andric MangledSymbol(const std::string &ParentName, uint8_t Type, uint8_t Binding,
350b57cec5SDimitry Andric std::vector<std::string> Names)
36*0fca6ea1SDimitry Andric : ParentName(ParentName), Type(Type), Binding(Binding),
37*0fca6ea1SDimitry Andric Names(std::move(Names)) {}
380b57cec5SDimitry Andric };
390b57cec5SDimitry Andric using MangledSymbols = std::map<const NamedDecl *, MangledSymbol>;
400b57cec5SDimitry Andric
WriteNamedDecl(const NamedDecl * ND,MangledSymbols & Symbols,int RDO)410b57cec5SDimitry Andric bool WriteNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {
420b57cec5SDimitry Andric // Here we filter out anything that's not set to DefaultVisibility.
430b57cec5SDimitry Andric // DefaultVisibility is set on a decl when -fvisibility is not specified on
440b57cec5SDimitry Andric // the command line (or specified as default) and the decl does not have
450b57cec5SDimitry Andric // __attribute__((visibility("hidden"))) set or when the command line
460b57cec5SDimitry Andric // argument is set to hidden but the decl explicitly has
470b57cec5SDimitry Andric // __attribute__((visibility ("default"))) set. We do this so that the user
480b57cec5SDimitry Andric // can have fine grain control of what they want to expose in the stub.
490b57cec5SDimitry Andric auto isVisible = [](const NamedDecl *ND) -> bool {
500b57cec5SDimitry Andric return ND->getVisibility() == DefaultVisibility;
510b57cec5SDimitry Andric };
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric auto ignoreDecl = [this, isVisible](const NamedDecl *ND) -> bool {
540b57cec5SDimitry Andric if (!isVisible(ND))
550b57cec5SDimitry Andric return true;
560b57cec5SDimitry Andric
57480093f4SDimitry Andric if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
58480093f4SDimitry Andric if (const auto *Parent = VD->getParentFunctionOrMethod())
59480093f4SDimitry Andric if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent))
60480093f4SDimitry Andric return true;
61480093f4SDimitry Andric
620b57cec5SDimitry Andric if ((VD->getStorageClass() == StorageClass::SC_Extern) ||
630b57cec5SDimitry Andric (VD->getStorageClass() == StorageClass::SC_Static &&
640b57cec5SDimitry Andric VD->getParentFunctionOrMethod() == nullptr))
650b57cec5SDimitry Andric return true;
66480093f4SDimitry Andric }
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
690b57cec5SDimitry Andric if (FD->isInlined() && !isa<CXXMethodDecl>(FD) &&
700b57cec5SDimitry Andric !Instance.getLangOpts().GNUInline)
710b57cec5SDimitry Andric return true;
720b57cec5SDimitry Andric if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
730b57cec5SDimitry Andric if (const auto *RC = dyn_cast<CXXRecordDecl>(MD->getParent()))
740b57cec5SDimitry Andric if (isa<ClassTemplateDecl>(RC->getParent()) || !isVisible(RC))
750b57cec5SDimitry Andric return true;
760b57cec5SDimitry Andric if (MD->isDependentContext() || !MD->hasBody())
770b57cec5SDimitry Andric return true;
780b57cec5SDimitry Andric }
790b57cec5SDimitry Andric if (FD->getStorageClass() == StorageClass::SC_Static)
800b57cec5SDimitry Andric return true;
810b57cec5SDimitry Andric }
820b57cec5SDimitry Andric return false;
830b57cec5SDimitry Andric };
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric auto getParentFunctionDecl = [](const NamedDecl *ND) -> const NamedDecl * {
860b57cec5SDimitry Andric if (const VarDecl *VD = dyn_cast<VarDecl>(ND))
870b57cec5SDimitry Andric if (const auto *FD =
880b57cec5SDimitry Andric dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod()))
890b57cec5SDimitry Andric return FD;
900b57cec5SDimitry Andric return nullptr;
910b57cec5SDimitry Andric };
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric auto getMangledNames = [](const NamedDecl *ND) -> std::vector<std::string> {
940b57cec5SDimitry Andric if (!ND)
950b57cec5SDimitry Andric return {""};
960b57cec5SDimitry Andric ASTNameGenerator NameGen(ND->getASTContext());
970b57cec5SDimitry Andric std::vector<std::string> MangledNames = NameGen.getAllManglings(ND);
980b57cec5SDimitry Andric if (isa<CXXConstructorDecl>(ND) || isa<CXXDestructorDecl>(ND))
990b57cec5SDimitry Andric return MangledNames;
1000b57cec5SDimitry Andric #ifdef EXPENSIVE_CHECKS
1010b57cec5SDimitry Andric assert(MangledNames.size() <= 1 && "Expected only one name mangling.");
1020b57cec5SDimitry Andric #endif
1030b57cec5SDimitry Andric return {NameGen.getName(ND)};
1040b57cec5SDimitry Andric };
1050b57cec5SDimitry Andric
1060b57cec5SDimitry Andric if (!(RDO & FromTU))
1070b57cec5SDimitry Andric return true;
1080b57cec5SDimitry Andric if (Symbols.find(ND) != Symbols.end())
1090b57cec5SDimitry Andric return true;
1100b57cec5SDimitry Andric // - Currently have not figured out how to produce the names for FieldDecls.
1110b57cec5SDimitry Andric // - Do not want to produce symbols for function paremeters.
1120b57cec5SDimitry Andric if (isa<FieldDecl>(ND) || isa<ParmVarDecl>(ND))
1130b57cec5SDimitry Andric return true;
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric const NamedDecl *ParentDecl = getParentFunctionDecl(ND);
1160b57cec5SDimitry Andric if ((ParentDecl && ignoreDecl(ParentDecl)) || ignoreDecl(ND))
1170b57cec5SDimitry Andric return true;
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric if (RDO & IsLate) {
1200b57cec5SDimitry Andric Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)
1210b57cec5SDimitry Andric << "Generating Interface Stubs is not supported with "
1220b57cec5SDimitry Andric "delayed template parsing.";
1230b57cec5SDimitry Andric } else {
1240b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(ND))
1250b57cec5SDimitry Andric if (FD->isDependentContext())
1260b57cec5SDimitry Andric return true;
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric const bool IsWeak = (ND->hasAttr<WeakAttr>() ||
1290b57cec5SDimitry Andric ND->hasAttr<WeakRefAttr>() || ND->isWeakImported());
1300b57cec5SDimitry Andric
1310b57cec5SDimitry Andric Symbols.insert(std::make_pair(
1320b57cec5SDimitry Andric ND,
1330b57cec5SDimitry Andric MangledSymbol(getMangledNames(ParentDecl).front(),
1340b57cec5SDimitry Andric // Type:
1350b57cec5SDimitry Andric isa<VarDecl>(ND) ? llvm::ELF::STT_OBJECT
1360b57cec5SDimitry Andric : llvm::ELF::STT_FUNC,
1370b57cec5SDimitry Andric // Binding:
1380b57cec5SDimitry Andric IsWeak ? llvm::ELF::STB_WEAK : llvm::ELF::STB_GLOBAL,
1390b57cec5SDimitry Andric getMangledNames(ND))));
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric return true;
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric
1440b57cec5SDimitry Andric void
HandleDecls(const llvm::iterator_range<DeclContext::decl_iterator> & Decls,MangledSymbols & Symbols,int RDO)1450b57cec5SDimitry Andric HandleDecls(const llvm::iterator_range<DeclContext::decl_iterator> &Decls,
1460b57cec5SDimitry Andric MangledSymbols &Symbols, int RDO) {
1470b57cec5SDimitry Andric for (const auto *D : Decls)
1480b57cec5SDimitry Andric HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
HandleTemplateSpecializations(const FunctionTemplateDecl & FTD,MangledSymbols & Symbols,int RDO)1510b57cec5SDimitry Andric void HandleTemplateSpecializations(const FunctionTemplateDecl &FTD,
1520b57cec5SDimitry Andric MangledSymbols &Symbols, int RDO) {
1530b57cec5SDimitry Andric for (const auto *D : FTD.specializations())
1540b57cec5SDimitry Andric HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric
HandleTemplateSpecializations(const ClassTemplateDecl & CTD,MangledSymbols & Symbols,int RDO)1570b57cec5SDimitry Andric void HandleTemplateSpecializations(const ClassTemplateDecl &CTD,
1580b57cec5SDimitry Andric MangledSymbols &Symbols, int RDO) {
1590b57cec5SDimitry Andric for (const auto *D : CTD.specializations())
1600b57cec5SDimitry Andric HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric
HandleNamedDecl(const NamedDecl * ND,MangledSymbols & Symbols,int RDO)1630b57cec5SDimitry Andric bool HandleNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {
1640b57cec5SDimitry Andric if (!ND)
1650b57cec5SDimitry Andric return false;
1660b57cec5SDimitry Andric
1670b57cec5SDimitry Andric switch (ND->getKind()) {
1680b57cec5SDimitry Andric default:
1690b57cec5SDimitry Andric break;
1700b57cec5SDimitry Andric case Decl::Kind::Namespace:
1710b57cec5SDimitry Andric HandleDecls(cast<NamespaceDecl>(ND)->decls(), Symbols, RDO);
1720b57cec5SDimitry Andric return true;
1730b57cec5SDimitry Andric case Decl::Kind::CXXRecord:
1740b57cec5SDimitry Andric HandleDecls(cast<CXXRecordDecl>(ND)->decls(), Symbols, RDO);
1750b57cec5SDimitry Andric return true;
1760b57cec5SDimitry Andric case Decl::Kind::ClassTemplateSpecialization:
1770b57cec5SDimitry Andric HandleDecls(cast<ClassTemplateSpecializationDecl>(ND)->decls(), Symbols,
1780b57cec5SDimitry Andric RDO);
1790b57cec5SDimitry Andric return true;
1800b57cec5SDimitry Andric case Decl::Kind::ClassTemplate:
1810b57cec5SDimitry Andric HandleTemplateSpecializations(*cast<ClassTemplateDecl>(ND), Symbols, RDO);
1820b57cec5SDimitry Andric return true;
1830b57cec5SDimitry Andric case Decl::Kind::FunctionTemplate:
1840b57cec5SDimitry Andric HandleTemplateSpecializations(*cast<FunctionTemplateDecl>(ND), Symbols,
1850b57cec5SDimitry Andric RDO);
1860b57cec5SDimitry Andric return true;
187a7dea167SDimitry Andric case Decl::Kind::Record:
188a7dea167SDimitry Andric case Decl::Kind::Typedef:
189a7dea167SDimitry Andric case Decl::Kind::Enum:
190a7dea167SDimitry Andric case Decl::Kind::EnumConstant:
1910b57cec5SDimitry Andric case Decl::Kind::TemplateTypeParm:
192480093f4SDimitry Andric case Decl::Kind::NonTypeTemplateParm:
193480093f4SDimitry Andric case Decl::Kind::CXXConversion:
194480093f4SDimitry Andric case Decl::Kind::UnresolvedUsingValue:
195480093f4SDimitry Andric case Decl::Kind::Using:
196480093f4SDimitry Andric case Decl::Kind::UsingShadow:
197480093f4SDimitry Andric case Decl::Kind::TypeAliasTemplate:
198480093f4SDimitry Andric case Decl::Kind::TypeAlias:
199480093f4SDimitry Andric case Decl::Kind::VarTemplate:
200480093f4SDimitry Andric case Decl::Kind::VarTemplateSpecialization:
201480093f4SDimitry Andric case Decl::Kind::UsingDirective:
202480093f4SDimitry Andric case Decl::Kind::TemplateTemplateParm:
203480093f4SDimitry Andric case Decl::Kind::ClassTemplatePartialSpecialization:
204480093f4SDimitry Andric case Decl::Kind::IndirectField:
205480093f4SDimitry Andric case Decl::Kind::ConstructorUsingShadow:
206480093f4SDimitry Andric case Decl::Kind::CXXDeductionGuide:
207480093f4SDimitry Andric case Decl::Kind::NamespaceAlias:
208480093f4SDimitry Andric case Decl::Kind::UnresolvedUsingTypename:
2090b57cec5SDimitry Andric return true;
210480093f4SDimitry Andric case Decl::Kind::Var: {
211480093f4SDimitry Andric // Bail on any VarDecl that either has no named symbol.
212480093f4SDimitry Andric if (!ND->getIdentifier())
213480093f4SDimitry Andric return true;
214480093f4SDimitry Andric const auto *VD = cast<VarDecl>(ND);
215480093f4SDimitry Andric // Bail on any VarDecl that is a dependent or templated type.
216480093f4SDimitry Andric if (VD->isTemplated() || VD->getType()->isDependentType())
217480093f4SDimitry Andric return true;
218480093f4SDimitry Andric if (WriteNamedDecl(ND, Symbols, RDO))
219480093f4SDimitry Andric return true;
220480093f4SDimitry Andric break;
221480093f4SDimitry Andric }
2220b57cec5SDimitry Andric case Decl::Kind::ParmVar:
2230b57cec5SDimitry Andric case Decl::Kind::CXXMethod:
2240b57cec5SDimitry Andric case Decl::Kind::CXXConstructor:
2250b57cec5SDimitry Andric case Decl::Kind::CXXDestructor:
2260b57cec5SDimitry Andric case Decl::Kind::Function:
2270b57cec5SDimitry Andric case Decl::Kind::Field:
2280b57cec5SDimitry Andric if (WriteNamedDecl(ND, Symbols, RDO))
2290b57cec5SDimitry Andric return true;
2300b57cec5SDimitry Andric }
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric // While interface stubs are in the development stage, it's probably best to
2330b57cec5SDimitry Andric // catch anything that's not a VarDecl or Template/FunctionDecl.
2340b57cec5SDimitry Andric Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)
2350b57cec5SDimitry Andric << "Expected a function or function template decl.";
2360b57cec5SDimitry Andric return false;
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric public:
InterfaceStubFunctionsConsumer(CompilerInstance & Instance,StringRef InFile,StringRef Format)2400b57cec5SDimitry Andric InterfaceStubFunctionsConsumer(CompilerInstance &Instance, StringRef InFile,
2410b57cec5SDimitry Andric StringRef Format)
2420b57cec5SDimitry Andric : Instance(Instance), InFile(InFile), Format(Format) {}
2430b57cec5SDimitry Andric
HandleTranslationUnit(ASTContext & context)2440b57cec5SDimitry Andric void HandleTranslationUnit(ASTContext &context) override {
2450b57cec5SDimitry Andric struct Visitor : public RecursiveASTVisitor<Visitor> {
2460b57cec5SDimitry Andric bool VisitNamedDecl(NamedDecl *ND) {
2470b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(ND))
2480b57cec5SDimitry Andric if (FD->isLateTemplateParsed()) {
2490b57cec5SDimitry Andric LateParsedDecls.insert(FD);
2500b57cec5SDimitry Andric return true;
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
2530b57cec5SDimitry Andric if (const auto *VD = dyn_cast<ValueDecl>(ND)) {
2540b57cec5SDimitry Andric ValueDecls.insert(VD);
2550b57cec5SDimitry Andric return true;
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric
2580b57cec5SDimitry Andric NamedDecls.insert(ND);
2590b57cec5SDimitry Andric return true;
2600b57cec5SDimitry Andric }
2610b57cec5SDimitry Andric
2620b57cec5SDimitry Andric std::set<const NamedDecl *> LateParsedDecls;
2630b57cec5SDimitry Andric std::set<NamedDecl *> NamedDecls;
2640b57cec5SDimitry Andric std::set<const ValueDecl *> ValueDecls;
2650b57cec5SDimitry Andric } v;
2660b57cec5SDimitry Andric
2670b57cec5SDimitry Andric v.TraverseDecl(context.getTranslationUnitDecl());
2680b57cec5SDimitry Andric
2690b57cec5SDimitry Andric MangledSymbols Symbols;
2700b57cec5SDimitry Andric auto OS = Instance.createDefaultOutputFile(/*Binary=*/false, InFile, "ifs");
2710b57cec5SDimitry Andric if (!OS)
2720b57cec5SDimitry Andric return;
2730b57cec5SDimitry Andric
2740b57cec5SDimitry Andric if (Instance.getLangOpts().DelayedTemplateParsing) {
2750b57cec5SDimitry Andric clang::Sema &S = Instance.getSema();
2760b57cec5SDimitry Andric for (const auto *FD : v.LateParsedDecls) {
2770b57cec5SDimitry Andric clang::LateParsedTemplate &LPT =
2780b57cec5SDimitry Andric *S.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second;
2790b57cec5SDimitry Andric S.LateTemplateParser(S.OpaqueParser, LPT);
2800b57cec5SDimitry Andric HandleNamedDecl(FD, Symbols, (FromTU | IsLate));
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric }
2830b57cec5SDimitry Andric
2840b57cec5SDimitry Andric for (const NamedDecl *ND : v.ValueDecls)
2850b57cec5SDimitry Andric HandleNamedDecl(ND, Symbols, FromTU);
2860b57cec5SDimitry Andric for (const NamedDecl *ND : v.NamedDecls)
2870b57cec5SDimitry Andric HandleNamedDecl(ND, Symbols, FromTU);
2880b57cec5SDimitry Andric
289480093f4SDimitry Andric auto writeIfsV1 = [this](const llvm::Triple &T,
290480093f4SDimitry Andric const MangledSymbols &Symbols,
2910b57cec5SDimitry Andric const ASTContext &context, StringRef Format,
2920b57cec5SDimitry Andric raw_ostream &OS) -> void {
2930b57cec5SDimitry Andric OS << "--- !" << Format << "\n";
294fe6060f1SDimitry Andric OS << "IfsVersion: 3.0\n";
295fe6060f1SDimitry Andric OS << "Target: " << T.str() << "\n";
2960b57cec5SDimitry Andric OS << "Symbols:\n";
2970b57cec5SDimitry Andric for (const auto &E : Symbols) {
2980b57cec5SDimitry Andric const MangledSymbol &Symbol = E.second;
299*0fca6ea1SDimitry Andric for (const auto &Name : Symbol.Names) {
3005ffd83dbSDimitry Andric OS << " - { Name: \""
3010b57cec5SDimitry Andric << (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus
3020b57cec5SDimitry Andric ? ""
3030b57cec5SDimitry Andric : (Symbol.ParentName + "."))
3045ffd83dbSDimitry Andric << Name << "\", Type: ";
3050b57cec5SDimitry Andric switch (Symbol.Type) {
3060b57cec5SDimitry Andric default:
3070b57cec5SDimitry Andric llvm_unreachable(
308a7dea167SDimitry Andric "clang -emit-interface-stubs: Unexpected symbol type.");
3090b57cec5SDimitry Andric case llvm::ELF::STT_NOTYPE:
3100b57cec5SDimitry Andric OS << "NoType";
3110b57cec5SDimitry Andric break;
3120b57cec5SDimitry Andric case llvm::ELF::STT_OBJECT: {
3130b57cec5SDimitry Andric auto VD = cast<ValueDecl>(E.first)->getType();
3140b57cec5SDimitry Andric OS << "Object, Size: "
3150b57cec5SDimitry Andric << context.getTypeSizeInChars(VD).getQuantity();
3160b57cec5SDimitry Andric break;
3170b57cec5SDimitry Andric }
3180b57cec5SDimitry Andric case llvm::ELF::STT_FUNC:
3190b57cec5SDimitry Andric OS << "Func";
3200b57cec5SDimitry Andric break;
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric if (Symbol.Binding == llvm::ELF::STB_WEAK)
3230b57cec5SDimitry Andric OS << ", Weak: true";
3240b57cec5SDimitry Andric OS << " }\n";
3250b57cec5SDimitry Andric }
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric OS << "...\n";
3280b57cec5SDimitry Andric OS.flush();
3290b57cec5SDimitry Andric };
3300b57cec5SDimitry Andric
331fe6060f1SDimitry Andric assert(Format == "ifs-v1" && "Unexpected IFS Format.");
332a7dea167SDimitry Andric writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS);
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric };
335a7dea167SDimitry Andric } // namespace
3360b57cec5SDimitry Andric
3370b57cec5SDimitry Andric std::unique_ptr<ASTConsumer>
CreateASTConsumer(CompilerInstance & CI,StringRef InFile)3385ffd83dbSDimitry Andric GenerateInterfaceStubsAction::CreateASTConsumer(CompilerInstance &CI,
3390b57cec5SDimitry Andric StringRef InFile) {
340fe6060f1SDimitry Andric return std::make_unique<InterfaceStubFunctionsConsumer>(CI, InFile, "ifs-v1");
3410b57cec5SDimitry Andric }
342