diff options
author | 2020-08-03 14:33:06 +0000 | |
---|---|---|
committer | 2020-08-03 14:33:06 +0000 | |
commit | 061da546b983eb767bad15e67af1174fb0bcf31c (patch) | |
tree | 83c78b820819d70aa40c36d90447978b300078c5 /gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp | |
parent | Import LLVM 10.0.0 release including clang, lld and lldb. (diff) | |
download | wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.tar.xz wireguard-openbsd-061da546b983eb767bad15e67af1174fb0bcf31c.zip |
Import LLVM 10.0.0 release including clang, lld and lldb.
ok hackroom
tested by plenty
Diffstat (limited to 'gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp')
-rw-r--r-- | gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp b/gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp new file mode 100644 index 00000000000..19e80e5036b --- /dev/null +++ b/gnu/llvm/lldb/source/Symbol/CxxModuleHandler.cpp @@ -0,0 +1,289 @@ +//===-- CxxModuleHandler.cpp ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Symbol/CxxModuleHandler.h" + +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Utility/Log.h" +#include "clang/Sema/Lookup.h" +#include "llvm/Support/Error.h" + +using namespace lldb_private; +using namespace clang; + +CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) + : m_importer(&importer), + m_sema(ClangASTContext::GetASTContext(target)->getSema()) { + + std::initializer_list<const char *> supported_names = { + // containers + "deque", + "forward_list", + "list", + "queue", + "stack", + "vector", + // pointers + "shared_ptr", + "unique_ptr", + "weak_ptr", + // utility + "allocator", + }; + m_supported_templates.insert(supported_names.begin(), supported_names.end()); +} + +/// Builds a list of scopes that point into the given context. +/// +/// \param sema The sema that will be using the scopes. +/// \param ctxt The context that the scope should look into. +/// \param result A list of scopes. The scopes need to be freed by the caller +/// (except the TUScope which is owned by the sema). +static void makeScopes(Sema &sema, DeclContext *ctxt, + std::vector<Scope *> &result) { + // FIXME: The result should be a list of unique_ptrs, but the TUScope makes + // this currently impossible as it's owned by the Sema. + + if (auto parent = ctxt->getParent()) { + makeScopes(sema, parent, result); + + Scope *scope = + new Scope(result.back(), Scope::DeclScope, sema.getDiagnostics()); + scope->setEntity(ctxt); + result.push_back(scope); + } else + result.push_back(sema.TUScope); +} + +/// Uses the Sema to look up the given name in the given DeclContext. +static std::unique_ptr<LookupResult> +emulateLookupInCtxt(Sema &sema, llvm::StringRef name, DeclContext *ctxt) { + IdentifierInfo &ident = sema.getASTContext().Idents.get(name); + + std::unique_ptr<LookupResult> lookup_result; + lookup_result.reset(new LookupResult(sema, DeclarationName(&ident), + SourceLocation(), + Sema::LookupOrdinaryName)); + + // Usually during parsing we already encountered the scopes we would use. But + // here don't have these scopes so we have to emulate the behavior of the + // Sema during parsing. + std::vector<Scope *> scopes; + makeScopes(sema, ctxt, scopes); + + // Now actually perform the lookup with the sema. + sema.LookupName(*lookup_result, scopes.back()); + + // Delete all the allocated scopes beside the translation unit scope (which + // has depth 0). + for (Scope *s : scopes) + if (s->getDepth() != 0) + delete s; + + return lookup_result; +} + +/// Error class for handling problems when finding a certain DeclContext. +struct MissingDeclContext : public llvm::ErrorInfo<MissingDeclContext> { + + static char ID; + + MissingDeclContext(DeclContext *context, std::string error) + : m_context(context), m_error(error) {} + + DeclContext *m_context; + std::string m_error; + + void log(llvm::raw_ostream &OS) const override { + OS << llvm::formatv("error when reconstructing context of kind {0}:{1}", + m_context->getDeclKindName(), m_error); + } + + std::error_code convertToErrorCode() const override { + return llvm::inconvertibleErrorCode(); + } +}; + +char MissingDeclContext::ID = 0; + +/// Given a foreign decl context, this function finds the equivalent local +/// decl context in the ASTContext of the given Sema. Potentially deserializes +/// decls from the 'std' module if necessary. +static llvm::Expected<DeclContext *> +getEqualLocalDeclContext(Sema &sema, DeclContext *foreign_ctxt) { + + // Inline namespaces don't matter for lookups, so let's skip them. + while (foreign_ctxt && foreign_ctxt->isInlineNamespace()) + foreign_ctxt = foreign_ctxt->getParent(); + + // If the foreign context is the TU, we just return the local TU. + if (foreign_ctxt->isTranslationUnit()) + return sema.getASTContext().getTranslationUnitDecl(); + + // Recursively find/build the parent DeclContext. + llvm::Expected<DeclContext *> parent = + getEqualLocalDeclContext(sema, foreign_ctxt->getParent()); + if (!parent) + return parent; + + // We currently only support building namespaces. + if (foreign_ctxt->isNamespace()) { + NamedDecl *ns = llvm::dyn_cast<NamedDecl>(foreign_ctxt); + llvm::StringRef ns_name = ns->getName(); + + auto lookup_result = emulateLookupInCtxt(sema, ns_name, *parent); + for (NamedDecl *named_decl : *lookup_result) { + if (DeclContext *DC = llvm::dyn_cast<DeclContext>(named_decl)) + return DC->getPrimaryContext(); + } + return llvm::make_error<MissingDeclContext>( + foreign_ctxt, + "Couldn't find namespace " + ns->getQualifiedNameAsString()); + } + + return llvm::make_error<MissingDeclContext>(foreign_ctxt, "Unknown context "); +} + +/// Returns true iff tryInstantiateStdTemplate supports instantiating a template +/// with the given template arguments. +static bool templateArgsAreSupported(ArrayRef<TemplateArgument> a) { + for (const TemplateArgument &arg : a) { + switch (arg.getKind()) { + case TemplateArgument::Type: + case TemplateArgument::Integral: + break; + default: + // TemplateArgument kind hasn't been handled yet. + return false; + } + } + return true; +} + +/// Constructor function for Clang declarations. Ensures that the created +/// declaration is registered with the ASTImporter. +template <typename T, typename... Args> +T *createDecl(ASTImporter &importer, Decl *from_d, Args &&... args) { + T *to_d = T::Create(std::forward<Args>(args)...); + importer.RegisterImportedDecl(from_d, to_d); + return to_d; +} + +llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS); + + // If we don't have a template to instiantiate, then there is nothing to do. + auto td = dyn_cast<ClassTemplateSpecializationDecl>(d); + if (!td) + return {}; + + // We only care about templates in the std namespace. + if (!td->getDeclContext()->isStdNamespace()) + return {}; + + // We have a whitelist of supported template names. + if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) + return {}; + + // Early check if we even support instantiating this template. We do this + // before we import anything into the target AST. + auto &foreign_args = td->getTemplateInstantiationArgs(); + if (!templateArgsAreSupported(foreign_args.asArray())) + return {}; + + // Find the local DeclContext that corresponds to the DeclContext of our + // decl we want to import. + llvm::Expected<DeclContext *> to_context = + getEqualLocalDeclContext(*m_sema, td->getDeclContext()); + if (!to_context) { + LLDB_LOG_ERROR(log, to_context.takeError(), + "Got error while searching equal local DeclContext for decl " + "'{1}':\n{0}", + td->getName()); + return {}; + } + + // Look up the template in our local context. + std::unique_ptr<LookupResult> lookup = + emulateLookupInCtxt(*m_sema, td->getName(), *to_context); + + ClassTemplateDecl *new_class_template = nullptr; + for (auto LD : *lookup) { + if ((new_class_template = dyn_cast<ClassTemplateDecl>(LD))) + break; + } + if (!new_class_template) + return {}; + + // Import the foreign template arguments. + llvm::SmallVector<TemplateArgument, 4> imported_args; + + // If this logic is changed, also update templateArgsAreSupported. + for (const TemplateArgument &arg : foreign_args.asArray()) { + switch (arg.getKind()) { + case TemplateArgument::Type: { + llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); + if (!type) { + LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); + return {}; + } + imported_args.push_back(TemplateArgument(*type)); + break; + } + case TemplateArgument::Integral: { + llvm::APSInt integral = arg.getAsIntegral(); + llvm::Expected<QualType> type = + m_importer->Import(arg.getIntegralType()); + if (!type) { + LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); + return {}; + } + imported_args.push_back( + TemplateArgument(d->getASTContext(), integral, *type)); + break; + } + default: + assert(false && "templateArgsAreSupported not updated?"); + } + } + + // Find the class template specialization declaration that + // corresponds to these arguments. + void *InsertPos = nullptr; + ClassTemplateSpecializationDecl *result = + new_class_template->findSpecialization(imported_args, InsertPos); + + if (result) { + // We found an existing specialization in the module that fits our arguments + // so we can treat it as the result and register it with the ASTImporter. + m_importer->RegisterImportedDecl(d, result); + return result; + } + + // Instantiate the template. + result = createDecl<ClassTemplateSpecializationDecl>( + *m_importer, d, m_sema->getASTContext(), + new_class_template->getTemplatedDecl()->getTagKind(), + new_class_template->getDeclContext(), + new_class_template->getTemplatedDecl()->getLocation(), + new_class_template->getLocation(), new_class_template, imported_args, + nullptr); + + new_class_template->AddSpecialization(result, InsertPos); + if (new_class_template->isOutOfLine()) + result->setLexicalDeclContext( + new_class_template->getLexicalDeclContext()); + return result; +} + +llvm::Optional<Decl *> CxxModuleHandler::Import(Decl *d) { + if (!isValid()) + return {}; + + return tryInstantiateStdTemplate(d); +} |