diff options
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser')
23 files changed, 482 insertions, 293 deletions
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp index 39ba5f4e9e4f..3edbc4ab98c0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp @@ -443,7 +443,9 @@ void ASTResultSynthesizer::CommitPersistentDecls() { return; auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state); - TypeSystemClang *scratch_ctx = TypeSystemClang::GetScratch(m_target); + + TypeSystemClang *scratch_ctx = ScratchTypeSystemClang::GetForTarget( + m_target, m_ast_context->getLangOpts()); for (clang::NamedDecl *decl : m_decls) { StringRef name = decl->getName(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h index 3787c572d45b..b70ec223df4d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h @@ -359,15 +359,12 @@ public: } void CompleteType(clang::TagDecl *Tag) override { - while (!Tag->isCompleteDefinition()) - for (size_t i = 0; i < Sources.size(); ++i) { - // FIXME: We are technically supposed to loop here too until - // Tag->isCompleteDefinition() is true, but if our low quality source - // is failing to complete the tag this code will deadlock. - Sources[i]->CompleteType(Tag); - if (Tag->isCompleteDefinition()) - break; - } + for (clang::ExternalSemaSource *S : Sources) { + S->CompleteType(Tag); + // Stop after the first source completed the type. + if (Tag->isCompleteDefinition()) + break; + } } void CompleteType(clang::ObjCInterfaceDecl *Class) override { @@ -404,13 +401,6 @@ public: return nullptr; } - bool DeclIsFromPCHWithObjectFile(const clang::Decl *D) override { - for (auto *S : Sources) - if (S->DeclIsFromPCHWithObjectFile(D)) - return true; - return false; - } - bool layoutRecordType( const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment, llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets, diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp index ac16738933ac..e2601a059bb7 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp @@ -216,7 +216,12 @@ namespace { /// imported while completing the original Decls). class CompleteTagDeclsScope : public ClangASTImporter::NewDeclListener { ClangASTImporter::ImporterDelegateSP m_delegate; - llvm::SmallVector<NamedDecl *, 32> m_decls_to_complete; + /// List of declarations in the target context that need to be completed. + /// Every declaration should only be completed once and therefore should only + /// be once in this list. + llvm::SetVector<NamedDecl *> m_decls_to_complete; + /// Set of declarations that already were successfully completed (not just + /// added to m_decls_to_complete). llvm::SmallPtrSet<NamedDecl *, 32> m_decls_already_completed; clang::ASTContext *m_dst_ctx; clang::ASTContext *m_src_ctx; @@ -244,10 +249,13 @@ public: NamedDecl *decl = m_decls_to_complete.pop_back_val(); m_decls_already_completed.insert(decl); + // The decl that should be completed has to be imported into the target + // context from some other context. + assert(to_context_md->hasOrigin(decl)); // We should only complete decls coming from the source context. - assert(to_context_md->m_origins[decl].ctx == m_src_ctx); + assert(to_context_md->getOrigin(decl).ctx == m_src_ctx); - Decl *original_decl = to_context_md->m_origins[decl].decl; + Decl *original_decl = to_context_md->getOrigin(decl).decl; // Complete the decl now. TypeSystemClang::GetCompleteDecl(m_src_ctx, original_decl); @@ -266,7 +274,7 @@ public: container_decl->setHasExternalVisibleStorage(false); } - to_context_md->m_origins.erase(decl); + to_context_md->removeOrigin(decl); } // Stop listening to imported decls. We do this after clearing the @@ -287,7 +295,8 @@ public: // Check if we already completed this type. if (m_decls_already_completed.count(to_named_decl) != 0) return; - m_decls_to_complete.push_back(to_named_decl); + // Queue this type to be completed. + m_decls_to_complete.insert(to_named_decl); } }; } // namespace @@ -581,10 +590,7 @@ bool ClangASTImporter::CompleteTagDeclWithOrigin(clang::TagDecl *decl, ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - origins[decl] = DeclOrigin(origin_ast_ctx, origin_decl); - + context_md->setOrigin(decl, DeclOrigin(origin_ast_ctx, origin_decl)); return true; } @@ -721,29 +727,14 @@ ClangASTImporter::DeclOrigin ClangASTImporter::GetDeclOrigin(const clang::Decl *decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) - return iter->second; - return DeclOrigin(); + return context_md->getOrigin(decl); } void ClangASTImporter::SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl) { ASTContextMetadataSP context_md = GetContextMetadata(&decl->getASTContext()); - - OriginMap &origins = context_md->m_origins; - - OriginMap::iterator iter = origins.find(decl); - - if (iter != origins.end()) { - iter->second.decl = original_decl; - iter->second.ctx = &original_decl->getASTContext(); - return; - } - origins[decl] = DeclOrigin(&original_decl->getASTContext(), original_decl); + context_md->setOrigin( + decl, DeclOrigin(&original_decl->getASTContext(), original_decl)); } void ClangASTImporter::RegisterNamespaceMap(const clang::NamespaceDecl *decl, @@ -817,14 +808,7 @@ void ClangASTImporter::ForgetSource(clang::ASTContext *dst_ast, return; md->m_delegates.erase(src_ast); - - for (OriginMap::iterator iter = md->m_origins.begin(); - iter != md->m_origins.end();) { - if (iter->second.ctx == src_ast) - md->m_origins.erase(iter++); - else - ++iter; - } + md->removeOriginsWithContext(src_ast); } ClangASTImporter::MapCompleter::~MapCompleter() { return; } @@ -895,13 +879,14 @@ ClangASTImporter::ASTImporterDelegate::ImportImpl(Decl *From) { return dn_or_err.takeError(); DeclContext *dc = *dc_or_err; DeclContext::lookup_result lr = dc->lookup(*dn_or_err); - if (lr.size()) { - clang::Decl *lookup_found = lr.front(); - RegisterImportedDecl(From, lookup_found); - m_decls_to_ignore.insert(lookup_found); - return lookup_found; - } else - LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); + for (clang::Decl *candidate : lr) { + if (candidate->getKind() == From->getKind()) { + RegisterImportedDecl(From, candidate); + m_decls_to_ignore.insert(candidate); + return candidate; + } + } + LLDB_LOG(log, "[ClangASTImporter] Complete definition not found"); } return ASTImporter::ImportImpl(From); @@ -1100,37 +1085,31 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, m_master.MaybeGetContextMetadata(m_source_ctx); if (from_context_md) { - OriginMap &origins = from_context_md->m_origins; - - OriginMap::iterator origin_iter = origins.find(from); + DeclOrigin origin = from_context_md->getOrigin(from); - if (origin_iter != origins.end()) { - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - if (origin_iter->second.ctx != &to->getASTContext()) - to_context_md->m_origins[to] = origin_iter->second; - } + if (origin.Valid()) { + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + if (origin.ctx != &to->getASTContext()) + to_context_md->setOrigin(to, origin); ImporterDelegateSP direct_completer = - m_master.GetDelegate(&to->getASTContext(), origin_iter->second.ctx); + m_master.GetDelegate(&to->getASTContext(), origin.ctx); if (direct_completer.get() != this) - direct_completer->ASTImporter::Imported(origin_iter->second.decl, to); + direct_completer->ASTImporter::Imported(origin.decl, to); LLDB_LOG(log, " [ClangASTImporter] Propagated origin " "(Decl*){0}/(ASTContext*){1} from (ASTContext*){2} to " "(ASTContext*){3}", - origin_iter->second.decl, origin_iter->second.ctx, - &from->getASTContext(), &to->getASTContext()); + origin.decl, origin.ctx, &from->getASTContext(), + &to->getASTContext()); } else { if (m_new_decl_listener) m_new_decl_listener->NewDeclImported(from, to); - if (to_context_md->m_origins.find(to) == to_context_md->m_origins.end() || - user_id != LLDB_INVALID_UID) { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); - } + if (!to_context_md->hasOrigin(to) || user_id != LLDB_INVALID_UID) + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Decl has no origin information in " @@ -1151,7 +1130,7 @@ void ClangASTImporter::ASTImporterDelegate::Imported(clang::Decl *from, namespace_map_iter->second; } } else { - to_context_md->m_origins[to] = DeclOrigin(m_source_ctx, from); + to_context_md->setOrigin(to, DeclOrigin(m_source_ctx, from)); LLDB_LOG(log, " [ClangASTImporter] Sourced origin " diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h index 6ceec774914b..bf4ad174cf9c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h @@ -160,14 +160,12 @@ public: decl = rhs.decl; } - bool Valid() { return (ctx != nullptr || decl != nullptr); } + bool Valid() const { return (ctx != nullptr || decl != nullptr); } clang::ASTContext *ctx; clang::Decl *decl; }; - typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; - /// Listener interface used by the ASTImporterDelegate to inform other code /// about decls that have been imported the first time. struct NewDeclListener { @@ -259,17 +257,61 @@ public: typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP> NamespaceMetaMap; - struct ASTContextMetadata { - ASTContextMetadata(clang::ASTContext *dst_ctx) - : m_dst_ctx(dst_ctx), m_delegates(), m_origins(), m_namespace_maps(), - m_map_completer(nullptr) {} + class ASTContextMetadata { + typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap; + + public: + ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {} clang::ASTContext *m_dst_ctx; DelegateMap m_delegates; - OriginMap m_origins; NamespaceMetaMap m_namespace_maps; - MapCompleter *m_map_completer; + MapCompleter *m_map_completer = nullptr; + + /// Sets the DeclOrigin for the given Decl and overwrites any existing + /// DeclOrigin. + void setOrigin(const clang::Decl *decl, DeclOrigin origin) { + m_origins[decl] = origin; + } + + /// Removes any tracked DeclOrigin for the given decl. + void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); } + + /// Remove all DeclOrigin entries that point to the given ASTContext. + /// Useful when an ASTContext is about to be deleted and all the dangling + /// pointers to it need to be removed. + void removeOriginsWithContext(clang::ASTContext *ctx) { + for (OriginMap::iterator iter = m_origins.begin(); + iter != m_origins.end();) { + if (iter->second.ctx == ctx) + m_origins.erase(iter++); + else + ++iter; + } + } + + /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin + /// instance if there no known DeclOrigin for the given Decl. + DeclOrigin getOrigin(const clang::Decl *decl) const { + auto iter = m_origins.find(decl); + if (iter == m_origins.end()) + return DeclOrigin(); + return iter->second; + } + + /// Returns true there is a known DeclOrigin for the given Decl. + bool hasOrigin(const clang::Decl *decl) const { + return getOrigin(decl).Valid(); + } + + private: + /// Maps declarations to the ASTContext/Decl from which they were imported + /// from. If a declaration is from an ASTContext which has been deleted + /// since the declaration was imported or the declaration wasn't created by + /// the ASTImporter, then it doesn't have a DeclOrigin and will not be + /// tracked here. + OriginMap m_origins; }; typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp index 6fe85a1298fc..0f34c48c7e82 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp @@ -71,20 +71,22 @@ ClangASTSource::~ClangASTSource() { if (!m_target) return; - // We are in the process of destruction, don't create clang ast context on - // demand by passing false to - // Target::GetScratchTypeSystemClang(create_on_demand). - TypeSystemClang *scratch_clang_ast_context = - TypeSystemClang::GetScratch(*m_target, false); - if (!scratch_clang_ast_context) - return; + // Unregister the current ASTContext as a source for all scratch + // ASTContexts in the ClangASTImporter. Without this the scratch AST might + // query the deleted ASTContext for additional type information. + // We unregister from *all* scratch ASTContexts in case a type got exported + // to a scratch AST that isn't the best fitting scratch ASTContext. + TypeSystemClang *scratch_ast = ScratchTypeSystemClang::GetForTarget( + *m_target, ScratchTypeSystemClang::DefaultAST, false); - clang::ASTContext &scratch_ast_context = - scratch_clang_ast_context->getASTContext(); + if (!scratch_ast) + return; - if (m_ast_context != &scratch_ast_context && m_ast_importer_sp) - m_ast_importer_sp->ForgetSource(&scratch_ast_context, m_ast_context); + ScratchTypeSystemClang *default_scratch_ast = + llvm::cast<ScratchTypeSystemClang>(scratch_ast); + // Unregister from the default scratch AST (and all sub-ASTs). + default_scratch_ast->ForgetSource(m_ast_context, *m_ast_importer_sp); } void ClangASTSource::StartTranslationUnit(ASTConsumer *Consumer) { @@ -482,6 +484,15 @@ void ClangASTSource::FindExternalLexicalDecls( if (!copied_decl) continue; + // FIXME: We should add the copied decl to the 'decls' list. This would + // add the copied Decl into the DeclContext and make sure that we + // correctly propagate that we added some Decls back to Clang. + // By leaving 'decls' empty we incorrectly return false from + // DeclContext::LoadLexicalDeclsFromExternalStorage which might cause + // lookup issues later on. + // We can't just add them for now as the ASTImporter already added the + // decl into the DeclContext and this would add it twice. + if (FieldDecl *copied_field = dyn_cast<FieldDecl>(copied_decl)) { QualType copied_field_type = copied_field->getType(); @@ -679,12 +690,7 @@ void ClangASTSource::FillNamespaceMap( return; } - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; @@ -1656,14 +1662,8 @@ void ClangASTSource::CompleteNamespaceMap( module_sp->GetFileSpec().GetFilename()); } } else { - const ModuleList &target_images = m_target->GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_images.GetMutex()); - CompilerDeclContext null_namespace_decl; - - for (size_t i = 0, e = target_images.GetSize(); i < e; ++i) { - lldb::ModuleSP image = target_images.GetModuleAtIndexUnlocked(i); - + for (lldb::ModuleSP image : m_target->GetImages().Modules()) { if (!image) continue; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp index 8c49898e1d6c..852ce3bbd3db 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp @@ -19,6 +19,7 @@ #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectVariable.h" +#include "lldb/Expression/DiagnosticManager.h" #include "lldb/Expression/Materializer.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/CompilerDecl.h" @@ -109,7 +110,7 @@ bool ClangExpressionDeclMap::WillParse(ExecutionContext &exe_ctx, m_parser_vars->m_persistent_vars = llvm::cast<ClangPersistentVariables>( target->GetPersistentExpressionStateForLanguage(eLanguageTypeC)); - if (!TypeSystemClang::GetScratch(*target)) + if (!ScratchTypeSystemClang::GetForTarget(*target)) return false; } @@ -125,6 +126,12 @@ void ClangExpressionDeclMap::InstallCodeGenerator( m_parser_vars->m_code_gen = code_gen; } +void ClangExpressionDeclMap::InstallDiagnosticManager( + DiagnosticManager &diag_manager) { + assert(m_parser_vars); + m_parser_vars->m_diagnostics = &diag_manager; +} + void ClangExpressionDeclMap::DidParse() { if (m_parser_vars && m_parser_vars->m_persistent_vars) { for (size_t entity_index = 0, num_entities = m_found_entities.GetSize(); @@ -177,7 +184,7 @@ ClangExpressionDeclMap::TargetInfo ClangExpressionDeclMap::GetTargetInfo() { TypeFromUser ClangExpressionDeclMap::DeportType(TypeSystemClang &target, TypeSystemClang &source, TypeFromParser parser_type) { - assert(&target == TypeSystemClang::GetScratch(*m_target)); + assert(&target == GetScratchContext(*m_target)); assert((TypeSystem *)&source == parser_type.GetTypeSystem()); assert(&source.getASTContext() == m_ast_context); @@ -196,6 +203,17 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (ast == nullptr) return false; + // Check if we already declared a persistent variable with the same name. + if (lldb::ExpressionVariableSP conflicting_var = + m_parser_vars->m_persistent_vars->GetVariable(name)) { + std::string msg = llvm::formatv("redefinition of persistent variable '{0}'", + name).str(); + m_parser_vars->m_diagnostics->AddDiagnostic( + msg, DiagnosticSeverity::eDiagnosticSeverityError, + DiagnosticOrigin::eDiagnosticOriginLLDB); + return false; + } + if (m_parser_vars->m_materializer && is_result) { Status err; @@ -204,7 +222,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - auto *clang_ast_context = TypeSystemClang::GetScratch(*target); + auto *clang_ast_context = GetScratchContext(*target); if (!clang_ast_context) return false; @@ -242,7 +260,7 @@ bool ClangExpressionDeclMap::AddPersistentVariable(const NamedDecl *decl, if (target == nullptr) return false; - TypeSystemClang *context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *context = GetScratchContext(*target); if (!context) return false; @@ -703,7 +721,7 @@ clang::NamedDecl *ClangExpressionDeclMap::GetPersistentDecl(ConstString name) { if (!target) return nullptr; - TypeSystemClang::GetScratch(*target); + ScratchTypeSystemClang::GetForTarget(*target); if (!m_parser_vars->m_persistent_vars) return nullptr; @@ -1620,7 +1638,7 @@ void ClangExpressionDeclMap::AddOneGenericVariable(NameSearchContext &context, if (target == nullptr) return; - TypeSystemClang *scratch_ast_context = TypeSystemClang::GetScratch(*target); + TypeSystemClang *scratch_ast_context = GetScratchContext(*target); if (!scratch_ast_context) return; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h index 6974535a8993..a9cd5d166b9d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h @@ -102,6 +102,8 @@ public: void InstallCodeGenerator(clang::ASTConsumer *code_gen); + void InstallDiagnosticManager(DiagnosticManager &diag_manager); + /// Disable the state needed for parsing and IR transformation. void DidParse(); @@ -330,6 +332,8 @@ private: clang::ASTConsumer *m_code_gen = nullptr; ///< If non-NULL, a code generator ///that receives new top-level ///functions. + DiagnosticManager *m_diagnostics = nullptr; + private: ParserVars(const ParserVars &) = delete; const ParserVars &operator=(const ParserVars &) = delete; @@ -376,6 +380,11 @@ private: /// Deallocate struct variables void DisableStructVars() { m_struct_vars.reset(); } + TypeSystemClang *GetScratchContext(Target &target) { + return ScratchTypeSystemClang::GetForTarget(target, + m_ast_context->getLangOpts()); + } + /// Get this parser's ID for use in extracting parser- and JIT-specific data /// from persistent variables. uint64_t GetParserID() { return (uint64_t) this; } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 6ff028cf6980..7644a5e1423e 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -85,7 +85,7 @@ #include "lldb/Utility/DataBufferHeap.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/Stream.h" #include "lldb/Utility/StreamString.h" #include "lldb/Utility/StringList.h" @@ -302,6 +302,55 @@ static void SetupModuleHeaderPaths(CompilerInstance *compiler, search_opts.ImplicitModuleMaps = true; } +/// Iff the given identifier is a C++ keyword, remove it from the +/// identifier table (i.e., make the token a normal identifier). +static void RemoveCppKeyword(IdentifierTable &idents, llvm::StringRef token) { + // FIXME: 'using' is used by LLDB for local variables, so we can't remove + // this keyword without breaking this functionality. + if (token == "using") + return; + // GCC's '__null' is used by LLDB to define NULL/Nil/nil. + if (token == "__null") + return; + + LangOptions cpp_lang_opts; + cpp_lang_opts.CPlusPlus = true; + cpp_lang_opts.CPlusPlus11 = true; + cpp_lang_opts.CPlusPlus20 = true; + + clang::IdentifierInfo &ii = idents.get(token); + // The identifier has to be a C++-exclusive keyword. if not, then there is + // nothing to do. + if (!ii.isCPlusPlusKeyword(cpp_lang_opts)) + return; + // If the token is already an identifier, then there is nothing to do. + if (ii.getTokenID() == clang::tok::identifier) + return; + // Otherwise the token is a C++ keyword, so turn it back into a normal + // identifier. + ii.revertTokenIDToIdentifier(); +} + +/// Remove all C++ keywords from the given identifier table. +static void RemoveAllCppKeywords(IdentifierTable &idents) { +#define KEYWORD(NAME, FLAGS) RemoveCppKeyword(idents, llvm::StringRef(#NAME)); +#include "clang/Basic/TokenKinds.def" +} + +/// Configures Clang diagnostics for the expression parser. +static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) { + // List of Clang warning groups that are not useful when parsing expressions. + const std::vector<const char *> groupsToIgnore = { + "unused-value", + "odr", + }; + for (const char *group : groupsToIgnore) { + compiler.getDiagnostics().setSeverityForGroup( + clang::diag::Flavor::WarningOrError, group, + clang::diag::Severity::Ignored, SourceLocation()); + } +} + //===----------------------------------------------------------------------===// // Implementation of ClangExpressionParser //===----------------------------------------------------------------------===// @@ -454,6 +503,10 @@ ClangExpressionParser::ClangExpressionParser( // 4. Create and install the target on the compiler. m_compiler->createDiagnostics(); + // Limit the number of error diagnostics we emit. + // A value of 0 means no limit for both LLDB and Clang. + m_compiler->getDiagnostics().setErrorLimit(target_sp->GetExprErrorLimit()); + auto target_info = TargetInfo::CreateTargetInfo( m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); if (log) { @@ -598,12 +651,7 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo); // Disable some warnings. - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "unused-value", - clang::diag::Severity::Ignored, SourceLocation()); - m_compiler->getDiagnostics().setSeverityForGroup( - clang::diag::Flavor::WarningOrError, "odr", - clang::diag::Severity::Ignored, SourceLocation()); + SetupDefaultClangDiagnostics(*m_compiler); // Inform the target of the language options // @@ -623,6 +671,21 @@ ClangExpressionParser::ClangExpressionParser( m_compiler->createSourceManager(m_compiler->getFileManager()); m_compiler->createPreprocessor(TU_Complete); + switch (language) { + case lldb::eLanguageTypeC: + case lldb::eLanguageTypeC89: + case lldb::eLanguageTypeC99: + case lldb::eLanguageTypeC11: + case lldb::eLanguageTypeObjC: + // This is not a C++ expression but we enabled C++ as explained above. + // Remove all C++ keywords from the PP so that the user can still use + // variables that have C++ keywords as names (e.g. 'int template;'). + RemoveAllCppKeywords(m_compiler->getPreprocessor().getIdentifierTable()); + break; + default: + break; + } + if (ClangModulesDeclVendor *decl_vendor = target_sp->GetClangModulesDeclVendor()) { if (auto *clang_persistent_vars = llvm::cast<ClangPersistentVariables>( @@ -1010,8 +1073,8 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, if (file.Write(expr_text, bytes_written).Success()) { if (bytes_written == expr_text_len) { file.Close(); - if (auto fileEntry = - m_compiler->getFileManager().getFile(result_path)) { + if (auto fileEntry = m_compiler->getFileManager().getOptionalFileRef( + result_path)) { source_mgr.setMainFileID(source_mgr.createFileID( *fileEntry, SourceLocation(), SrcMgr::C_User)); @@ -1074,6 +1137,7 @@ ClangExpressionParser::ParseInternal(DiagnosticManager &diagnostic_manager, ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap(); if (decl_map) { decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer()); + decl_map->InstallDiagnosticManager(diagnostic_manager); clang::ExternalASTSource *ast_source = decl_map->CreateProxy(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp index a429963277d1..180e08b03c93 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp @@ -221,7 +221,7 @@ TokenVerifier::TokenVerifier(std::string body) { clang::SourceManager SM(diags, file_mgr); auto buf = llvm::MemoryBuffer::getMemBuffer(body); - FileID FID = SM.createFileID(clang::SourceManager::Unowned, buf.get()); + FileID FID = SM.createFileID(buf->getMemBufferRef()); // Let's just enable the latest ObjC and C++ which should get most tokens // right. @@ -231,7 +231,7 @@ TokenVerifier::TokenVerifier(std::string body) { Opts.CPlusPlus17 = true; Opts.LineComment = true; - Lexer lex(FID, buf.get(), SM, Opts); + Lexer lex(FID, buf->getMemBufferRef(), SM, Opts); Token token; bool exit = false; @@ -297,6 +297,7 @@ bool ClangExpressionSourceCode::GetText( bool force_add_all_locals, llvm::ArrayRef<std::string> modules) const { const char *target_specific_defines = "typedef signed char BOOL;\n"; std::string module_macros; + llvm::raw_string_ostream module_macros_stream(module_macros); Target *target = exe_ctx.GetTargetPtr(); if (target) { @@ -344,9 +345,13 @@ bool ClangExpressionSourceCode::GetText( decl_vendor->ForEachMacro( modules_for_macros, - [&module_macros](const std::string &expansion) -> bool { - module_macros.append(expansion); - module_macros.append("\n"); + [&module_macros_stream](llvm::StringRef token, + llvm::StringRef expansion) -> bool { + // Check if the macro hasn't already been defined in the + // g_expression_prefix (which defines a few builtin macros). + module_macros_stream << "#ifndef " << token << "\n"; + module_macros_stream << expansion << "\n"; + module_macros_stream << "#endif\n"; return false; }); } @@ -387,8 +392,8 @@ bool ClangExpressionSourceCode::GetText( StreamString wrap_stream; - wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(), - debug_macros_stream.GetData(), g_expression_prefix, + wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", g_expression_prefix, + module_macros.c_str(), debug_macros_stream.GetData(), target_specific_defines, m_prefix.c_str()); // First construct a tagged form of the user expression so we can find it diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp index 8abb7e420575..b76fa6fbf690 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp @@ -137,14 +137,12 @@ bool lldb_private::ComputeClangResourceDirectory(FileSpec &lldb_shlib_spec, FileSystem::Instance().Resolve(file_spec); return true; } - raw_path = lldb_shlib_spec.GetPath(); } - raw_path.resize(rev_it - r_end); - } else { - raw_path.resize(rev_it - r_end); } // Fall back to the Clang resource directory inside the framework. + raw_path = lldb_shlib_spec.GetPath(); + raw_path.resize(rev_it - r_end); raw_path.append("LLDB.framework/Resources/Clang"); file_spec.GetDirectory().SetString(raw_path.c_str()); FileSystem::Instance().Resolve(file_spec); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp index 95acb883774d..c014ad504d37 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp @@ -33,7 +33,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" -#include "lldb/Utility/Reproducer.h" +#include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/StreamString.h" #include <memory> @@ -95,8 +95,10 @@ public: uint32_t FindDecls(ConstString name, bool append, uint32_t max_matches, std::vector<CompilerDecl> &decls) override; - void ForEachMacro(const ModuleVector &modules, - std::function<bool(const std::string &)> handler) override; + void ForEachMacro( + const ModuleVector &modules, + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) override; + private: void ReportModuleExportsHelper(std::set<ClangModulesDeclVendor::ModuleID> &exports, @@ -420,7 +422,7 @@ ClangModulesDeclVendorImpl::FindDecls(ConstString name, bool append, void ClangModulesDeclVendorImpl::ForEachMacro( const ClangModulesDeclVendor::ModuleVector &modules, - std::function<bool(const std::string &)> handler) { + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) { if (!m_enabled) { return; } @@ -490,7 +492,8 @@ void ClangModulesDeclVendorImpl::ForEachMacro( if (macro_info) { std::string macro_expansion = "#define "; - macro_expansion.append(mi->first->getName().str()); + llvm::StringRef macro_identifier = mi->first->getName(); + macro_expansion.append(macro_identifier.str()); { if (macro_info->isFunctionLike()) { @@ -575,7 +578,7 @@ void ClangModulesDeclVendorImpl::ForEachMacro( } } - if (handler(macro_expansion)) { + if (handler(macro_identifier, macro_expansion)) { return; } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h index f04d1b07f03d..d820552a2912 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h @@ -90,13 +90,13 @@ public: /// if module A #defines a macro and module B #undefs it. /// /// \param[in] handler - /// A function to call with the text of each #define (including the - /// #define directive). #undef directives are not included; we simply - /// elide any corresponding #define. If this function returns true, - /// we stop the iteration immediately. - virtual void - ForEachMacro(const ModuleVector &modules, - std::function<bool(const std::string &)> handler) = 0; + /// A function to call with the identifier of this macro and the text of + /// each #define (including the #define directive). #undef directives are + /// not included; we simply elide any corresponding #define. If this + /// function returns true, we stop the iteration immediately. + virtual void ForEachMacro( + const ModuleVector &modules, + std::function<bool(llvm::StringRef, llvm::StringRef)> handler) = 0; /// Query whether Clang supports modules for a particular language. /// LLDB uses this to decide whether to try to find the modules loaded diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp index a28b4a7fb42c..9be294750fa0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp @@ -417,7 +417,6 @@ void ClangUserExpression::CreateSourceCode( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, std::vector<std::string> modules_to_import, bool for_completion) { - m_filename = m_clang_state->GetNextExprFileName(); std::string prefix = m_expr_prefix; if (m_options.GetExecutionPolicy() == eExecutionPolicyTopLevel) { @@ -477,9 +476,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, if (!target) return LogConfigError("No target"); - if (!target->GetEnableImportStdModule()) - return LogConfigError("Importing std module not enabled in settings"); - StackFrame *frame = exe_ctx.GetFramePtr(); if (!frame) return LogConfigError("No frame"); @@ -529,8 +525,6 @@ CppModuleConfiguration GetModuleConfig(lldb::LanguageType language, bool ClangUserExpression::PrepareForParsing( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx, bool for_completion) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - InstallContext(exe_ctx); if (!SetupPersistentState(diagnostic_manager, exe_ctx)) @@ -551,50 +545,20 @@ bool ClangUserExpression::PrepareForParsing( SetupDeclVendor(exe_ctx, m_target, diagnostic_manager); - CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); - llvm::ArrayRef<std::string> imported_modules = - module_config.GetImportedModules(); - m_imported_cpp_modules = !imported_modules.empty(); - m_include_directories = module_config.GetIncludeDirs(); + m_filename = m_clang_state->GetNextExprFileName(); - LLDB_LOG(log, "List of imported modules in expression: {0}", - llvm::make_range(imported_modules.begin(), imported_modules.end())); - LLDB_LOG(log, "List of include directories gathered for modules: {0}", - llvm::make_range(m_include_directories.begin(), - m_include_directories.end())); + if (m_target->GetImportStdModule() == eImportStdModuleTrue) + SetupCppModuleImports(exe_ctx); - CreateSourceCode(diagnostic_manager, exe_ctx, imported_modules, + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, for_completion); return true; } -bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx, - lldb_private::ExecutionPolicy execution_policy, - bool keep_result_in_memory, - bool generate_debug_info) { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); - - if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) - return false; - - LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); - - //////////////////////////////////// - // Set up the target and compiler - // - - Target *target = exe_ctx.GetTargetPtr(); - - if (!target) { - diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); - return false; - } - - ////////////////////////// - // Parse the expression - // - +bool ClangUserExpression::TryParse( + DiagnosticManager &diagnostic_manager, ExecutionContextScope *exe_scope, + ExecutionContext &exe_ctx, lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, bool generate_debug_info) { m_materializer_up = std::make_unique<Materializer>(); ResetDeclMap(exe_ctx, m_result_delegate, keep_result_in_memory); @@ -612,26 +576,16 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, DeclMap()->SetLookupsEnabled(true); } - Process *process = exe_ctx.GetProcessPtr(); - ExecutionContextScope *exe_scope = process; - - if (!exe_scope) - exe_scope = exe_ctx.GetTargetPtr(); - - // We use a shared pointer here so we can use the original parser - if it - // succeeds or the rewrite parser we might make if it fails. But the - // parser_sp will never be empty. - - ClangExpressionParser parser(exe_scope, *this, generate_debug_info, - m_include_directories, m_filename); + m_parser = std::make_unique<ClangExpressionParser>( + exe_scope, *this, generate_debug_info, m_include_directories, m_filename); - unsigned num_errors = parser.Parse(diagnostic_manager); + unsigned num_errors = m_parser->Parse(diagnostic_manager); // Check here for FixItHints. If there are any try to apply the fixits and // set the fixed text in m_fixed_text before returning an error. if (num_errors) { if (diagnostic_manager.HasFixIts()) { - if (parser.RewriteExpression(diagnostic_manager)) { + if (m_parser->RewriteExpression(diagnostic_manager)) { size_t fixed_start; size_t fixed_end; m_fixed_text = diagnostic_manager.GetFixedExpression(); @@ -652,7 +606,7 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, // { - Status jit_error = parser.PrepareForExecution( + Status jit_error = m_parser->PrepareForExecution( m_jit_start_addr, m_jit_end_addr, m_execution_unit_sp, exe_ctx, m_can_interpret, execution_policy); @@ -666,10 +620,91 @@ bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, return false; } } + return true; +} + +void ClangUserExpression::SetupCppModuleImports(ExecutionContext &exe_ctx) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + CppModuleConfiguration module_config = GetModuleConfig(m_language, exe_ctx); + m_imported_cpp_modules = module_config.GetImportedModules(); + m_include_directories = module_config.GetIncludeDirs(); + + LLDB_LOG(log, "List of imported modules in expression: {0}", + llvm::make_range(m_imported_cpp_modules.begin(), + m_imported_cpp_modules.end())); + LLDB_LOG(log, "List of include directories gathered for modules: {0}", + llvm::make_range(m_include_directories.begin(), + m_include_directories.end())); +} + +static bool shouldRetryWithCppModule(Target &target, ExecutionPolicy exe_policy) { + // Top-level expression don't yet support importing C++ modules. + if (exe_policy == ExecutionPolicy::eExecutionPolicyTopLevel) + return false; + return target.GetImportStdModule() == eImportStdModuleFallback; +} + +bool ClangUserExpression::Parse(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, + bool keep_result_in_memory, + bool generate_debug_info) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); + + if (!PrepareForParsing(diagnostic_manager, exe_ctx, /*for_completion*/ false)) + return false; + + LLDB_LOGF(log, "Parsing the following code:\n%s", m_transformed_text.c_str()); + + //////////////////////////////////// + // Set up the target and compiler + // + + Target *target = exe_ctx.GetTargetPtr(); + + if (!target) { + diagnostic_manager.PutString(eDiagnosticSeverityError, "invalid target"); + return false; + } + + ////////////////////////// + // Parse the expression + // + + Process *process = exe_ctx.GetProcessPtr(); + ExecutionContextScope *exe_scope = process; + + if (!exe_scope) + exe_scope = exe_ctx.GetTargetPtr(); + + bool parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + // If the expression failed to parse, check if retrying parsing with a loaded + // C++ module is possible. + if (!parse_success && shouldRetryWithCppModule(*target, execution_policy)) { + // Load the loaded C++ modules. + SetupCppModuleImports(exe_ctx); + // If we did load any modules, then retry parsing. + if (!m_imported_cpp_modules.empty()) { + // The module imports are injected into the source code wrapper, + // so recreate those. + CreateSourceCode(diagnostic_manager, exe_ctx, m_imported_cpp_modules, + /*for_completion*/ false); + // Clear the error diagnostics from the previous parse attempt. + diagnostic_manager.Clear(); + parse_success = TryParse(diagnostic_manager, exe_scope, exe_ctx, + execution_policy, keep_result_in_memory, + generate_debug_info); + } + } + if (!parse_success) + return false; if (exe_ctx.GetProcessPtr() && execution_policy == eExecutionPolicyTopLevel) { Status static_init_error = - parser.RunStaticInitializers(m_execution_unit_sp, exe_ctx); + m_parser->RunStaticInitializers(m_execution_unit_sp, exe_ctx); if (!static_init_error.Success()) { const char *error_cstr = static_init_error.AsCString(); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h index f734069655ef..b628f6debf66 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h @@ -168,12 +168,23 @@ public: lldb::ExpressionVariableSP GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override; - bool DidImportCxxModules() const { return m_imported_cpp_modules; } + /// Returns true iff this expression is using any imported C++ modules. + bool DidImportCxxModules() const { return !m_imported_cpp_modules.empty(); } private: /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the /// environment. + /// Contains the actual parsing implementation. + /// The parameter have the same meaning as in ClangUserExpression::Parse. + /// \see ClangUserExpression::Parse + bool TryParse(DiagnosticManager &diagnostic_manager, + ExecutionContextScope *exe_scope, ExecutionContext &exe_ctx, + lldb_private::ExecutionPolicy execution_policy, bool keep_result_in_memory, + bool generate_debug_info); + + void SetupCppModuleImports(ExecutionContext &exe_ctx); + void ScanContext(ExecutionContext &exe_ctx, lldb_private::Status &err) override; @@ -219,6 +230,8 @@ private: ResultDelegate m_result_delegate; ClangPersistentVariables *m_clang_state; std::unique_ptr<ClangExpressionSourceCode> m_source_code; + /// The parser instance we used to parse the expression. + std::unique_ptr<ClangExpressionParser> m_parser; /// File name used for the expression. std::string m_filename; @@ -226,8 +239,9 @@ private: /// See the comment to `UserExpression::Evaluate` for details. ValueObject *m_ctx_obj; - /// True iff this expression explicitly imported C++ modules. - bool m_imported_cpp_modules = false; + /// A list of module names that should be imported when parsing. + /// \see CppModuleConfiguration::GetImportedModules + std::vector<std::string> m_imported_cpp_modules; /// True if the expression parser should enforce the presence of a valid class /// pointer in order to generate the expression as a method. diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp index 25ec982220a0..9788a4e1c183 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp @@ -42,12 +42,11 @@ char ClangUtilityFunction::ID; /// \param[in] name /// The name of the function, as used in the text. ClangUtilityFunction::ClangUtilityFunction(ExecutionContextScope &exe_scope, - const char *text, const char *name) - : UtilityFunction(exe_scope, text, name) { - m_function_text.assign(ClangExpressionSourceCode::g_expression_prefix); - if (text && text[0]) - m_function_text.append(text); -} + std::string text, std::string name) + : UtilityFunction( + exe_scope, + std::string(ClangExpressionSourceCode::g_expression_prefix) + text, + std::move(name)) {} ClangUtilityFunction::~ClangUtilityFunction() {} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h index 1f2dd5fdbecc..7914e1406cd0 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h @@ -41,6 +41,34 @@ public: } static bool classof(const Expression *obj) { return obj->isA(&ID); } + /// Constructor + /// + /// \param[in] text + /// The text of the function. Must be a full translation unit. + /// + /// \param[in] name + /// The name of the function, as used in the text. + ClangUtilityFunction(ExecutionContextScope &exe_scope, std::string text, + std::string name); + + ~ClangUtilityFunction() override; + + ExpressionTypeSystemHelper *GetTypeSystemHelper() override { + return &m_type_system_helper; + } + + ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } + + void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } + + void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { + m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); + } + + bool Install(DiagnosticManager &diagnostic_manager, + ExecutionContext &exe_ctx) override; + +private: class ClangUtilityFunctionHelper : public ClangExpressionHelper { public: ClangUtilityFunctionHelper() {} @@ -58,7 +86,7 @@ public: void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory); /// Return the object that the parser should allow to access ASTs. May be - /// NULL if the ASTs do not need to be transformed. + /// nullptr if the ASTs do not need to be transformed. /// /// \param[in] passthrough /// The ASTConsumer that the returned transformer should send @@ -71,37 +99,9 @@ public: private: std::unique_ptr<ClangExpressionDeclMap> m_expr_decl_map_up; }; - /// Constructor - /// - /// \param[in] text - /// The text of the function. Must be a full translation unit. - /// - /// \param[in] name - /// The name of the function, as used in the text. - ClangUtilityFunction(ExecutionContextScope &exe_scope, const char *text, - const char *name); - - ~ClangUtilityFunction() override; - - ExpressionTypeSystemHelper *GetTypeSystemHelper() override { - return &m_type_system_helper; - } - ClangExpressionDeclMap *DeclMap() { return m_type_system_helper.DeclMap(); } - - void ResetDeclMap() { m_type_system_helper.ResetDeclMap(); } - - void ResetDeclMap(ExecutionContext &exe_ctx, bool keep_result_in_memory) { - m_type_system_helper.ResetDeclMap(exe_ctx, keep_result_in_memory); - } - - bool Install(DiagnosticManager &diagnostic_manager, - ExecutionContext &exe_ctx) override; - -private: - ClangUtilityFunctionHelper m_type_system_helper; ///< The map to use when - ///parsing and materializing - ///the expression. + /// The map to use when parsing and materializing the expression. + ClangUtilityFunctionHelper m_type_system_helper; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp index f1272c67d20f..ffab16b1682b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp @@ -38,9 +38,11 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { // Check for /c++/vX/ that is used by libc++. static llvm::Regex libcpp_regex(R"regex(/c[+][+]/v[0-9]/)regex"); - if (libcpp_regex.match(f.GetPath())) { - // Strip away libc++'s /experimental directory if there is one. - posix_dir.consume_back("/experimental"); + // If the path is in the libc++ include directory use it as the found libc++ + // path. Ignore subdirectories such as /c++/v1/experimental as those don't + // need to be specified in the header search. + if (libcpp_regex.match(f.GetPath()) && + parent_path(posix_dir, Style::posix).endswith("c++")) { return m_std_inc.TrySet(posix_dir); } @@ -55,9 +57,38 @@ bool CppModuleConfiguration::analyzeFile(const FileSpec &f) { return true; } +/// Utility function for just appending two paths. +static std::string MakePath(llvm::StringRef lhs, llvm::StringRef rhs) { + llvm::SmallString<256> result(lhs); + llvm::sys::path::append(result, rhs); + return std::string(result); +} + bool CppModuleConfiguration::hasValidConfig() { - // We all these include directories to have a valid usable configuration. - return m_c_inc.Valid() && m_std_inc.Valid(); + // We need to have a C and C++ include dir for a valid configuration. + if (!m_c_inc.Valid() || !m_std_inc.Valid()) + return false; + + // Do some basic sanity checks on the directories that we don't activate + // the module when it's clear that it's not usable. + const std::vector<std::string> files_to_check = { + // * Check that the C library contains at least one random C standard + // library header. + MakePath(m_c_inc.Get(), "stdio.h"), + // * Without a libc++ modulemap file we can't have a 'std' module that + // could be imported. + MakePath(m_std_inc.Get(), "module.modulemap"), + // * Check for a random libc++ header (vector in this case) that has to + // exist in a working libc++ setup. + MakePath(m_std_inc.Get(), "vector"), + }; + + for (llvm::StringRef file_to_check : files_to_check) { + if (!FileSystem::Instance().Exists(file_to_check)) + return false; + } + + return true; } CppModuleConfiguration::CppModuleConfiguration( @@ -76,7 +107,8 @@ CppModuleConfiguration::CppModuleConfiguration( m_resource_inc = std::string(resource_dir.str()); // This order matches the way Clang orders these directories. - m_include_dirs = {m_std_inc.Get(), m_resource_inc, m_c_inc.Get()}; + m_include_dirs = {m_std_inc.Get().str(), m_resource_inc, + m_c_inc.Get().str()}; m_imported_modules = {"std"}; } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h index 235ac2bd090c..b984db43fa6d 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h @@ -32,7 +32,7 @@ class CppModuleConfiguration { /// the path was already set. LLVM_NODISCARD bool TrySet(llvm::StringRef path); /// Return the path if there is one. - std::string Get() const { + llvm::StringRef Get() const { assert(m_valid && "Called Get() on an invalid SetOncePath?"); return m_path; } @@ -57,9 +57,6 @@ class CppModuleConfiguration { public: /// Creates a configuration by analyzing the given list of used source files. - /// - /// Currently only looks at the used paths and doesn't actually access the - /// files on the disk. explicit CppModuleConfiguration(const FileSpecList &support_files); /// Creates an empty and invalid configuration. CppModuleConfiguration() {} diff --git a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp index 2f8cf1846ee7..f953e860969c 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp @@ -22,6 +22,7 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) std::initializer_list<const char *> supported_names = { // containers + "array", "deque", "forward_list", "list", @@ -34,6 +35,7 @@ CxxModuleHandler::CxxModuleHandler(ASTImporter &importer, ASTContext *target) "weak_ptr", // utility "allocator", + "pair", }; m_supported_templates.insert(supported_names.begin(), supported_names.end()); } @@ -180,21 +182,21 @@ 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 {}; + return llvm::None; // We only care about templates in the std namespace. if (!td->getDeclContext()->isStdNamespace()) - return {}; + return llvm::None; // We have a list of supported template names. - if (m_supported_templates.find(td->getName()) == m_supported_templates.end()) - return {}; + if (!m_supported_templates.contains(td->getName())) + return llvm::None; // 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 {}; + return llvm::None; // Find the local DeclContext that corresponds to the DeclContext of our // decl we want to import. @@ -205,7 +207,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { "Got error while searching equal local DeclContext for decl " "'{1}':\n{0}", td->getName()); - return {}; + return llvm::None; } // Look up the template in our local context. @@ -218,7 +220,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { break; } if (!new_class_template) - return {}; + return llvm::None; // Import the foreign template arguments. llvm::SmallVector<TemplateArgument, 4> imported_args; @@ -230,7 +232,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { llvm::Expected<QualType> type = m_importer->Import(arg.getAsType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back(TemplateArgument(*type)); break; @@ -241,7 +243,7 @@ llvm::Optional<Decl *> CxxModuleHandler::tryInstantiateStdTemplate(Decl *d) { m_importer->Import(arg.getIntegralType()); if (!type) { LLDB_LOG_ERROR(log, type.takeError(), "Couldn't import type: {0}"); - return {}; + return llvm::None; } imported_args.push_back( TemplateArgument(d->getASTContext(), integral, *type)); diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp index b92f00ec2b63..a6e36d81b950 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp @@ -48,29 +48,27 @@ ClangDynamicCheckerFunctions::~ClangDynamicCheckerFunctions() = default; bool ClangDynamicCheckerFunctions::Install( DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) { - Status error; - m_valid_pointer_check.reset( - exe_ctx.GetTargetRef().GetUtilityFunctionForLanguage( - g_valid_pointer_check_text, lldb::eLanguageTypeC, - VALID_POINTER_CHECK_NAME, error)); - if (error.Fail()) + auto utility_fn_or_error = exe_ctx.GetTargetRef().CreateUtilityFunction( + g_valid_pointer_check_text, VALID_POINTER_CHECK_NAME, + lldb::eLanguageTypeC, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_valid_pointer_check = std::move(*utility_fn_or_error); - if (!m_valid_pointer_check->Install(diagnostic_manager, exe_ctx)) - return false; - - Process *process = exe_ctx.GetProcessPtr(); - - if (process) { + if (Process *process = exe_ctx.GetProcessPtr()) { ObjCLanguageRuntime *objc_language_runtime = ObjCLanguageRuntime::Get(*process); if (objc_language_runtime) { - m_objc_object_check.reset(objc_language_runtime->CreateObjectChecker( - VALID_OBJC_OBJECT_CHECK_NAME)); - - if (!m_objc_object_check->Install(diagnostic_manager, exe_ctx)) + auto utility_fn_or_error = objc_language_runtime->CreateObjectChecker( + VALID_OBJC_OBJECT_CHECK_NAME, exe_ctx); + if (!utility_fn_or_error) { + llvm::consumeError(utility_fn_or_error.takeError()); return false; + } + m_objc_object_check = std::move(*utility_fn_or_error); } } diff --git a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp index 8511e554509a..b35bf07034bd 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp @@ -305,9 +305,7 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { } lldb::TargetSP target_sp(m_execution_unit.GetTarget()); - lldb_private::ExecutionContext exe_ctx(target_sp, true); - llvm::Optional<uint64_t> bit_size = - m_result_type.GetBitSize(exe_ctx.GetBestExecutionContextScope()); + llvm::Optional<uint64_t> bit_size = m_result_type.GetBitSize(target_sp.get()); if (!bit_size) { lldb_private::StreamString type_desc_stream; m_result_type.DumpTypeDescription(&type_desc_stream); @@ -330,7 +328,8 @@ bool IRForTarget::CreateResultVariable(llvm::Function &llvm_function) { m_result_name = lldb_private::ConstString("$RESULT_NAME"); LLDB_LOG(log, "Creating a new result global: \"{0}\" with size {1}", - m_result_name, m_result_type.GetByteSize(nullptr).getValueOr(0)); + m_result_name, + m_result_type.GetByteSize(target_sp.get()).getValueOr(0)); // Construct a new result global and set up its metadata @@ -1242,10 +1241,12 @@ bool IRForTarget::MaybeHandleVariable(Value *llvm_value_ptr) { value_type = global_variable->getType(); } - llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(nullptr); + auto *target = m_execution_unit.GetTarget().get(); + llvm::Optional<uint64_t> value_size = compiler_type.GetByteSize(target); if (!value_size) return false; - llvm::Optional<size_t> opt_alignment = compiler_type.GetTypeBitAlign(nullptr); + llvm::Optional<size_t> opt_alignment = + compiler_type.GetTypeBitAlign(target); if (!opt_alignment) return false; lldb::offset_t value_alignment = (*opt_alignment + 7ull) / 8ull; diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h index b7b6640c4810..4fe727460fdb 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h +++ b/lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h @@ -18,7 +18,7 @@ class ModuleDependencyCollectorAdaptor : public clang::ModuleDependencyCollector { public: ModuleDependencyCollectorAdaptor( - std::shared_ptr<llvm::FileCollector> file_collector) + std::shared_ptr<llvm::FileCollectorBase> file_collector) : clang::ModuleDependencyCollector(""), m_file_collector(file_collector) { } @@ -33,7 +33,7 @@ public: void writeFileMap() override {} private: - std::shared_ptr<llvm::FileCollector> m_file_collector; + std::shared_ptr<llvm::FileCollectorBase> m_file_collector; }; } // namespace lldb_private diff --git a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp index c1f88889f1dc..829afa5ffcec 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp @@ -78,7 +78,8 @@ clang::NamedDecl *NameSearchContext::AddFunDecl(const CompilerType &type, clang::FunctionDecl *func_decl = FunctionDecl::Create( ast, context, SourceLocation(), SourceLocation(), decl_name, qual_type, nullptr, SC_Extern, isInlineSpecified, hasWrittenPrototype, - isConstexprSpecified ? CSK_constexpr : CSK_unspecified); + isConstexprSpecified ? ConstexprSpecKind::Constexpr + : ConstexprSpecKind::Unspecified); // We have to do more than just synthesize the FunctionDecl. We have to // synthesize ParmVarDecls for all of the FunctionDecl's arguments. To do |
