teemperor updated this revision to Diff 196962. teemperor edited the summary of this revision. teemperor added a comment.
- Renamed to CxxModuleHandler as I want to reuse most of code later for decl importing from generic modules. - Moved declaration construction into it's own templated method similar to the way the ASTImporter is handling decl construction. - Make sure we register all created decls with the ASTImporter to prevent triggering the new assert in ASTImporter::Import_New(Decl *d). CHANGES SINCE LAST ACTION https://reviews.llvm.org/D59537/new/ https://reviews.llvm.org/D59537 Files: lldb/include/lldb/Symbol/ClangASTContext.h lldb/include/lldb/Symbol/ClangASTImporter.h lldb/include/lldb/Symbol/CxxModuleHandler.h lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/TestBasicDeque.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/TestDbgInfoContentDeque.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/TestBasicForwardList.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/TestDbgInfoContentForwardList.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/TestBasicList.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/TestDbgInfoContentList.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/TestSharedPtrDbgInfoContent.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/TestSharedPtr.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/TestUniquePtrDbgInfoContent.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/TestUniquePtr.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/TestBasicVector.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/TestBoolVector.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/TestDbgInfoContentVector.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/TestVectorOfVectors.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/TestDbgInfoContentWeakPtr.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/main.cpp lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/Makefile lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/TestWeakPtr.py lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/main.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp lldb/source/Symbol/CMakeLists.txt lldb/source/Symbol/ClangASTContext.cpp lldb/source/Symbol/ClangASTImporter.cpp lldb/source/Symbol/CxxModuleHandler.cpp
Index: lldb/source/Symbol/CxxModuleHandler.cpp =================================================================== --- /dev/null +++ lldb/source/Symbol/CxxModuleHandler.cpp @@ -0,0 +1,278 @@ +//===-- 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 "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 + "vector", + "list", + "forward_list", + "deque", + // 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) { + // 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. + auto to_context = getEqualLocalDeclContext(*m_sema, td->getDeclContext()); + if (!to_context) + 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_New(arg.getAsType()); + if (!type) { + llvm::consumeError(type.takeError()); + return {}; + } + imported_args.push_back(TemplateArgument(*type)); + break; + } + case TemplateArgument::Integral: { + llvm::APSInt integral = arg.getAsIntegral(); + llvm::Expected<QualType> type = + m_importer->Import_New(arg.getIntegralType()); + if (!type) { + llvm::consumeError(type.takeError()); + 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); +} Index: lldb/source/Symbol/ClangASTImporter.cpp =================================================================== --- lldb/source/Symbol/ClangASTImporter.cpp +++ lldb/source/Symbol/ClangASTImporter.cpp @@ -16,6 +16,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" #include "llvm/Support/raw_ostream.h" #include <memory> @@ -58,6 +60,8 @@ clang::QualType type) { MinionSP minion_sp(GetMinion(dst_ast, src_ast)); + Minion::CxxModuleScope std_scope(*minion_sp, dst_ast); + if (minion_sp) return minion_sp->Import(type); @@ -99,6 +103,8 @@ minion_sp = GetMinion(dst_ast, src_ast); + Minion::CxxModuleScope std_scope(*minion_sp, dst_ast); + if (minion_sp) { clang::Decl *result = minion_sp->Import(decl); @@ -557,6 +563,7 @@ MinionSP minion_sp(GetMinion(&decl->getASTContext(), decl_origin.ctx)); + Minion::CxxModuleScope std_scope(*minion_sp, &decl->getASTContext()); if (minion_sp) minion_sp->ImportDefinitionTo(decl, decl_origin.decl); @@ -624,6 +631,8 @@ MinionSP minion_sp(GetMinion(&tag_decl->getASTContext(), decl_origin.ctx)); + Minion::CxxModuleScope std_scope(*minion_sp, &tag_decl->getASTContext()); + TagDecl *origin_tag_decl = llvm::dyn_cast<TagDecl>(decl_origin.decl); for (Decl *origin_child_decl : origin_tag_decl->decls()) { @@ -816,6 +825,23 @@ ClangASTImporter::MapCompleter::~MapCompleter() { return; } +llvm::Expected<Decl *> ClangASTImporter::Minion::ImportImpl(Decl *From) { + if (m_std_handler) { + llvm::Optional<Decl *> D = m_std_handler->Import(From); + if (D) { + // Make sure we don't use this decl later to map it back to it's original + // decl. The decl the CxxModuleHandler created has nothing to do with + // the one from debug info, and linking those two would just cause the + // ASTImporter to try 'updating' the module decl with the minimal one from + // the debug info. + m_decls_to_ignore.insert(*D); + return *D; + } + } + + return ASTImporter::ImportImpl(From); +} + void ClangASTImporter::Minion::InitDeportWorkQueues( std::set<clang::NamedDecl *> *decls_to_deport, std::set<clang::NamedDecl *> *decls_already_deported) { @@ -943,6 +969,11 @@ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + // Some decls shouldn't be tracked here because they were not created by + // copying 'from' to 'to'. Just exit early for those. + if (m_decls_to_ignore.find(to) != m_decls_to_ignore.end()) + return clang::ASTImporter::Imported(from, to); + lldb::user_id_t user_id = LLDB_INVALID_UID; ClangASTMetadata *metadata = m_master.GetDeclMetadata(from); if (metadata) Index: lldb/source/Symbol/ClangASTContext.cpp =================================================================== --- lldb/source/Symbol/ClangASTContext.cpp +++ lldb/source/Symbol/ClangASTContext.cpp @@ -52,6 +52,7 @@ #include "clang/Basic/TargetOptions.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/LangStandard.h" +#include "clang/Sema/Sema.h" #ifdef LLDB_DEFINED_NDEBUG_FOR_CLANG #undef NDEBUG @@ -792,6 +793,12 @@ m_pointer_byte_size = 0; } +void ClangASTContext::setSema(Sema *s) { + // Ensure that the new sema actually belongs to our ASTContext. + assert(s == nullptr || &s->getASTContext() == m_ast_up.get()); + m_sema = s; +} + const char *ClangASTContext::GetTargetTriple() { return m_target_triple.c_str(); } Index: lldb/source/Symbol/CMakeLists.txt =================================================================== --- lldb/source/Symbol/CMakeLists.txt +++ lldb/source/Symbol/CMakeLists.txt @@ -27,6 +27,7 @@ LocateSymbolFile.cpp ObjectFile.cpp PostfixExpression.cpp + CxxModuleHandler.cpp Symbol.cpp SymbolContext.cpp SymbolFile.cpp Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -967,8 +967,10 @@ *Consumer, TU_Complete, completion_consumer)); m_compiler->setASTConsumer(std::move(Consumer)); - if (ast_context.getLangOpts().Modules) + if (ast_context.getLangOpts().Modules) { m_compiler->createModuleManager(); + m_ast_context->setSema(&m_compiler->getSema()); + } ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { @@ -1005,6 +1007,10 @@ &m_compiler->getSema()); ParseAST(m_compiler->getSema(), false, false); } + + // Make sure we have no pointer to the Sema we are about to destroy. + if (ast_context.getLangOpts().Modules) + m_ast_context->setSema(nullptr); // Destroy the Sema. This is necessary because we want to emulate the // original behavior of ParseAST (which also destroys the Sema after parsing). m_compiler->setSema(nullptr); Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h +++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.h @@ -193,6 +193,8 @@ /// The NameSearchContext to use when filing results. virtual void FindExternalVisibleDecls(NameSearchContext &context); + clang::Sema *getSema(); + void SetImportInProgress(bool import_in_progress) { m_import_in_progress = import_in_progress; } Index: lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp =================================================================== --- lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -761,6 +761,10 @@ } } +clang::Sema *ClangASTSource::getSema() { + return ClangASTContext::GetASTContext(m_ast_context)->getSema(); +} + bool ClangASTSource::IgnoreName(const ConstString name, bool ignore_all_dollar_names) { static const ConstString id_name("id"); Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/main.cpp @@ -0,0 +1,8 @@ +#include <memory> + +int main(int argc, char **argv) { + std::shared_ptr<int> s(new int); + *s = 3; + std::weak_ptr<int> w = s; + return *s; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/TestWeakPtr.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/TestWeakPtr.py @@ -0,0 +1,33 @@ +""" +Test basic std::weak_ptr functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestSharedPtr(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)*w.lock()", substrs=['(int) $0 = 3']) + self.expect("expr (int)(*w.lock() = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)*w.lock()", substrs=['(int) $2 = 5']) + self.expect("expr w.use_count()", substrs=['(long) $3 = 1']) + self.expect("expr w.reset()") + self.expect("expr w.use_count()", substrs=['(long) $4 = 0']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/main.cpp @@ -0,0 +1,12 @@ +#include <memory> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::shared_ptr<Foo> s(new Foo); + s->a = 3; + std::weak_ptr<Foo> w = s; + return s->a; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/TestDbgInfoContentWeakPtr.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/TestDbgInfoContentWeakPtr.py @@ -0,0 +1,33 @@ +""" +Test std::weak_ptr functionality with a decl from debug info as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestDbgInfoContentWeakPtr(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)w.lock()->a", substrs=['(int) $0 = 3']) + self.expect("expr (int)(w.lock()->a = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)w.lock()->a", substrs=['(int) $2 = 5']) + self.expect("expr w.use_count()", substrs=['(long) $3 = 1']) + self.expect("expr w.reset()") + self.expect("expr w.use_count()", substrs=['(long) $4 = 0']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/weak_ptr-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/main.cpp @@ -0,0 +1,6 @@ +#include <vector> + +int main(int argc, char **argv) { + std::vector<std::vector<int> > a = {{1, 2, 3}, {3, 2, 1}}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/TestVectorOfVectors.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/TestVectorOfVectors.py @@ -0,0 +1,30 @@ +""" +Test std::vector functionality when it's contents are vectors. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestVectorOfVectors(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 2']) + self.expect("expr (int)a.front().front()", substrs=['(int) $1 = 1']) + self.expect("expr (int)a[1][1]", substrs=['(int) $2 = 2']) + self.expect("expr (int)a.back().at(0)", substrs=['(int) $3 = 3']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-of-vectors/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/main.cpp @@ -0,0 +1,10 @@ +#include <vector> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::vector<Foo> a = {{3}, {1}, {2}}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/TestDbgInfoContentVector.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/TestDbgInfoContentVector.py @@ -0,0 +1,47 @@ +""" +Test basic std::vector functionality but with a declaration from +the debug info (the Foo struct) as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestDbgInfoContentVector(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front().a", substrs=['(int) $1 = 3']) + self.expect("expr (int)a[1].a", substrs=['(int) $2 = 1']) + self.expect("expr (int)a.back().a", substrs=['(int) $3 = 2']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front().a", substrs=['(int) $4 = 2']) + + self.expect("expr (int)(a.begin()->a)", substrs=['(int) $5 = 2']) + self.expect("expr (int)(a.rbegin()->a)", substrs=['(int) $6 = 3']) + + self.expect("expr a.pop_back()") + self.expect("expr (int)a.back().a", substrs=['(int) $7 = 1']) + self.expect("expr (size_t)a.size()", substrs=['(size_t) $8 = 2']) + + self.expect("expr (int)a.at(0).a", substrs=['(int) $9 = 2']) + + self.expect("expr a.push_back({4})") + self.expect("expr (int)a.back().a", substrs=['(int) $10 = 4']) + self.expect("expr (size_t)a.size()", substrs=['(size_t) $11 = 3']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/main.cpp @@ -0,0 +1,6 @@ +#include <vector> + +int main(int argc, char **argv) { + std::vector<bool> a = {0, 1, 0, 1}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/TestBoolVector.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/TestBoolVector.py @@ -0,0 +1,34 @@ +""" +Test basic std::vector<bool> functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestBoolVector(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 4']) + self.expect("expr (bool)a.front()", substrs=['(bool) $1 = false']) + self.expect("expr (bool)a[1]", substrs=['(bool) $2 = true']) + self.expect("expr (bool)a.back()", substrs=['(bool) $3 = true']) + + self.expect("expr (bool)(*a.begin())", substrs=['(bool) $4 = false']) + self.expect("expr (bool)(*a.rbegin())", substrs=['(bool) $5 = true']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-bool/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/main.cpp @@ -0,0 +1,6 @@ +#include <vector> + +int main(int argc, char **argv) { + std::vector<int> a = {3, 1, 2}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/TestBasicVector.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/TestBasicVector.py @@ -0,0 +1,57 @@ +""" +Test basic std::vector functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestBasicVector(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()", substrs=['(int) $1 = 3']) + self.expect("expr (int)a[1]", substrs=['(int) $2 = 1']) + self.expect("expr (int)a.back()", substrs=['(int) $3 = 2']) + + self.expect("expr std::sort(a.begin(), a.end())") + self.expect("expr (int)a.front()", substrs=['(int) $4 = 1']) + self.expect("expr (int)a[1]", substrs=['(int) $5 = 2']) + self.expect("expr (int)a.back()", substrs=['(int) $6 = 3']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front()", substrs=['(int) $7 = 3']) + self.expect("expr (int)a[1]", substrs=['(int) $8 = 2']) + self.expect("expr (int)a.back()", substrs=['(int) $9 = 1']) + + self.expect("expr (int)(*a.begin())", substrs=['(int) $10 = 3']) + self.expect("expr (int)(*a.rbegin())", substrs=['(int) $11 = 1']) + + self.expect("expr a.pop_back()") + self.expect("expr (int)a.back()", substrs=['(int) $12 = 2']) + self.expect("expr (size_t)a.size()", substrs=['(size_t) $13 = 2']) + + self.expect("expr (int)a.at(0)", substrs=['(int) $14 = 3']) + + self.expect("expr a.push_back(4)") + self.expect("expr (int)a.back()", substrs=['(int) $15 = 4']) + self.expect("expr (size_t)a.size()", substrs=['(size_t) $16 = 3']) + + self.expect("expr a.emplace_back(5)") + self.expect("expr (int)a.back()", substrs=['(int) $17 = 5']) + self.expect("expr (size_t)a.size()", substrs=['(size_t) $18 = 4']) Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/vector-basic/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/main.cpp @@ -0,0 +1,7 @@ +#include <memory> + +int main(int argc, char **argv) { + std::shared_ptr<int> s(new int); + *s = 3; + return *s; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/TestUniquePtr.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/TestUniquePtr.py @@ -0,0 +1,33 @@ +""" +Test basic std::unique_ptr functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestUniquePtr(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)*s", substrs=['(int) $0 = 3']) + self.expect("expr (int)(*s = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)*s", substrs=['(int) $2 = 5']) + self.expect("expr (bool)s", substrs=['(bool) $3 = true']) + self.expect("expr s.reset()") + self.expect("expr (bool)s", substrs=['(bool) $4 = false']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/main.cpp @@ -0,0 +1,11 @@ +#include <memory> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::shared_ptr<Foo> s(new Foo); + s->a = 3; + return s->a; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/TestUniquePtrDbgInfoContent.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/TestUniquePtrDbgInfoContent.py @@ -0,0 +1,33 @@ +""" +Test std::unique_ptr functionality with a decl from debug info as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestUniquePtrDbgInfoContent(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)s->a", substrs=['(int) $0 = 3']) + self.expect("expr (int)(s->a = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)s->a", substrs=['(int) $2 = 5']) + self.expect("expr (bool)s", substrs=['(bool) $3 = true']) + self.expect("expr s.reset()") + self.expect("expr (bool)s", substrs=['(bool) $4 = false']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/unique_ptr-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/main.cpp @@ -0,0 +1,7 @@ +#include <memory> + +int main(int argc, char **argv) { + std::shared_ptr<int> s(new int); + *s = 3; + return *s; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/TestSharedPtr.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/TestSharedPtr.py @@ -0,0 +1,33 @@ +""" +Test basic std::shared_ptr functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestSharedPtr(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)*s", substrs=['(int) $0 = 3']) + self.expect("expr (int)(*s = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)*s", substrs=['(int) $2 = 5']) + self.expect("expr (bool)s", substrs=['(bool) $3 = true']) + self.expect("expr s.reset()") + self.expect("expr (bool)s", substrs=['(bool) $4 = false']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/main.cpp @@ -0,0 +1,11 @@ +#include <memory> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::shared_ptr<Foo> s(new Foo); + s->a = 3; + return s->a; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/TestSharedPtrDbgInfoContent.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/TestSharedPtrDbgInfoContent.py @@ -0,0 +1,33 @@ +""" +Test std::shared_ptr functionality with a class from debug info as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestSharedPtr(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (int)s->a", substrs=['(int) $0 = 3']) + self.expect("expr (int)(s->a = 5)", substrs=['(int) $1 = 5']) + self.expect("expr (int)s->a", substrs=['(int) $2 = 5']) + self.expect("expr (bool)s", substrs=['(bool) $3 = true']) + self.expect("expr s.reset()") + self.expect("expr (bool)s", substrs=['(bool) $4 = false']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/shared_ptr-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/main.cpp @@ -0,0 +1,10 @@ +#include <list> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::list<Foo> a = {{3}, {1}, {2}}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/TestDbgInfoContentList.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/TestDbgInfoContentList.py @@ -0,0 +1,38 @@ +""" +Test basic std::list functionality but with a declaration from +the debug info (the Foo struct) as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestDbgInfoContentList(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front().a", substrs=['(int) $1 = 3']) + self.expect("expr (int)a.back().a", substrs=['(int) $2 = 2']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front().a", substrs=['(int) $3 = 2']) + self.expect("expr (int)a.back().a", substrs=['(int) $4 = 3']) + + self.expect("expr (int)(a.begin()->a)", substrs=['(int) $5 = 2']) + self.expect("expr (int)(a.rbegin()->a)", substrs=['(int) $6 = 3']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/main.cpp @@ -0,0 +1,6 @@ +#include <list> + +int main(int argc, char **argv) { + std::list<int> a = {3, 1, 2}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/TestBasicList.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/TestBasicList.py @@ -0,0 +1,41 @@ +""" +Test basic std::list functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestBasicList(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()", substrs=['(int) $1 = 3']) + self.expect("expr (int)a.back()", substrs=['(int) $2 = 2']) + + self.expect("expr a.sort()") + self.expect("expr (int)a.front()", substrs=['(int) $3 = 1']) + self.expect("expr (int)a.back()", substrs=['(int) $4 = 3']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front()", substrs=['(int) $5 = 3']) + self.expect("expr (int)a.back()", substrs=['(int) $6 = 1']) + + self.expect("expr (int)(*a.begin())", substrs=['(int) $7 = 3']) + self.expect("expr (int)(*a.rbegin())", substrs=['(int) $8 = 1']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/list-basic/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/main.cpp @@ -0,0 +1,10 @@ +#include <forward_list> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::forward_list<Foo> a = {{3}, {1}, {2}}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/TestDbgInfoContentForwardList.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/TestDbgInfoContentForwardList.py @@ -0,0 +1,31 @@ +""" +Test std::forward_list functionality with a decl from debug info as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestDbgInfoContentForwardList(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)std::distance(a.begin(), a.end())", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()->a", substrs=['(int) $1 = 3']) + + self.expect("expr (int)(a.begin()->a)", substrs=['(int) $2 = 3']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/main.cpp @@ -0,0 +1,6 @@ +#include <forward_list> + +int main(int argc, char **argv) { + std::forward_list<int> a = {3, 1, 2}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/TestBasicForwardList.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/TestBasicForwardList.py @@ -0,0 +1,34 @@ +""" +Test basic std::forward_list functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestBasicList(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)std::distance(a.begin(), a.end())", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()", substrs=['(int) $1 = 3']) + + self.expect("expr a.sort()") + self.expect("expr (int)a.front()", substrs=['(int) $2 = 1']) + + self.expect("expr (int)(*a.begin())", substrs=['(int) $3 = 1']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/forward_list-basic/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/main.cpp @@ -0,0 +1,10 @@ +#include <deque> + +struct Foo { + int a; +}; + +int main(int argc, char **argv) { + std::deque<Foo> a = {{3}, {1}, {2}}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/TestDbgInfoContentDeque.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/TestDbgInfoContentDeque.py @@ -0,0 +1,37 @@ +""" +Test std::deque functionality with a decl from dbg info as content. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestDbgInfoContentDeque(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()->a", substrs=['(int) $1 = 3']) + self.expect("expr (int)a.back()->a", substrs=['(int) $2 = 2']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front()->a", substrs=['(int) $3 = 2']) + self.expect("expr (int)a.back()->a", substrs=['(int) $4 = 3']) + + self.expect("expr (int)(a.begin()->a)", substrs=['(int) $5 = 2']) + self.expect("expr (int)(a.rbegin()->a)", substrs=['(int) $6 = 3']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-dbg-info-content/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/main.cpp =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/main.cpp @@ -0,0 +1,6 @@ +#include <deque> + +int main(int argc, char **argv) { + std::deque<int> a = {3, 1, 2}; + return 0; // Set break point at this line. +} Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/TestBasicDeque.py =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/TestBasicDeque.py @@ -0,0 +1,41 @@ +""" +Test basic std::list functionality. +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestBasicDeque(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + # FIXME: This should work on more setups, so remove these + # skipIf's in the future. + @add_test_categories(["libc++"]) + @skipIf(compiler=no_match("clang")) + @skipIf(oslist=no_match(["linux"])) + @skipIf(debug_info=no_match(["dwarf"])) + def test(self): + self.build() + + lldbutil.run_to_source_breakpoint(self, + "// Set break point at this line.", lldb.SBFileSpec("main.cpp")) + + self.runCmd("settings set target.import-std-module true") + + self.expect("expr (size_t)a.size()", substrs=['(size_t) $0 = 3']) + self.expect("expr (int)a.front()", substrs=['(int) $1 = 3']) + self.expect("expr (int)a.back()", substrs=['(int) $2 = 2']) + + self.expect("expr std::sort(a.begin(), a.end())") + self.expect("expr (int)a.front()", substrs=['(int) $3 = 1']) + self.expect("expr (int)a.back()", substrs=['(int) $4 = 3']) + + self.expect("expr std::reverse(a.begin(), a.end())") + self.expect("expr (int)a.front()", substrs=['(int) $5 = 3']) + self.expect("expr (int)a.back()", substrs=['(int) $6 = 1']) + + self.expect("expr (int)(*a.begin())", substrs=['(int) $7 = 3']) + self.expect("expr (int)(*a.rbegin())", substrs=['(int) $8 = 1']) + Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/Makefile =================================================================== --- /dev/null +++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/deque-basic/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make +USE_LIBCPP := 1 +CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS) +CXX_SOURCES := main.cpp +include $(LEVEL)/Makefile.rules Index: lldb/include/lldb/Symbol/CxxModuleHandler.h =================================================================== --- /dev/null +++ lldb/include/lldb/Symbol/CxxModuleHandler.h @@ -0,0 +1,65 @@ +//===-- CxxModuleHandler.h --------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_CxxModuleHandler_h_ +#define liblldb_CxxModuleHandler_h_ + +#include "clang/AST/ASTImporter.h" +#include "clang/Sema/Sema.h" +#include "llvm/ADT/StringSet.h" + +namespace lldb_private { + +/// Handles importing decls into an ASTContext with an attached C++ module. +/// +/// This class searches a C++ module (which must be attached to the target +/// ASTContext) for an equivalent decl to the one that should be imported. +/// If the decl that is found in the module is a suitable replacement +/// for the decl that should be imported, the module decl will be treated as +/// the result of the import process. +/// +/// If the Decl that should be imported is a template specialization +/// that doesn't exist yet in the target ASTContext (e.g. `std::vector<int>`), +/// then this class tries to create the template specialization in the target +/// ASTContext. This is only possible if the CxxModuleHandler can determine +/// that instantiating this template is safe to do, e.g. because the target +/// decl is a container class from the STL. +class CxxModuleHandler { + /// The ASTImporter that should be used to import any Decls which aren't + /// directly handled by this class itself. + clang::ASTImporter *m_importer = nullptr; + + /// The Sema instance of the target ASTContext. + clang::Sema *m_sema = nullptr; + + /// List of template names this class currently supports. These are the + /// template names inside the 'std' namespace such as 'vector' or 'list'. + llvm::StringSet<> m_supported_templates; + + /// Tries to manually instantiate the given foreign template in the target + /// context (designated by m_sema). + llvm::Optional<clang::Decl *> tryInstantiateStdTemplate(clang::Decl *d); + +public: + CxxModuleHandler() = default; + CxxModuleHandler(clang::ASTImporter &importer, clang::ASTContext *target); + + /// Attempts to import the given decl into the target ASTContext by + /// deserializing it from the 'std' module. This function returns a Decl if a + /// Decl has been deserialized from the 'std' module. Otherwise this function + /// returns nothing. + llvm::Optional<clang::Decl *> Import(clang::Decl *d); + + /// Returns true iff this instance is capable of importing any declarations + /// in the target ASTContext. + bool isValid() const { return m_sema != nullptr; } +}; + +} // namespace lldb_private + +#endif // liblldb_CxxModuleHandler_h_ Index: lldb/include/lldb/Symbol/ClangASTImporter.h =================================================================== --- lldb/include/lldb/Symbol/ClangASTImporter.h +++ lldb/include/lldb/Symbol/ClangASTImporter.h @@ -23,6 +23,7 @@ #include "lldb/Host/FileSystem.h" #include "lldb/Symbol/CompilerDeclContext.h" +#include "lldb/Symbol/CxxModuleHandler.h" #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" @@ -243,6 +244,41 @@ m_decls_to_deport(nullptr), m_decls_already_deported(nullptr), m_master(master), m_source_ctx(source_ctx) {} + /// Scope guard that attaches a CxxModuleHandler to a Minion and deattaches + /// it at the end of the scope. Supports being used multiple times on the + /// same Minion instance in nested scopes. + class CxxModuleScope { + /// The handler we attach to the Minion. + CxxModuleHandler m_handler; + /// The Minion we are supposed to attach the handler to. + Minion &m_minion; + /// True iff we attached the handler to the Minion. + bool m_valid = false; + + public: + CxxModuleScope(Minion &minion, clang::ASTContext *dst_ctx) + : m_minion(minion) { + // If the minion doesn't have a CxxModuleHandler yet, create one + // and attach it. + if (!minion.m_std_handler) { + m_handler = CxxModuleHandler(minion, dst_ctx); + m_valid = true; + minion.m_std_handler = &m_handler; + } + } + ~CxxModuleScope() { + if (m_valid) { + // Make sure no one messed with the handler we placed. + assert(m_minion.m_std_handler == &m_handler); + m_minion.m_std_handler = nullptr; + } + } + }; + + protected: + llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override; + + public: // A call to "InitDeportWorkQueues" puts the minion into deport mode. // In deport mode, every copied Decl that could require completion is // recorded and placed into the decls_to_deport set. @@ -266,10 +302,16 @@ clang::Decl *GetOriginalDecl(clang::Decl *To) override; + /// Decls we should ignore when mapping decls back to their original + /// ASTContext. Used by the CxxModuleHandler to mark declarations that + /// were created from the 'std' C++ module to prevent that the Importer + /// tries to sync them with the broken equivalent in the debug info AST. + std::set<clang::Decl *> m_decls_to_ignore; std::set<clang::NamedDecl *> *m_decls_to_deport; std::set<clang::NamedDecl *> *m_decls_already_deported; ClangASTImporter &m_master; clang::ASTContext *m_source_ctx; + CxxModuleHandler *m_std_handler = nullptr; }; typedef std::shared_ptr<Minion> MinionSP; Index: lldb/include/lldb/Symbol/ClangASTContext.h =================================================================== --- lldb/include/lldb/Symbol/ClangASTContext.h +++ lldb/include/lldb/Symbol/ClangASTContext.h @@ -104,6 +104,9 @@ clang::TargetInfo *getTargetInfo(); + void setSema(clang::Sema *s); + clang::Sema *getSema() { return m_sema; } + void Clear(); const char *GetTargetTriple(); @@ -997,6 +1000,10 @@ uint32_t m_pointer_byte_size; bool m_ast_owned; bool m_can_evaluate_expressions; + // The sema associated that is currently used to build this ASTContext. + // May be null if we are already done parsing this ASTContext or the + // ASTContext wasn't created by parsing source code. + clang::Sema * m_sema = nullptr; // clang-format on private: // For ClangASTContext only
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits