-
Notifications
You must be signed in to change notification settings - Fork 12.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[lldb][ClangExpressionParser][NFC] Factor LangOptions logic out of ClangExpressionParser constructor #101669
Conversation
…angExpressionParser constructor We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward.
@llvm/pr-subscribers-lldb Author: Michael Buch (Michael137) ChangesWe plan to eventually use the Clang driver to initialize the This should make refactorings of this code more straightforward. Full diff: https://github.com/llvm/llvm-project/pull/101669.diff 3 Files Affected:
diff --git a/lldb/include/lldb/Expression/Expression.h b/lldb/include/lldb/Expression/Expression.h
index 356fe4b82ae43..8de9364436ccf 100644
--- a/lldb/include/lldb/Expression/Expression.h
+++ b/lldb/include/lldb/Expression/Expression.h
@@ -56,7 +56,7 @@ class Expression {
/// Return the desired result type of the function, or eResultTypeAny if
/// indifferent.
- virtual ResultType DesiredResultType() { return eResultTypeAny; }
+ virtual ResultType DesiredResultType() const { return eResultTypeAny; }
/// Flags
diff --git a/lldb/include/lldb/Expression/UserExpression.h b/lldb/include/lldb/Expression/UserExpression.h
index b04d00b72e8fa..7ce463d2cb4e7 100644
--- a/lldb/include/lldb/Expression/UserExpression.h
+++ b/lldb/include/lldb/Expression/UserExpression.h
@@ -206,7 +206,7 @@ class UserExpression : public Expression {
/// Return the desired result type of the function, or eResultTypeAny if
/// indifferent.
- ResultType DesiredResultType() override { return m_desired_type; }
+ ResultType DesiredResultType() const override { return m_desired_type; }
/// Return true if validation code should be inserted into the expression.
bool NeedsValidation() override { return true; }
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 303e88feea20b..11d519e738ee5 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -77,6 +77,7 @@
#include "lldb/Host/HostInfo.h"
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/Language.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
@@ -351,62 +352,20 @@ static void SetupDefaultClangDiagnostics(CompilerInstance &compiler) {
}
}
-//===----------------------------------------------------------------------===//
-// Implementation of ClangExpressionParser
-//===----------------------------------------------------------------------===//
-
-ClangExpressionParser::ClangExpressionParser(
- ExecutionContextScope *exe_scope, Expression &expr,
- bool generate_debug_info, std::vector<std::string> include_directories,
- std::string filename)
- : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
- m_pp_callbacks(nullptr),
- m_include_directories(std::move(include_directories)),
- m_filename(std::move(filename)) {
+static void SetupLangOpts(CompilerInstance &compiler,
+ ExecutionContextScope &exe_scope,
+ Expression const &expr) {
Log *log = GetLog(LLDBLog::Expressions);
- // We can't compile expressions without a target. So if the exe_scope is
- // null or doesn't have a target, then we just need to get out of here. I'll
- // lldbassert and not make any of the compiler objects since
- // I can't return errors directly from the constructor. Further calls will
- // check if the compiler was made and
- // bag out if it wasn't.
-
- if (!exe_scope) {
- lldbassert(exe_scope &&
- "Can't make an expression parser with a null scope.");
- return;
- }
-
- lldb::TargetSP target_sp;
- target_sp = exe_scope->CalculateTarget();
- if (!target_sp) {
- lldbassert(target_sp.get() &&
- "Can't make an expression parser with a null target.");
- return;
- }
-
- // 1. Create a new compiler instance.
- m_compiler = std::make_unique<CompilerInstance>();
+ // If the expression is being evaluated in the context of an existing stack
+ // frame, we introspect to see if the language runtime is available.
- // Make sure clang uses the same VFS as LLDB.
- m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
+ lldb::StackFrameSP frame_sp = exe_scope.CalculateStackFrame();
+ lldb::ProcessSP process_sp = exe_scope.CalculateProcess();
// Defaults to lldb::eLanguageTypeUnknown.
lldb::LanguageType frame_lang = expr.Language().AsLanguageType();
- std::string abi;
- ArchSpec target_arch;
- target_arch = target_sp->GetArchitecture();
-
- const auto target_machine = target_arch.GetMachine();
-
- // If the expression is being evaluated in the context of an existing stack
- // frame, we introspect to see if the language runtime is available.
-
- lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame();
- lldb::ProcessSP process_sp = exe_scope->CalculateProcess();
-
// Make sure the user hasn't provided a preferred execution language with
// `expression --language X -- ...`
if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown)
@@ -414,73 +373,11 @@ ClangExpressionParser::ClangExpressionParser(
if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) {
LLDB_LOGF(log, "Frame has language of type %s",
- Language::GetNameForLanguageType(frame_lang));
+ lldb_private::Language::GetNameForLanguageType(frame_lang));
}
- // 2. Configure the compiler with a set of default options that are
- // appropriate for most situations.
- if (target_arch.IsValid()) {
- std::string triple = target_arch.GetTriple().str();
- m_compiler->getTargetOpts().Triple = triple;
- LLDB_LOGF(log, "Using %s as the target triple",
- m_compiler->getTargetOpts().Triple.c_str());
- } else {
- // If we get here we don't have a valid target and just have to guess.
- // Sometimes this will be ok to just use the host target triple (when we
- // evaluate say "2+3", but other expressions like breakpoint conditions and
- // other things that _are_ target specific really shouldn't just be using
- // the host triple. In such a case the language runtime should expose an
- // overridden options set (3), below.
- m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
- LLDB_LOGF(log, "Using default target triple of %s",
- m_compiler->getTargetOpts().Triple.c_str());
- }
- // Now add some special fixes for known architectures: Any arm32 iOS
- // environment, but not on arm64
- if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
- m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
- m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) {
- m_compiler->getTargetOpts().ABI = "apcs-gnu";
- }
- // Supported subsets of x86
- if (target_machine == llvm::Triple::x86 ||
- target_machine == llvm::Triple::x86_64) {
- m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse");
- m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse2");
- }
-
- // Set the target CPU to generate code for. This will be empty for any CPU
- // that doesn't really need to make a special
- // CPU string.
- m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU();
-
- // Set the target ABI
- abi = GetClangTargetABI(target_arch);
- if (!abi.empty())
- m_compiler->getTargetOpts().ABI = abi;
-
- // 3. 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) {
- LLDB_LOGF(log, "Target datalayout string: '%s'",
- target_info->getDataLayoutString());
- LLDB_LOGF(log, "Target ABI: '%s'", target_info->getABI().str().c_str());
- LLDB_LOGF(log, "Target vector alignment: %d",
- target_info->getMaxVectorAlign());
- }
- m_compiler->setTarget(target_info);
-
- assert(m_compiler->hasTarget());
-
- // 4. Set language options.
lldb::LanguageType language = expr.Language().AsLanguageType();
- LangOptions &lang_opts = m_compiler->getLangOpts();
+ LangOptions &lang_opts = compiler.getLangOpts();
switch (language) {
case lldb::eLanguageTypeC:
@@ -522,7 +419,7 @@ ClangExpressionParser::ClangExpressionParser(
case lldb::eLanguageTypeC_plus_plus_11:
case lldb::eLanguageTypeC_plus_plus_14:
lang_opts.CPlusPlus11 = true;
- m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ compiler.getHeaderSearchOpts().UseLibcxx = true;
[[fallthrough]];
case lldb::eLanguageTypeC_plus_plus_03:
lang_opts.CPlusPlus = true;
@@ -539,7 +436,7 @@ ClangExpressionParser::ClangExpressionParser(
lang_opts.ObjC = true;
lang_opts.CPlusPlus = true;
lang_opts.CPlusPlus11 = true;
- m_compiler->getHeaderSearchOpts().UseLibcxx = true;
+ compiler.getHeaderSearchOpts().UseLibcxx = true;
break;
}
@@ -551,42 +448,14 @@ ClangExpressionParser::ClangExpressionParser(
if (expr.DesiredResultType() == Expression::eResultTypeId)
lang_opts.DebuggerCastResultToId = true;
- lang_opts.CharIsSigned = ArchSpec(m_compiler->getTargetOpts().Triple.c_str())
- .CharIsSignedByDefault();
+ lang_opts.CharIsSigned =
+ ArchSpec(compiler.getTargetOpts().Triple.c_str()).CharIsSignedByDefault();
// Spell checking is a nice feature, but it ends up completing a lot of types
// that we didn't strictly speaking need to complete. As a result, we spend a
// long time parsing and importing debug information.
lang_opts.SpellChecking = false;
- auto *clang_expr = dyn_cast<ClangUserExpression>(&m_expr);
- if (clang_expr && clang_expr->DidImportCxxModules()) {
- LLDB_LOG(log, "Adding lang options for importing C++ modules");
-
- lang_opts.Modules = true;
- // We want to implicitly build modules.
- lang_opts.ImplicitModules = true;
- // To automatically import all submodules when we import 'std'.
- lang_opts.ModulesLocalVisibility = false;
-
- // We use the @import statements, so we need this:
- // FIXME: We could use the modules-ts, but that currently doesn't work.
- lang_opts.ObjC = true;
-
- // Options we need to parse libc++ code successfully.
- // FIXME: We should ask the driver for the appropriate default flags.
- lang_opts.GNUMode = true;
- lang_opts.GNUKeywords = true;
- lang_opts.CPlusPlus11 = true;
- lang_opts.BuiltinHeadersInSystemModules = true;
-
- // The Darwin libc expects this macro to be set.
- lang_opts.GNUCVersion = 40201;
-
- SetupModuleHeaderPaths(m_compiler.get(), m_include_directories,
- target_sp);
- }
-
if (process_sp && lang_opts.ObjC) {
if (auto *runtime = ObjCLanguageRuntime::Get(*process_sp)) {
switch (runtime->GetRuntimeVersion()) {
@@ -615,6 +484,146 @@ ClangExpressionParser::ClangExpressionParser(
// 'fopen'). Those libc functions are already correctly handled by LLDB, and
// additionally enabling them as expandable builtins is breaking Clang.
lang_opts.NoBuiltin = true;
+}
+
+void SetupImportStdModuleLangOpts(CompilerInstance &compiler) {
+ LangOptions &lang_opts = compiler.getLangOpts();
+ lang_opts.Modules = true;
+ // We want to implicitly build modules.
+ lang_opts.ImplicitModules = true;
+ // To automatically import all submodules when we import 'std'.
+ lang_opts.ModulesLocalVisibility = false;
+
+ // We use the @import statements, so we need this:
+ // FIXME: We could use the modules-ts, but that currently doesn't work.
+ lang_opts.ObjC = true;
+
+ // Options we need to parse libc++ code successfully.
+ // FIXME: We should ask the driver for the appropriate default flags.
+ lang_opts.GNUMode = true;
+ lang_opts.GNUKeywords = true;
+ lang_opts.CPlusPlus11 = true;
+ lang_opts.BuiltinHeadersInSystemModules = true;
+
+ // The Darwin libc expects this macro to be set.
+ lang_opts.GNUCVersion = 40201;
+}
+
+//===----------------------------------------------------------------------===//
+// Implementation of ClangExpressionParser
+//===----------------------------------------------------------------------===//
+
+ClangExpressionParser::ClangExpressionParser(
+ ExecutionContextScope *exe_scope, Expression &expr,
+ bool generate_debug_info, std::vector<std::string> include_directories,
+ std::string filename)
+ : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
+ m_pp_callbacks(nullptr),
+ m_include_directories(std::move(include_directories)),
+ m_filename(std::move(filename)) {
+ Log *log = GetLog(LLDBLog::Expressions);
+
+ // We can't compile expressions without a target. So if the exe_scope is
+ // null or doesn't have a target, then we just need to get out of here. I'll
+ // lldbassert and not make any of the compiler objects since
+ // I can't return errors directly from the constructor. Further calls will
+ // check if the compiler was made and
+ // bag out if it wasn't.
+
+ if (!exe_scope) {
+ lldbassert(exe_scope &&
+ "Can't make an expression parser with a null scope.");
+ return;
+ }
+
+ lldb::TargetSP target_sp;
+ target_sp = exe_scope->CalculateTarget();
+ if (!target_sp) {
+ lldbassert(target_sp.get() &&
+ "Can't make an expression parser with a null target.");
+ return;
+ }
+
+ // 1. Create a new compiler instance.
+ m_compiler = std::make_unique<CompilerInstance>();
+
+ // Make sure clang uses the same VFS as LLDB.
+ m_compiler->createFileManager(FileSystem::Instance().GetVirtualFileSystem());
+
+ std::string abi;
+ ArchSpec target_arch;
+ target_arch = target_sp->GetArchitecture();
+
+ const auto target_machine = target_arch.GetMachine();
+
+ // 2. Configure the compiler with a set of default options that are
+ // appropriate for most situations.
+ if (target_arch.IsValid()) {
+ std::string triple = target_arch.GetTriple().str();
+ m_compiler->getTargetOpts().Triple = triple;
+ LLDB_LOGF(log, "Using %s as the target triple",
+ m_compiler->getTargetOpts().Triple.c_str());
+ } else {
+ // If we get here we don't have a valid target and just have to guess.
+ // Sometimes this will be ok to just use the host target triple (when we
+ // evaluate say "2+3", but other expressions like breakpoint conditions and
+ // other things that _are_ target specific really shouldn't just be using
+ // the host triple. In such a case the language runtime should expose an
+ // overridden options set (3), below.
+ m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple();
+ LLDB_LOGF(log, "Using default target triple of %s",
+ m_compiler->getTargetOpts().Triple.c_str());
+ }
+ // Now add some special fixes for known architectures: Any arm32 iOS
+ // environment, but not on arm64
+ if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos &&
+ m_compiler->getTargetOpts().Triple.find("ios") != std::string::npos) {
+ m_compiler->getTargetOpts().ABI = "apcs-gnu";
+ }
+ // Supported subsets of x86
+ if (target_machine == llvm::Triple::x86 ||
+ target_machine == llvm::Triple::x86_64) {
+ m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse");
+ m_compiler->getTargetOpts().FeaturesAsWritten.push_back("+sse2");
+ }
+
+ // Set the target CPU to generate code for. This will be empty for any CPU
+ // that doesn't really need to make a special
+ // CPU string.
+ m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU();
+
+ // Set the target ABI
+ abi = GetClangTargetABI(target_arch);
+ if (!abi.empty())
+ m_compiler->getTargetOpts().ABI = abi;
+
+ // 3. 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) {
+ LLDB_LOGF(log, "Target datalayout string: '%s'",
+ target_info->getDataLayoutString());
+ LLDB_LOGF(log, "Target ABI: '%s'", target_info->getABI().str().c_str());
+ LLDB_LOGF(log, "Target vector alignment: %d",
+ target_info->getMaxVectorAlign());
+ }
+ m_compiler->setTarget(target_info);
+
+ assert(m_compiler->hasTarget());
+
+ // 4. Set language options.
+ SetupLangOpts(*m_compiler, *exe_scope, expr);
+ if (isa<ClangUserExpression>(&m_expr)) {
+ LLDB_LOG(log, "Adding lang options for importing C++ modules");
+ SetupImportStdModuleLangOpts(*m_compiler);
+ SetupModuleHeaderPaths(m_compiler.get(), m_include_directories, target_sp);
+ }
// Set CodeGen options
m_compiler->getCodeGenOpts().EmitDeclMetadata = true;
@@ -648,7 +657,7 @@ ClangExpressionParser::ClangExpressionParser(
m_compiler->createSourceManager(m_compiler->getFileManager());
m_compiler->createPreprocessor(TU_Complete);
- switch (language) {
+ switch (expr.Language().AsLanguageType()) {
case lldb::eLanguageTypeC:
case lldb::eLanguageTypeC89:
case lldb::eLanguageTypeC99:
|
lang_opts.CharIsSigned = ArchSpec(m_compiler->getTargetOpts().Triple.c_str()) | ||
.CharIsSignedByDefault(); | ||
lang_opts.CharIsSigned = | ||
ArchSpec(compiler.getTargetOpts().Triple.c_str()).CharIsSignedByDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
due to clang-format
m_filename(std::move(filename)) { | ||
static void SetupLangOpts(CompilerInstance &compiler, | ||
ExecutionContextScope &exe_scope, | ||
Expression const &expr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the LLVM codebase is more of a west const type of codebase ;)
} | ||
|
||
// 1. Create a new compiler instance. | ||
m_compiler = std::make_unique<CompilerInstance>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems unnecessary for this to be unique_ptr, but I assume this is the IsValid
flag for the object?
It would be cleaner if we had a createClangExpressionParser static function that returned an Expected.
Not a big deal though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed. Though this is how it always was. Didn't want to go too crazy with the refactor :)
We actually don't want to create the manually CompilerInstance
in the future anyway. So there's a good chance this goes away soon
… ClangExpressionParser (#101681) Same motivation as #101669. We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupTargetOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` * Made `GetClangTargetABI` a file-local function since it's not using any of the state in `ClangExpressionParser`, and isn't used anywhere outside the source file
… ClangExpressionParser (llvm#101681) Same motivation as llvm#101669. We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupTargetOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` * Made `GetClangTargetABI` a file-local function since it's not using any of the state in `ClangExpressionParser`, and isn't used anywhere outside the source file
…angExpressionParser constructor (llvm#101669) We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupLangOpts` and `SetupImportStdModuleLangOpts` * Called them from `ClangExpressionParser::ClangExpressionParser`
…angExpressionParser constructor (llvm#101669) We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupLangOpts` and `SetupImportStdModuleLangOpts` * Called them from `ClangExpressionParser::ClangExpressionParser`
… ClangExpressionParser (llvm#101681) Same motivation as llvm#101669. We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupTargetOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` * Made `GetClangTargetABI` a file-local function since it's not using any of the state in `ClangExpressionParser`, and isn't used anywhere outside the source file (cherry picked from commit d6cbcf9)
…angExpressionParser constructor (llvm#101669) We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupLangOpts` and `SetupImportStdModuleLangOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` (cherry picked from commit 12e3a06)
… ClangExpressionParser (llvm#101681) Same motivation as llvm#101669. We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupTargetOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` * Made `GetClangTargetABI` a file-local function since it's not using any of the state in `ClangExpressionParser`, and isn't used anywhere outside the source file (cherry picked from commit d6cbcf9)
…angExpressionParser constructor (llvm#101669) We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupLangOpts` and `SetupImportStdModuleLangOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` (cherry picked from commit 12e3a06)
… ClangExpressionParser (llvm#101681) Same motivation as llvm#101669. We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupTargetOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` * Made `GetClangTargetABI` a file-local function since it's not using any of the state in `ClangExpressionParser`, and isn't used anywhere outside the source file (cherry picked from commit d6cbcf9)
…angExpressionParser constructor (llvm#101669) We plan to eventually use the Clang driver to initialize the `CompilerInstance`. This should make refactorings of this code more straightforward. **Changes**: * Introduced `SetupLangOpts` and `SetupImportStdModuleLangOpts` * Called them from `ClangExpressionParser::ClangExpressionParser` (cherry picked from commit 12e3a06)
We plan to eventually use the Clang driver to initialize the
CompilerInstance
.This should make refactorings of this code more straightforward.
Changes:
SetupLangOpts
andSetupImportStdModuleLangOpts
ClangExpressionParser::ClangExpressionParser