xref: /freebsd/contrib/llvm-project/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp (revision 2ed24e28d1d95c62cc37ca3534d4d33360b4cef2)
1  //===--- InterfaceStubFunctionsConsumer.cpp -------------------------------===//
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/AST/Mangle.h"
10  #include "clang/AST/RecursiveASTVisitor.h"
11  #include "clang/Basic/TargetInfo.h"
12  #include "clang/Frontend/CompilerInstance.h"
13  #include "clang/Frontend/FrontendActions.h"
14  #include "clang/Sema/TemplateInstCallback.h"
15  #include "llvm/BinaryFormat/ELF.h"
16  
17  using namespace clang;
18  
19  namespace {
20  class InterfaceStubFunctionsConsumer : public ASTConsumer {
21    CompilerInstance &Instance;
22    StringRef InFile;
23    StringRef Format;
24    std::set<std::string> ParsedTemplates;
25  
26    enum RootDeclOrigin { TopLevel = 0, FromTU = 1, IsLate = 2 };
27    struct MangledSymbol {
28      std::string ParentName;
29      uint8_t Type;
30      uint8_t Binding;
31      std::vector<std::string> Names;
32      MangledSymbol() = delete;
33  
34      MangledSymbol(const std::string &ParentName, uint8_t Type, uint8_t Binding,
35                    std::vector<std::string> Names)
36          : ParentName(ParentName), Type(Type), Binding(Binding),
37            Names(std::move(Names)) {}
38    };
39    using MangledSymbols = std::map<const NamedDecl *, MangledSymbol>;
40  
41    bool WriteNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {
42      // Here we filter out anything that's not set to DefaultVisibility.
43      // DefaultVisibility is set on a decl when -fvisibility is not specified on
44      // the command line (or specified as default) and the decl does not have
45      // __attribute__((visibility("hidden"))) set or when the command line
46      // argument is set to hidden but the decl explicitly has
47      // __attribute__((visibility ("default"))) set. We do this so that the user
48      // can have fine grain control of what they want to expose in the stub.
49      auto isVisible = [](const NamedDecl *ND) -> bool {
50        return ND->getVisibility() == DefaultVisibility;
51      };
52  
53      auto ignoreDecl = [this, isVisible](const NamedDecl *ND) -> bool {
54        if (!isVisible(ND))
55          return true;
56  
57        if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) {
58          if (const auto *Parent = VD->getParentFunctionOrMethod())
59            if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent))
60              return true;
61  
62          if ((VD->getStorageClass() == StorageClass::SC_Extern) ||
63              (VD->getStorageClass() == StorageClass::SC_Static &&
64               VD->getParentFunctionOrMethod() == nullptr))
65            return true;
66        }
67  
68        if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
69          if (FD->isInlined() && !isa<CXXMethodDecl>(FD) &&
70              !Instance.getLangOpts().GNUInline)
71            return true;
72          if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
73            if (const auto *RC = dyn_cast<CXXRecordDecl>(MD->getParent()))
74              if (isa<ClassTemplateDecl>(RC->getParent()) || !isVisible(RC))
75                return true;
76            if (MD->isDependentContext() || !MD->hasBody())
77              return true;
78          }
79          if (FD->getStorageClass() == StorageClass::SC_Static)
80            return true;
81        }
82        return false;
83      };
84  
85      auto getParentFunctionDecl = [](const NamedDecl *ND) -> const NamedDecl * {
86        if (const VarDecl *VD = dyn_cast<VarDecl>(ND))
87          if (const auto *FD =
88                  dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod()))
89            return FD;
90        return nullptr;
91      };
92  
93      auto getMangledNames = [](const NamedDecl *ND) -> std::vector<std::string> {
94        if (!ND)
95          return {""};
96        ASTNameGenerator NameGen(ND->getASTContext());
97        std::vector<std::string> MangledNames = NameGen.getAllManglings(ND);
98        if (isa<CXXConstructorDecl>(ND) || isa<CXXDestructorDecl>(ND))
99          return MangledNames;
100  #ifdef EXPENSIVE_CHECKS
101        assert(MangledNames.size() <= 1 && "Expected only one name mangling.");
102  #endif
103        return {NameGen.getName(ND)};
104      };
105  
106      if (!(RDO & FromTU))
107        return true;
108      if (Symbols.find(ND) != Symbols.end())
109        return true;
110      // - Currently have not figured out how to produce the names for FieldDecls.
111      // - Do not want to produce symbols for function paremeters.
112      if (isa<FieldDecl>(ND) || isa<ParmVarDecl>(ND))
113        return true;
114  
115      const NamedDecl *ParentDecl = getParentFunctionDecl(ND);
116      if ((ParentDecl && ignoreDecl(ParentDecl)) || ignoreDecl(ND))
117        return true;
118  
119      if (RDO & IsLate) {
120        Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)
121            << "Generating Interface Stubs is not supported with "
122               "delayed template parsing.";
123      } else {
124        if (const auto *FD = dyn_cast<FunctionDecl>(ND))
125          if (FD->isDependentContext())
126            return true;
127  
128        const bool IsWeak = (ND->hasAttr<WeakAttr>() ||
129                             ND->hasAttr<WeakRefAttr>() || ND->isWeakImported());
130  
131        Symbols.insert(std::make_pair(
132            ND,
133            MangledSymbol(getMangledNames(ParentDecl).front(),
134                          // Type:
135                          isa<VarDecl>(ND) ? llvm::ELF::STT_OBJECT
136                                           : llvm::ELF::STT_FUNC,
137                          // Binding:
138                          IsWeak ? llvm::ELF::STB_WEAK : llvm::ELF::STB_GLOBAL,
139                          getMangledNames(ND))));
140      }
141      return true;
142    }
143  
144    void
145    HandleDecls(const llvm::iterator_range<DeclContext::decl_iterator> &Decls,
146                MangledSymbols &Symbols, int RDO) {
147      for (const auto *D : Decls)
148        HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
149    }
150  
151    void HandleTemplateSpecializations(const FunctionTemplateDecl &FTD,
152                                       MangledSymbols &Symbols, int RDO) {
153      for (const auto *D : FTD.specializations())
154        HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
155    }
156  
157    void HandleTemplateSpecializations(const ClassTemplateDecl &CTD,
158                                       MangledSymbols &Symbols, int RDO) {
159      for (const auto *D : CTD.specializations())
160        HandleNamedDecl(dyn_cast<NamedDecl>(D), Symbols, RDO);
161    }
162  
163    bool HandleNamedDecl(const NamedDecl *ND, MangledSymbols &Symbols, int RDO) {
164      if (!ND)
165        return false;
166  
167      switch (ND->getKind()) {
168      default:
169        break;
170      case Decl::Kind::Namespace:
171        HandleDecls(cast<NamespaceDecl>(ND)->decls(), Symbols, RDO);
172        return true;
173      case Decl::Kind::CXXRecord:
174        HandleDecls(cast<CXXRecordDecl>(ND)->decls(), Symbols, RDO);
175        return true;
176      case Decl::Kind::ClassTemplateSpecialization:
177        HandleDecls(cast<ClassTemplateSpecializationDecl>(ND)->decls(), Symbols,
178                    RDO);
179        return true;
180      case Decl::Kind::ClassTemplate:
181        HandleTemplateSpecializations(*cast<ClassTemplateDecl>(ND), Symbols, RDO);
182        return true;
183      case Decl::Kind::FunctionTemplate:
184        HandleTemplateSpecializations(*cast<FunctionTemplateDecl>(ND), Symbols,
185                                      RDO);
186        return true;
187      case Decl::Kind::Record:
188      case Decl::Kind::Typedef:
189      case Decl::Kind::Enum:
190      case Decl::Kind::EnumConstant:
191      case Decl::Kind::TemplateTypeParm:
192      case Decl::Kind::NonTypeTemplateParm:
193      case Decl::Kind::CXXConversion:
194      case Decl::Kind::UnresolvedUsingValue:
195      case Decl::Kind::Using:
196      case Decl::Kind::UsingShadow:
197      case Decl::Kind::TypeAliasTemplate:
198      case Decl::Kind::TypeAlias:
199      case Decl::Kind::VarTemplate:
200      case Decl::Kind::VarTemplateSpecialization:
201      case Decl::Kind::UsingDirective:
202      case Decl::Kind::TemplateTemplateParm:
203      case Decl::Kind::ClassTemplatePartialSpecialization:
204      case Decl::Kind::IndirectField:
205      case Decl::Kind::ConstructorUsingShadow:
206      case Decl::Kind::CXXDeductionGuide:
207      case Decl::Kind::NamespaceAlias:
208      case Decl::Kind::UnresolvedUsingTypename:
209        return true;
210      case Decl::Kind::Var: {
211        // Bail on any VarDecl that either has no named symbol.
212        if (!ND->getIdentifier())
213          return true;
214        const auto *VD = cast<VarDecl>(ND);
215        // Bail on any VarDecl that is a dependent or templated type.
216        if (VD->isTemplated() || VD->getType()->isDependentType())
217          return true;
218        if (WriteNamedDecl(ND, Symbols, RDO))
219          return true;
220        break;
221      }
222      case Decl::Kind::ParmVar:
223      case Decl::Kind::CXXMethod:
224      case Decl::Kind::CXXConstructor:
225      case Decl::Kind::CXXDestructor:
226      case Decl::Kind::Function:
227      case Decl::Kind::Field:
228        if (WriteNamedDecl(ND, Symbols, RDO))
229          return true;
230      }
231  
232      // While interface stubs are in the development stage, it's probably best to
233      // catch anything that's not a VarDecl or Template/FunctionDecl.
234      Instance.getDiagnostics().Report(diag::err_asm_invalid_type_in_input)
235          << "Expected a function or function template decl.";
236      return false;
237    }
238  
239  public:
240    InterfaceStubFunctionsConsumer(CompilerInstance &Instance, StringRef InFile,
241                                   StringRef Format)
242        : Instance(Instance), InFile(InFile), Format(Format) {}
243  
244    void HandleTranslationUnit(ASTContext &context) override {
245      struct Visitor : public RecursiveASTVisitor<Visitor> {
246        bool VisitNamedDecl(NamedDecl *ND) {
247          if (const auto *FD = dyn_cast<FunctionDecl>(ND))
248            if (FD->isLateTemplateParsed()) {
249              LateParsedDecls.insert(FD);
250              return true;
251            }
252  
253          if (const auto *VD = dyn_cast<ValueDecl>(ND)) {
254            ValueDecls.insert(VD);
255            return true;
256          }
257  
258          NamedDecls.insert(ND);
259          return true;
260        }
261  
262        std::set<const NamedDecl *> LateParsedDecls;
263        std::set<NamedDecl *> NamedDecls;
264        std::set<const ValueDecl *> ValueDecls;
265      } v;
266  
267      v.TraverseDecl(context.getTranslationUnitDecl());
268  
269      MangledSymbols Symbols;
270      auto OS = Instance.createDefaultOutputFile(/*Binary=*/false, InFile, "ifs");
271      if (!OS)
272        return;
273  
274      if (Instance.getLangOpts().DelayedTemplateParsing) {
275        clang::Sema &S = Instance.getSema();
276        for (const auto *FD : v.LateParsedDecls) {
277          clang::LateParsedTemplate &LPT =
278              *S.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second;
279          S.LateTemplateParser(S.OpaqueParser, LPT);
280          HandleNamedDecl(FD, Symbols, (FromTU | IsLate));
281        }
282      }
283  
284      for (const NamedDecl *ND : v.ValueDecls)
285        HandleNamedDecl(ND, Symbols, FromTU);
286      for (const NamedDecl *ND : v.NamedDecls)
287        HandleNamedDecl(ND, Symbols, FromTU);
288  
289      auto writeIfsV1 = [this](const llvm::Triple &T,
290                               const MangledSymbols &Symbols,
291                               const ASTContext &context, StringRef Format,
292                               raw_ostream &OS) -> void {
293        OS << "--- !" << Format << "\n";
294        OS << "IfsVersion: 3.0\n";
295        OS << "Target: " << T.str() << "\n";
296        OS << "Symbols:\n";
297        for (const auto &E : Symbols) {
298          const MangledSymbol &Symbol = E.second;
299          for (const auto &Name : Symbol.Names) {
300            OS << "  - { Name: \""
301               << (Symbol.ParentName.empty() || Instance.getLangOpts().CPlusPlus
302                       ? ""
303                       : (Symbol.ParentName + "."))
304               << Name << "\", Type: ";
305            switch (Symbol.Type) {
306            default:
307              llvm_unreachable(
308                  "clang -emit-interface-stubs: Unexpected symbol type.");
309            case llvm::ELF::STT_NOTYPE:
310              OS << "NoType";
311              break;
312            case llvm::ELF::STT_OBJECT: {
313              auto VD = cast<ValueDecl>(E.first)->getType();
314              OS << "Object, Size: "
315                 << context.getTypeSizeInChars(VD).getQuantity();
316              break;
317            }
318            case llvm::ELF::STT_FUNC:
319              OS << "Func";
320              break;
321            }
322            if (Symbol.Binding == llvm::ELF::STB_WEAK)
323              OS << ", Weak: true";
324            OS << " }\n";
325          }
326        }
327        OS << "...\n";
328        OS.flush();
329      };
330  
331      assert(Format == "ifs-v1" && "Unexpected IFS Format.");
332      writeIfsV1(Instance.getTarget().getTriple(), Symbols, context, Format, *OS);
333    }
334  };
335  } // namespace
336  
337  std::unique_ptr<ASTConsumer>
338  GenerateInterfaceStubsAction::CreateASTConsumer(CompilerInstance &CI,
339                                                  StringRef InFile) {
340    return std::make_unique<InterfaceStubFunctionsConsumer>(CI, InFile, "ifs-v1");
341  }
342