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