clang  19.0.0git
InterfaceStubFunctionsConsumer.cpp
Go to the documentation of this file.
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"
11 #include "clang/Basic/TargetInfo.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) {
278  *S.LateParsedTemplateMap.find(cast<FunctionDecl>(FD))->second;
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>
339  StringRef InFile) {
340  return std::make_unique<InterfaceStubFunctionsConsumer>(CI, InFile, "ifs-v1");
341 }
NodeId Parent
Definition: ASTDiff.cpp:191
llvm::MachO::Record Record
Definition: MachO.h:31
do v
Definition: arm_acle.h:83
ASTConsumer - This is an abstract interface that should be implemented by clients that read ASTs.
Definition: ASTConsumer.h:33
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:185
TranslationUnitDecl * getTranslationUnitDecl() const
Definition: ASTContext.h:1076
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:2060
Declaration of a class template.
spec_range specializations() const
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
ASTContext & getASTContext() const LLVM_READONLY
Definition: DeclBase.cpp:501
bool isWeakImported() const
Determine whether this is a weak-imported symbol.
Definition: DeclBase.cpp:820
bool hasAttr() const
Definition: DeclBase.h:583
Kind getKind() const
Definition: DeclBase.h:448
Represents a function declaration or definition.
Definition: Decl.h:1972
Declaration of a template function.
Definition: DeclTemplate.h:957
spec_range specializations() const
std::unique_ptr< ASTConsumer > CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override
Create the AST consumer object for this action, if supported.
This represents a decl that may have a name.
Definition: Decl.h:249
Visibility getVisibility() const
Determines the visibility of this entity.
Definition: Decl.h:420
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:270
A class that does preorder or postorder depth-first traversal on the entire Clang AST and visits each...
Sema - This implements semantic analysis and AST building for C.
Definition: Sema.h:462
LateParsedTemplateMapT LateParsedTemplateMap
Definition: Sema.h:8916
void * OpaqueParser
Definition: Sema.h:904
LateTemplateParserCB * LateTemplateParser
Definition: Sema.h:902
The base class of the type hierarchy.
Definition: Type.h:1813
Represents a variable declaration or definition.
Definition: Decl.h:919
Defines the clang::TargetInfo interface.
The JSON file list parser is used to communicate input to InstallAPI.
@ SC_Extern
Definition: Specifiers.h:248
@ SC_Static
Definition: Specifiers.h:249
const FunctionProtoType * T
@ DefaultVisibility
Objects with "default" visibility are seen by the dynamic linker and act like normal objects.
Definition: Visibility.h:46
Definition: Format.h:5433
Contains a late templated function.
Definition: Sema.h:11915