aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ExpressionParser
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ExpressionParser')
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ASTResultSynthesizer.cpp4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ASTUtils.h22
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.cpp99
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h60
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangASTSource.cpp48
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp30
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h9
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp82
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp19
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangHost.cpp6
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp15
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h14
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp155
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h20
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp11
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.h62
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.cpp44
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CppModuleConfiguration.h5
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/CxxModuleHandler.cpp20
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/IRDynamicChecks.cpp30
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/IRForTarget.cpp13
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/ModuleDependencyCollector.h4
-rw-r--r--lldb/source/Plugins/ExpressionParser/Clang/NameSearchContext.cpp3
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