teemperor created this revision.
teemperor added reviewers: aprantl, jingham, shafik, friss, davide.
teemperor added a project: C++ modules in LLDB.
Herald added subscribers: lldb-commits, jdoerfert, abidh, mgorny.
Herald added a reviewer: serge-sans-paille.
Herald added a project: LLDB.

This patch is the MVP version of importing the std module into the expression 
parser to improve C++ debugging.

What happens in this patch is that we inject a `@import std` into our 
expression source code. We also
modify our internal Clang instance for parsing this expression to work with 
modules and debug info
at the same time (which is the main change in terms of LOC). We implicitly 
build the `std` module on the first use. The
C++ include paths for building are extracted from the debug info, which means 
that this currently only
works if the program is compiled with `-glldb -fmodules` and uses the std 
module. The C include paths
are currently specified by LLDB.

I enabled the tests currently only for libc++ and Linux because I could test 
this locally. I'll enable the tests
for other platforms once this has landed and doesn't break any bots (and I 
implemented the platform-specific
C include paths for them).

With this patch we can now:

- Build a libc++ as a module and import it into the expression parser.
- Read from the module while also referencing declarations from the debug info. 
E.g. `std::abs(local_variable)`.

What doesn't work (yet):

- Merging debug info and C++ module declarations. E.g. 
`std::vector<CustomClass>` doesn't work.
- Pretty much anything that involves the ASTImporter and templated code. As the 
ASTImporter is used for saving the result declaration, this means that we can't

call yet any function that returns a non-trivial type.

- Use libstdc++ for this, as it requires multiple include paths and Clang only 
emits one include path per module. Also libstdc++ doesn't support Clang modules 
without patches.


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D58125

Files:
  lldb/include/lldb/Expression/ExpressionSourceCode.h
  lldb/include/lldb/Symbol/CompileUnit.h
  lldb/include/lldb/Symbol/SymbolFile.h
  lldb/include/lldb/Symbol/SymbolVendor.h
  lldb/include/lldb/Target/Platform.h
  lldb/include/lldb/Target/Target.h
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestImportStdModule.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestImportStdModule.py
  
lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
  lldb/source/Expression/ExpressionSourceCode.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.h
  lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
  lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
  lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
  lldb/source/Plugins/Platform/Linux/PlatformLinux.h
  lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
  lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
  lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
  lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
  lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
  lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
  lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
  lldb/source/Symbol/CompileUnit.cpp
  lldb/source/Symbol/SymbolVendor.cpp
  lldb/source/Target/Target.cpp

Index: lldb/source/Target/Target.cpp
===================================================================
--- lldb/source/Target/Target.cpp
+++ lldb/source/Target/Target.cpp
@@ -3313,6 +3313,9 @@
     {"auto-import-clang-modules", OptionValue::eTypeBoolean, false, true,
      nullptr, {},
      "Automatically load Clang modules referred to by the program."},
+    {"import-std-module", OptionValue::eTypeBoolean, false, false,
+     nullptr, {},
+     "Import the C++ std module to improve debugging STL containers."},
     {"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr,
      {}, "Automatically apply fix-it hints to expressions."},
     {"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr,
@@ -3451,6 +3454,7 @@
   ePropertyDebugFileSearchPaths,
   ePropertyClangModuleSearchPaths,
   ePropertyAutoImportClangModules,
+  ePropertyImportStdModule,
   ePropertyAutoApplyFixIts,
   ePropertyNotifyAboutFixIts,
   ePropertySaveObjects,
@@ -3873,6 +3877,12 @@
       nullptr, idx, g_properties[idx].default_uint_value != 0);
 }
 
+bool TargetProperties::GetEnableImportStdModule() const {
+  const uint32_t idx = ePropertyImportStdModule;
+  return m_collection_sp->GetPropertyAtIndexAsBoolean(
+      nullptr, idx, g_properties[idx].default_uint_value != 0);
+}
+
 bool TargetProperties::GetEnableAutoApplyFixIts() const {
   const uint32_t idx = ePropertyAutoApplyFixIts;
   return m_collection_sp->GetPropertyAtIndexAsBoolean(
Index: lldb/source/Symbol/SymbolVendor.cpp
===================================================================
--- lldb/source/Symbol/SymbolVendor.cpp
+++ lldb/source/Symbol/SymbolVendor.cpp
@@ -185,12 +185,15 @@
 }
 
 bool SymbolVendor::ParseImportedModules(
-    const SymbolContext &sc, std::vector<ConstString> &imported_modules) {
+    const SymbolContext &sc,
+    std::vector<SymbolFile::ModulePath> &imported_modules,
+    std::vector<ConstString> &module_includes) {
   ModuleSP module_sp(GetModule());
   if (module_sp) {
     std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
     if (m_sym_file_ap.get())
-      return m_sym_file_ap->ParseImportedModules(sc, imported_modules);
+      return m_sym_file_ap->ParseImportedModules(sc, imported_modules,
+                                                 module_includes);
   }
   return false;
 }
Index: lldb/source/Symbol/CompileUnit.cpp
===================================================================
--- lldb/source/Symbol/CompileUnit.cpp
+++ lldb/source/Symbol/CompileUnit.cpp
@@ -390,19 +390,29 @@
   m_variables = variables;
 }
 
-const std::vector<ConstString> &CompileUnit::GetImportedModules() {
+void CompileUnit::UpdateModules() {
   if (m_imported_modules.empty() &&
       m_flags.IsClear(flagsParsedImportedModules)) {
     m_flags.Set(flagsParsedImportedModules);
     if (SymbolVendor *symbol_vendor = GetModule()->GetSymbolVendor()) {
       SymbolContext sc;
       CalculateSymbolContext(&sc);
-      symbol_vendor->ParseImportedModules(sc, m_imported_modules);
+      symbol_vendor->ParseImportedModules(sc, m_imported_modules,
+                                          m_module_includes);
     }
   }
+}
+
+const std::vector<CompileUnit::ModulePath> &CompileUnit::GetImportedModules() {
+  UpdateModules();
   return m_imported_modules;
 }
 
+const std::vector<ConstString> &CompileUnit::GetModuleIncludes() {
+  UpdateModules();
+  return m_module_includes;
+}
+
 FileSpecList &CompileUnit::GetSupportFiles() {
   if (m_support_files.GetSize() == 0) {
     if (m_flags.IsClear(flagsParsedSupportFiles)) {
Index: lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
===================================================================
--- lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
+++ lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -63,7 +63,8 @@
 
   bool ParseImportedModules(
       const lldb_private::SymbolContext &sc,
-      std::vector<lldb_private::ConstString> &imported_modules) override;
+      std::vector<ModulePath> &imported_modules,
+      std::vector<lldb_private::ConstString> &module_includes) override;
 
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
 
Index: lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
+++ lldb/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -218,7 +218,8 @@
 }
 
 bool SymbolFileSymtab::ParseImportedModules(
-    const SymbolContext &sc, std::vector<ConstString> &imported_modules) {
+    const SymbolContext &sc, std::vector<ModulePath> &imported_modules,
+    std::vector<ConstString> &module_includes) {
   return false;
 }
 
Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.h
@@ -74,7 +74,8 @@
 
   bool ParseImportedModules(
       const lldb_private::SymbolContext &sc,
-      std::vector<lldb_private::ConstString> &imported_modules) override;
+      std::vector<ModulePath> &imported_modules,
+      std::vector<lldb_private::ConstString> &module_includes) override;
 
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
 
Index: lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ lldb/source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -377,7 +377,8 @@
 
 bool SymbolFilePDB::ParseImportedModules(
     const lldb_private::SymbolContext &sc,
-    std::vector<lldb_private::ConstString> &imported_modules) {
+    std::vector<ModulePath> &imported_modules,
+    std::vector<lldb_private::ConstString> &module_includes) {
   // PDB does not yet support module debug info
   return false;
 }
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h
@@ -94,9 +94,9 @@
                          FileSpecList &support_files) override;
   size_t ParseTypes(lldb_private::CompileUnit &comp_unit) override;
 
-  bool
-  ParseImportedModules(const SymbolContext &sc,
-                       std::vector<ConstString> &imported_modules) override;
+  bool ParseImportedModules(const SymbolContext &sc,
+                            std::vector<ModulePath> &imported_modules,
+                            std::vector<ConstString> &module_includes) override;
 
   size_t ParseBlocksRecursive(Function &func) override;
 
Index: lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ lldb/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -1136,7 +1136,8 @@
 }
 
 bool SymbolFileNativePDB::ParseImportedModules(
-    const SymbolContext &sc, std::vector<ConstString> &imported_modules) {
+    const SymbolContext &sc, std::vector<ModulePath> &imported_modules,
+    std::vector<ConstString> &module_includes) {
   // PDB does not yet support module debug info
   return false;
 }
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -72,7 +72,8 @@
 
   bool ParseImportedModules(
       const lldb_private::SymbolContext &sc,
-      std::vector<lldb_private::ConstString> &imported_modules) override;
+      std::vector<ModulePath> &imported_modules,
+      std::vector<lldb_private::ConstString> &module_includes) override;
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
   size_t
   ParseVariablesForContext(const lldb_private::SymbolContext &sc) override;
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -669,10 +669,12 @@
 }
 
 bool SymbolFileDWARFDebugMap::ParseImportedModules(
-    const SymbolContext &sc, std::vector<ConstString> &imported_modules) {
+    const SymbolContext &sc, std::vector<ModulePath> &imported_modules,
+    std::vector<ConstString> &module_includes) {
   SymbolFileDWARF *oso_dwarf = GetSymbolFile(sc);
   if (oso_dwarf)
-    return oso_dwarf->ParseImportedModules(sc, imported_modules);
+    return oso_dwarf->ParseImportedModules(sc, imported_modules,
+                                           module_includes);
   return false;
 }
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -125,7 +125,8 @@
 
   bool ParseImportedModules(
       const lldb_private::SymbolContext &sc,
-      std::vector<lldb_private::ConstString> &imported_modules) override;
+      std::vector<ModulePath> &imported_modules,
+      std::vector<lldb_private::ConstString> &module_includes) override;
 
   size_t ParseBlocksRecursive(lldb_private::Function &func) override;
 
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -908,43 +908,65 @@
   return false;
 }
 
+/// Constructs the import module path (e.g. {"std", "iostream"}) from the given
+/// imported DW_TAG_MODULE DIE.
+static void BuildModulePath(DWARFDIE die, SymbolFile::ModulePath &path) {
+  if (die.Tag() != DW_TAG_module)
+    return;
+
+  const char *name = die.GetAttributeValueAsString(DW_AT_name, nullptr);
+  if (!name)
+    return;
+
+  DWARFDIE parent = die.GetParent();
+  // If we have a parent, recursively visit it before appending the current
+  // module name. Otherwise our module path would be in reverse
+  // (e.g. {"iostream", "std"} instead of {"std", "iostream"}).
+  if (parent.IsValid())
+    BuildModulePath(parent, path);
+  ConstString const_name(name);
+  path.push_back(const_name);
+}
+
 bool SymbolFileDWARF::ParseImportedModules(
     const lldb_private::SymbolContext &sc,
-    std::vector<lldb_private::ConstString> &imported_modules) {
+    std::vector<ModulePath> &imported_modules,
+    std::vector<lldb_private::ConstString> &module_includes) {
   ASSERT_MODULE_LOCK(this);
   assert(sc.comp_unit);
   DWARFUnit *dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
-  if (dwarf_cu) {
-    if (ClangModulesDeclVendor::LanguageSupportsClangModules(
-            sc.comp_unit->GetLanguage())) {
-      UpdateExternalModuleListIfNeeded();
+  if (!dwarf_cu)
+    return false;
+  if (!ClangModulesDeclVendor::LanguageSupportsClangModules(
+          sc.comp_unit->GetLanguage()))
+    return false;
+  UpdateExternalModuleListIfNeeded();
 
-      if (sc.comp_unit) {
-        const DWARFDIE die = dwarf_cu->DIE();
+  if (sc.comp_unit) {
+    const DWARFDIE die = dwarf_cu->DIE();
 
-        if (die) {
-          for (DWARFDIE child_die = die.GetFirstChild(); child_die;
-               child_die = child_die.GetSibling()) {
-            if (child_die.Tag() == DW_TAG_imported_declaration) {
-              if (DWARFDIE module_die =
-                      child_die.GetReferencedDIE(DW_AT_import)) {
-                if (module_die.Tag() == DW_TAG_module) {
-                  if (const char *name = module_die.GetAttributeValueAsString(
-                          DW_AT_name, nullptr)) {
-                    ConstString const_name(name);
-                    imported_modules.push_back(const_name);
-                  }
-                }
-              }
-            }
-          }
-        }
-      } else {
-        for (const auto &pair : m_external_type_modules) {
-          imported_modules.push_back(pair.first);
+    if (!die)
+      return false;
+    for (DWARFDIE child_die = die.GetFirstChild(); child_die;
+         child_die = child_die.GetSibling()) {
+      if (child_die.Tag() != DW_TAG_imported_declaration)
+        continue;
+      if (DWARFDIE module_die = child_die.GetReferencedDIE(DW_AT_import)) {
+        if (module_die.Tag() != DW_TAG_module)
+          continue;
+        ModulePath path;
+        BuildModulePath(module_die, path);
+        imported_modules.push_back(path);
+        if (const char *inc = module_die.GetAttributeValueAsString(
+                DW_AT_LLVM_include_path, nullptr)) {
+          ConstString const_inc(inc);
+          module_includes.push_back(const_inc);
         }
       }
     }
+  } else {
+    for (const auto &pair : m_external_type_modules)
+      imported_modules.push_back({pair.first});
   }
   return false;
 }
Index: lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
===================================================================
--- lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
+++ lldb/source/Plugins/SymbolFile/Breakpad/SymbolFileBreakpad.h
@@ -71,7 +71,8 @@
 
   bool
   ParseImportedModules(const SymbolContext &sc,
-                       std::vector<ConstString> &imported_modules) override {
+                       std::vector<ModulePath> &imported_modules,
+                       std::vector<ConstString> &module_includes) override {
     return false;
   }
 
Index: lldb/source/Plugins/Platform/Linux/PlatformLinux.h
===================================================================
--- lldb/source/Plugins/Platform/Linux/PlatformLinux.h
+++ lldb/source/Plugins/Platform/Linux/PlatformLinux.h
@@ -52,6 +52,9 @@
 
   bool CanDebugProcess() override;
 
+  void GetSystemIncludeDirectoriesForLanguage(
+      lldb::LanguageType lang, std::vector<std::string> &directories) override;
+
   lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
                                Debugger &debugger, Target *target,
                                Status &error) override;
Index: lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
===================================================================
--- lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
+++ lldb/source/Plugins/Platform/Linux/PlatformLinux.cpp
@@ -263,6 +263,25 @@
   }
 }
 
+void PlatformLinux::GetSystemIncludeDirectoriesForLanguage(
+    lldb::LanguageType lang, std::vector<std::string> &directories) {
+  switch (lang) {
+  case lldb::eLanguageTypeC:
+  case lldb::eLanguageTypeC89:
+  case lldb::eLanguageTypeC99:
+  case lldb::eLanguageTypeC11:
+  case lldb::eLanguageTypeC_plus_plus:
+  case lldb::eLanguageTypeC_plus_plus_03:
+  case lldb::eLanguageTypeC_plus_plus_11:
+  case lldb::eLanguageTypeC_plus_plus_14:
+  case lldb::eLanguageTypeObjC_plus_plus:
+    directories = {"/usr/include/"};
+    break;
+  default:
+    break;
+  }
+}
+
 // For local debugging, Linux will override the debug logic to use llgs-launch
 // rather than lldb-launch, llgs-attach.  This differs from current lldb-
 // launch, debugserver-attach approach on MacOSX.
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -167,6 +167,8 @@
   lldb::ExpressionVariableSP
   GetResultAfterDematerialization(ExecutionContextScope *exe_scope) override;
 
+  bool DidImportCxxModules() const { return m_imported_cpp_modules; }
+
 private:
   //------------------------------------------------------------------
   /// Populate m_in_cplusplus_method and m_in_objectivec_method based on the
@@ -180,8 +182,10 @@
                     lldb::addr_t struct_address,
                     DiagnosticManager &diagnostic_manager) override;
 
+  std::vector<std::string> GetModulesToImport(ExecutionContext &exe_ctx);
   void UpdateLanguageForExpr(DiagnosticManager &diagnostic_manager,
-                             ExecutionContext &exe_ctx);
+                             ExecutionContext &exe_ctx,
+                             std::vector<std::string> modules_to_import);
   bool SetupPersistentState(DiagnosticManager &diagnostic_manager,
                                    ExecutionContext &exe_ctx);
   bool PrepareForParsing(DiagnosticManager &diagnostic_manager,
@@ -206,6 +210,8 @@
 
   /// The language type of the current expression.
   lldb::LanguageType m_expr_lang = lldb::eLanguageTypeUnknown;
+  /// The include directories that should be used when parsing the expression.
+  std::vector<ConstString> m_include_directories;
 
   /// The absolute character position in the transformed source code where the
   /// user code (as typed by the user) starts. If the variable is empty, then we
@@ -216,6 +222,9 @@
   /// The object (if any) in which context the expression is evaluated.
   /// 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;
 };
 
 } // namespace lldb_private
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -36,6 +36,7 @@
 #include "lldb/Symbol/Block.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/CompileUnit.h"
 #include "lldb/Symbol/Function.h"
 #include "lldb/Symbol/ObjectFile.h"
 #include "lldb/Symbol/SymbolVendor.h"
@@ -398,7 +399,8 @@
 }
 
 void ClangUserExpression::UpdateLanguageForExpr(
-    DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+    DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx,
+    std::vector<std::string> modules_to_import) {
   m_expr_lang = lldb::LanguageType::eLanguageTypeUnknown;
 
   std::string prefix = m_expr_prefix;
@@ -418,8 +420,8 @@
       m_expr_lang = lldb::eLanguageTypeC;
 
     if (!source_code->GetText(m_transformed_text, m_expr_lang,
-                              m_in_static_method, exe_ctx,
-                              !m_ctx_obj)) {
+                              m_in_static_method, exe_ctx, !m_ctx_obj,
+                              modules_to_import)) {
       diagnostic_manager.PutString(eDiagnosticSeverityError,
                                    "couldn't construct expression body");
       return;
@@ -437,6 +439,54 @@
   }
 }
 
+static bool SupportsCxxModuleImport(lldb::LanguageType language) {
+  switch (language) {
+  case lldb::eLanguageTypeC_plus_plus:
+  case lldb::eLanguageTypeC_plus_plus_11:
+  case lldb::eLanguageTypeC_plus_plus_14:
+  case lldb::eLanguageTypeObjC_plus_plus:
+    return true;
+  default:
+    return false;
+  }
+}
+
+std::vector<std::string>
+ClangUserExpression::GetModulesToImport(ExecutionContext &exe_ctx) {
+  if (!SupportsCxxModuleImport(Language()))
+    return {};
+
+  Target *target = exe_ctx.GetTargetPtr();
+  if (!target || !target->GetEnableImportStdModule())
+    return {};
+
+  StackFrame *frame = exe_ctx.GetFramePtr();
+  if (!frame)
+    return {};
+
+  Block *block = frame->GetFrameBlock();
+  if (!block)
+    return {};
+
+  SymbolContext sc;
+  block->CalculateSymbolContext(&sc);
+  if (!sc.comp_unit)
+    return {};
+
+  m_include_directories = sc.comp_unit->GetModuleIncludes();
+  std::vector<CompileUnit::ModulePath> modules =
+      sc.comp_unit->GetImportedModules();
+
+  // Check if we imported 'std' or any of its submodules.
+  // We currently don't support importing any other modules in the expression
+  // parser.
+  for (CompileUnit::ModulePath path : modules)
+    if (!path.empty() && path.front() == ConstString("std"))
+      return {"std"};
+
+  return {};
+}
+
 bool ClangUserExpression::PrepareForParsing(
     DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
   InstallContext(exe_ctx);
@@ -459,7 +509,10 @@
 
   SetupDeclVendor(exe_ctx, m_target);
 
-  UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
+  std::vector<std::string> modules_to_include = GetModulesToImport(exe_ctx);
+  m_imported_cpp_modules = !modules_to_include.empty();
+
+  UpdateLanguageForExpr(diagnostic_manager, exe_ctx, modules_to_include);
   return true;
 }
 
@@ -518,7 +571,8 @@
   // 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);
+  ClangExpressionParser parser(exe_scope, *this, generate_debug_info,
+                               m_include_directories);
 
   unsigned num_errors = parser.Parse(diagnostic_manager);
 
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -287,7 +287,10 @@
   switch (language) {
   default:
     return false;
-  // C++ and friends to be added
+  case lldb::LanguageType::eLanguageTypeC_plus_plus:
+  case lldb::LanguageType::eLanguageTypeC_plus_plus_03:
+  case lldb::LanguageType::eLanguageTypeC_plus_plus_11:
+  case lldb::LanguageType::eLanguageTypeC_plus_plus_14:
   case lldb::LanguageType::eLanguageTypeC:
   case lldb::LanguageType::eLanguageTypeC11:
   case lldb::LanguageType::eLanguageTypeC89:
@@ -300,20 +303,19 @@
 bool ClangModulesDeclVendorImpl::AddModulesForCompileUnit(
     CompileUnit &cu, ClangModulesDeclVendor::ModuleVector &exported_modules,
     Stream &error_stream) {
-  if (LanguageSupportsClangModules(cu.GetLanguage())) {
-    std::vector<ConstString> imported_modules = cu.GetImportedModules();
+  if (!LanguageSupportsClangModules(cu.GetLanguage()))
+    return true;
 
-    for (ConstString imported_module : imported_modules) {
-      std::vector<ConstString> path;
+  auto imported_modules = cu.GetImportedModules();
 
-      path.push_back(imported_module);
+  for (CompileUnit::ModulePath imported_module : imported_modules) {
+    CompileUnit::ModulePath path;
 
-      if (!AddModule(path, &exported_modules, error_stream)) {
-        return false;
-      }
-    }
+    path.push_back(imported_module.back());
 
-    return true;
+    if (!AddModule(path, &exported_modules, error_stream)) {
+      return false;
+    }
   }
 
   return true;
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
@@ -52,9 +52,14 @@
   ///
   /// @param[in] expr
   ///     The expression to be parsed.
+  ///
+  /// @param[in] include_directories
+  ///     List of include directories that should be used when parsing the
+  ///     expression.
   //------------------------------------------------------------------
   ClangExpressionParser(ExecutionContextScope *exe_scope, Expression &expr,
-                        bool generate_debug_info);
+                        bool generate_debug_info,
+                        std::vector<ConstString> include_directories = {});
 
   //------------------------------------------------------------------
   /// Destructor
@@ -189,6 +194,8 @@
   LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
                                              ///encounters module imports
   std::unique_ptr<ClangASTContext> m_ast_context;
+
+  std::vector<ConstString> m_include_directories;
 };
 }
 
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -38,6 +38,7 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/Support/CrashRecoveryContext.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/TargetSelect.h"
@@ -57,10 +58,13 @@
 
 #include "ClangDiagnostic.h"
 #include "ClangExpressionParser.h"
+#include "ClangUserExpression.h"
 
+#include "ASTConsumerUtils.h"
 #include "ClangASTSource.h"
 #include "ClangExpressionDeclMap.h"
 #include "ClangExpressionHelper.h"
+#include "ClangHost.h"
 #include "ClangModulesDeclVendor.h"
 #include "ClangPersistentVariables.h"
 #include "IRForTarget.h"
@@ -213,15 +217,54 @@
   std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
 };
 
+static void
+SetupModuleHeaderPaths(CompilerInstance *compiler,
+                       std::vector<ConstString> include_directories) {
+  for (ConstString dir : include_directories) {
+    compiler->getHeaderSearchOpts().AddPath(
+        dir.AsCString(), clang::frontend::IncludeDirGroup::System, false, true);
+  }
+
+  {
+    llvm::SmallString<128> path;
+    auto props = ModuleList::GetGlobalModuleListProperties();
+    props.GetClangModulesCachePath().GetPath(path);
+    compiler->getHeaderSearchOpts().ModuleCachePath = path.str();
+  }
+
+  {
+    FileSpec clang_resource_dir = GetClangResourceDir();
+    std::string resource_dir = clang_resource_dir.GetPath();
+    if (FileSystem::Instance().IsDirectory(resource_dir)) {
+      compiler->getHeaderSearchOpts().ResourceDir = resource_dir;
+
+      compiler->getHeaderSearchOpts().AddPath(
+          resource_dir + "/include", clang::frontend::IncludeDirGroup::System,
+          false, true);
+    }
+  }
+
+  compiler->getHeaderSearchOpts().ImplicitModuleMaps = true;
+
+  std::vector<std::string> system_include_directories;
+  Platform::GetHostPlatform()->GetSystemIncludeDirectoriesForLanguage(
+      lldb::LanguageType::eLanguageTypeC_plus_plus, system_include_directories);
+
+  for (const std::string &include_dir : system_include_directories) {
+    compiler->getHeaderSearchOpts().AddPath(
+        include_dir, clang::frontend::IncludeDirGroup::System, false, true);
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // Implementation of ClangExpressionParser
 //===----------------------------------------------------------------------===//
 
-ClangExpressionParser::ClangExpressionParser(ExecutionContextScope *exe_scope,
-                                             Expression &expr,
-                                             bool generate_debug_info)
+ClangExpressionParser::ClangExpressionParser(
+    ExecutionContextScope *exe_scope, Expression &expr,
+    bool generate_debug_info, std::vector<ConstString> include_directories)
     : ExpressionParser(exe_scope, expr, generate_debug_info), m_compiler(),
-      m_pp_callbacks(nullptr) {
+      m_pp_callbacks(nullptr), m_include_directories(include_directories) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
 
   // We can't compile expressions without a target.  So if the exe_scope is
@@ -428,6 +471,23 @@
   // long time parsing and importing debug information.
   lang_opts.SpellChecking = false;
 
+  auto &clang_expr = *static_cast<ClangUserExpression *>(&m_expr);
+  if (clang_expr.DidImportCxxModules()) {
+    lang_opts.Modules = true;
+    lang_opts.ImplicitModules = true;
+    // To automatically import all submodules.
+    lang_opts.ModulesLocalVisibility = false;
+
+    // for @import statements.
+    lang_opts.ObjC = true;
+    lang_opts.GNUMode = true;
+    lang_opts.GNUKeywords = true;
+    lang_opts.DoubleSquareBracketAttributes = true;
+    lang_opts.CPlusPlus11 = true;
+
+    SetupModuleHeaderPaths(m_compiler.get(), m_include_directories);
+  }
+
   if (process_sp && lang_opts.ObjC) {
     if (process_sp->GetObjCLanguageRuntime()) {
       if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() ==
@@ -513,17 +573,6 @@
   m_compiler->createASTContext();
   clang::ASTContext &ast_context = m_compiler->getASTContext();
 
-  ClangExpressionHelper *type_system_helper =
-      dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
-  ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
-
-  if (decl_map) {
-    llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> ast_source(
-        decl_map->CreateProxy());
-    decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
-    ast_context.setExternalSource(ast_source);
-  }
-
   m_ast_context.reset(
       new ClangASTContext(m_compiler->getTargetOpts().Triple.c_str()));
   m_ast_context->setASTContext(&ast_context);
@@ -865,12 +914,6 @@
   ClangExpressionHelper *type_system_helper =
       dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
 
-  ASTConsumer *ast_transformer =
-      type_system_helper->ASTTransformer(m_code_generator.get());
-
-  if (ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap())
-    decl_map->InstallCodeGenerator(m_code_generator.get());
-
   // If we want to parse for code completion, we need to attach our code
   // completion consumer to the Sema and specify a completion position.
   // While parsing the Sema will call this consumer with the provided
@@ -885,17 +928,65 @@
     PP.SetCodeCompletionPoint(main_file, completion_line, completion_column);
   }
 
+  ASTConsumer *ast_transformer =
+      type_system_helper->ASTTransformer(m_code_generator.get());
+
+  std::unique_ptr<clang::ASTConsumer> Consumer;
   if (ast_transformer) {
-    ast_transformer->Initialize(m_compiler->getASTContext());
-    ParseAST(m_compiler->getPreprocessor(), ast_transformer,
-             m_compiler->getASTContext(), false, TU_Complete,
-             completion_consumer);
+    Consumer.reset(new ASTConsumerForwarder(ast_transformer));
+  } else if (m_code_generator) {
+    Consumer.reset(new ASTConsumerForwarder(m_code_generator.get()));
   } else {
-    m_code_generator->Initialize(m_compiler->getASTContext());
-    ParseAST(m_compiler->getPreprocessor(), m_code_generator.get(),
-             m_compiler->getASTContext(), false, TU_Complete,
-             completion_consumer);
+    Consumer.reset(new ASTConsumer());
+  }
+
+  clang::ASTContext &ast_context = m_compiler->getASTContext();
+
+  m_compiler->setSema(new Sema(m_compiler->getPreprocessor(), ast_context,
+                               *Consumer, TU_Complete, completion_consumer));
+  m_compiler->setASTConsumer(std::move(Consumer));
+
+  if (ast_context.getLangOpts().Modules)
+    m_compiler->createModuleManager();
+
+  ClangExpressionDeclMap *decl_map = type_system_helper->DeclMap();
+  if (decl_map) {
+    decl_map->InstallCodeGenerator(&m_compiler->getASTConsumer());
+
+    clang::ExternalASTSource *ast_source = decl_map->CreateProxy();
+
+    if (ast_context.getExternalSource()) {
+      auto module_wrapper =
+          new ExternalASTSourceWrapper(ast_context.getExternalSource());
+
+      auto ast_source_wrapper = new ExternalASTSourceWrapper(ast_source);
+
+      auto multiplexer =
+          new SemaSourceWithPriorities(*module_wrapper, *ast_source_wrapper);
+      IntrusiveRefCntPtr<ExternalASTSource> Source(multiplexer);
+      ast_context.setExternalSource(Source);
+    } else {
+      ast_context.setExternalSource(ast_source);
+    }
+    decl_map->InstallASTContext(ast_context, m_compiler->getFileManager());
+  }
+
+  // Check that the ASTReader is properly attached to ASTContext and Sema.
+  if (ast_context.getLangOpts().Modules) {
+    assert(m_compiler->getASTContext().getExternalSource() &&
+           "ASTContext doesn't know about the ASTReader?");
+    assert(m_compiler->getSema().getExternalSource() &&
+           "Sema doesn't know about the ASTReader?");
+  }
+
+  {
+    llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(
+        &m_compiler->getSema());
+    ParseAST(m_compiler->getSema(), false, false);
   }
+  // Destroy the Sema. This is necessary because we want to emulate the
+  // original behavior of ParseAST (which also destroys the Sema after parsing).
+  m_compiler->setSema(nullptr);
 
   diag_buf->EndSourceFile();
 
Index: lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
+++ lldb/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
@@ -3,6 +3,7 @@
 endif()
 
 add_lldb_library(lldbPluginExpressionParserClang PLUGIN
+  ASTConsumerUtils.cpp
   ASTDumper.cpp
   ASTResultSynthesizer.cpp
   ASTStructExtractor.cpp
Index: lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.h
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.h
@@ -0,0 +1,584 @@
+//===-- ASTConsumerUtils.h --------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ASTConsumerUtils_h_
+#define liblldb_ASTConsumerUtils_h_
+
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/MultiplexExternalSemaSource.h"
+#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaConsumer.h"
+
+namespace lldb_private {
+
+/// Wraps an ExternalASTSource into an ExternalSemaSource. Doesn't take
+/// ownership of the provided source.
+class ExternalASTSourceWrapper : public clang::ExternalSemaSource {
+  ExternalASTSource *m_Source;
+
+public:
+  ExternalASTSourceWrapper(ExternalASTSource *Source) : m_Source(Source) {
+    assert(m_Source && "Can't wrap nullptr ExternalASTSource");
+  }
+
+  ~ExternalASTSourceWrapper() override;
+
+  virtual clang::Decl *GetExternalDecl(uint32_t ID) override {
+    return m_Source->GetExternalDecl(ID);
+  }
+
+  virtual clang::Selector GetExternalSelector(uint32_t ID) override {
+    return m_Source->GetExternalSelector(ID);
+  }
+
+  virtual uint32_t GetNumExternalSelectors() override {
+    return m_Source->GetNumExternalSelectors();
+  }
+
+  virtual clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+    return m_Source->GetExternalDeclStmt(Offset);
+  }
+
+  virtual clang::CXXCtorInitializer **
+  GetExternalCXXCtorInitializers(uint64_t Offset) override {
+    return m_Source->GetExternalCXXCtorInitializers(Offset);
+  }
+
+  virtual clang::CXXBaseSpecifier *
+  GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+    return m_Source->GetExternalCXXBaseSpecifiers(Offset);
+  }
+
+  virtual void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override {
+    m_Source->updateOutOfDateIdentifier(II);
+  }
+
+  virtual bool
+  FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+                                 clang::DeclarationName Name) override {
+    return m_Source->FindExternalVisibleDeclsByName(DC, Name);
+  }
+
+  virtual void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+    m_Source->completeVisibleDeclsMap(DC);
+  }
+
+  virtual clang::Module *getModule(unsigned ID) override {
+    return m_Source->getModule(ID);
+  }
+
+  virtual llvm::Optional<ASTSourceDescriptor>
+  getSourceDescriptor(unsigned ID) override {
+    return m_Source->getSourceDescriptor(ID);
+  }
+
+  virtual ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+    return m_Source->hasExternalDefinitions(D);
+  }
+
+  virtual void FindExternalLexicalDecls(
+      const clang::DeclContext *DC,
+      llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+      llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+    m_Source->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+  }
+
+  virtual void
+  FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+                      llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+    m_Source->FindFileRegionDecls(File, Offset, Length, Decls);
+  }
+
+  virtual void CompleteRedeclChain(const clang::Decl *D) override {
+    m_Source->CompleteRedeclChain(D);
+  }
+
+  virtual void CompleteType(clang::TagDecl *Tag) override {
+    m_Source->CompleteType(Tag);
+  }
+
+  virtual void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+    m_Source->CompleteType(Class);
+  }
+
+  virtual void ReadComments() override { m_Source->ReadComments(); }
+
+  virtual void StartedDeserializing() override {
+    m_Source->StartedDeserializing();
+  }
+
+  virtual void FinishedDeserializing() override {
+    m_Source->FinishedDeserializing();
+  }
+
+  virtual void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+    m_Source->StartTranslationUnit(Consumer);
+  }
+
+  virtual void PrintStats() override;
+
+  virtual bool layoutRecordType(
+      const clang::RecordDecl *Record, uint64_t &Size, uint64_t &Alignment,
+      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &FieldOffsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &BaseOffsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &VirtualBaseOffsets) override {
+    return m_Source->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+                                      BaseOffsets, VirtualBaseOffsets);
+  }
+};
+
+/// Wraps an ASTConsumer into an SemaConsumer. Doesn't take ownership of the
+/// provided consumer. If the provided ASTConsumer is also a SemaConsumer,
+/// the wrapper will also forward SemaConsumer functions.
+class ASTConsumerForwarder : public clang::SemaConsumer {
+  clang::ASTConsumer *m_c;
+  clang::SemaConsumer *m_sc;
+
+public:
+  ASTConsumerForwarder(clang::ASTConsumer *c) : m_c(c) {
+    m_sc = llvm::dyn_cast<clang::SemaConsumer>(m_c);
+  }
+
+  ~ASTConsumerForwarder() override;
+
+  void Initialize(clang::ASTContext &Context) override {
+    m_c->Initialize(Context);
+  }
+
+  bool HandleTopLevelDecl(clang::DeclGroupRef D) override {
+    return m_c->HandleTopLevelDecl(D);
+  }
+
+  void HandleInlineFunctionDefinition(clang::FunctionDecl *D) override {
+    m_c->HandleInlineFunctionDefinition(D);
+  }
+
+  void HandleInterestingDecl(clang::DeclGroupRef D) override {
+    m_c->HandleInterestingDecl(D);
+  }
+
+  void HandleTranslationUnit(clang::ASTContext &Ctx) override {
+    m_c->HandleTranslationUnit(Ctx);
+  }
+
+  void HandleTagDeclDefinition(clang::TagDecl *D) override {
+    m_c->HandleTagDeclDefinition(D);
+  }
+
+  void HandleTagDeclRequiredDefinition(const clang::TagDecl *D) override {
+    m_c->HandleTagDeclRequiredDefinition(D);
+  }
+
+  void HandleCXXImplicitFunctionInstantiation(clang::FunctionDecl *D) override {
+    m_c->HandleCXXImplicitFunctionInstantiation(D);
+  }
+
+  void HandleTopLevelDeclInObjCContainer(clang::DeclGroupRef D) override {
+    m_c->HandleTopLevelDeclInObjCContainer(D);
+  }
+
+  void HandleImplicitImportDecl(clang::ImportDecl *D) override {
+    m_c->HandleImplicitImportDecl(D);
+  }
+
+  void CompleteTentativeDefinition(clang::VarDecl *D) override {
+    m_c->CompleteTentativeDefinition(D);
+  }
+
+  void AssignInheritanceModel(clang::CXXRecordDecl *RD) override {
+    m_c->AssignInheritanceModel(RD);
+  }
+
+  void HandleCXXStaticMemberVarInstantiation(clang::VarDecl *D) override {
+    m_c->HandleCXXStaticMemberVarInstantiation(D);
+  }
+
+  void HandleVTable(clang::CXXRecordDecl *RD) override {
+    m_c->HandleVTable(RD);
+  }
+
+  clang::ASTMutationListener *GetASTMutationListener() override {
+    return m_c->GetASTMutationListener();
+  }
+
+  clang::ASTDeserializationListener *GetASTDeserializationListener() override {
+    return m_c->GetASTDeserializationListener();
+  }
+
+  void PrintStats() override;
+
+  void InitializeSema(clang::Sema &S) override {
+    if (m_sc)
+      m_sc->InitializeSema(S);
+  }
+
+  /// Inform the semantic consumer that Sema is no longer available.
+  void ForgetSema() override {
+    if (m_sc)
+      m_sc->ForgetSema();
+  }
+
+  bool shouldSkipFunctionBody(clang::Decl *D) override {
+    return m_c->shouldSkipFunctionBody(D);
+  }
+};
+
+/// A ExternalSemaSource multiplexer that prioritizes its sources.
+///
+/// This ExternalSemaSource will forward all requests to its attached sources.
+/// However, unlike a normal multiplexer it will not forward a request to all
+/// sources, but instead give priority to certain sources. If a source with a
+/// higher priority can fulfill a request, all sources with a lower priority
+/// will not receive the request.
+///
+/// This class is mostly use to multiplex between sources of different
+/// 'quality', e.g. a C++ modules and debug information. The C++ module will
+/// provide more accurate replies to the requests, but might not be able to
+/// answer all requests. The debug information will be used as a fallback then
+/// to provide information that is not in the C++ module.
+class SemaSourceWithPriorities : public clang::ExternalSemaSource {
+
+private:
+  /// The sources ordered in decreasing priority.
+  llvm::SmallVector<clang::ExternalSemaSource *, 2> Sources;
+
+public:
+  /// Construct a SemaSourceWithPriorities with a 'high quality' source that
+  /// has the higher priority and a 'low quality' source that will be used
+  /// as a fallback.
+  SemaSourceWithPriorities(clang::ExternalSemaSource &high_quality_source,
+                           clang::ExternalSemaSource &low_quality_source) {
+    Sources.push_back(&high_quality_source);
+    Sources.push_back(&low_quality_source);
+  }
+
+  ~SemaSourceWithPriorities() override;
+
+  void addSource(clang::ExternalSemaSource &source) {
+    Sources.push_back(&source);
+  }
+
+  //===--------------------------------------------------------------------===//
+  // ExternalASTSource.
+  //===--------------------------------------------------------------------===//
+
+  clang::Decl *GetExternalDecl(uint32_t ID) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (clang::Decl *Result = Sources[i]->GetExternalDecl(ID))
+        return Result;
+    return nullptr;
+  }
+
+  void CompleteRedeclChain(const clang::Decl *D) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->CompleteRedeclChain(D);
+  }
+
+  clang::Selector GetExternalSelector(uint32_t ID) override {
+    clang::Selector Sel;
+    for (size_t i = 0; i < Sources.size(); ++i) {
+      Sel = Sources[i]->GetExternalSelector(ID);
+      if (!Sel.isNull())
+        return Sel;
+    }
+    return Sel;
+  }
+
+  uint32_t GetNumExternalSelectors() override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (uint32_t total = Sources[i]->GetNumExternalSelectors())
+        return total;
+    return 0;
+  }
+
+  clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (clang::Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset))
+        return Result;
+    return nullptr;
+  }
+
+  clang::CXXBaseSpecifier *
+  GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (clang::CXXBaseSpecifier *R =
+              Sources[i]->GetExternalCXXBaseSpecifiers(Offset))
+        return R;
+    return nullptr;
+  }
+
+  clang::CXXCtorInitializer **
+  GetExternalCXXCtorInitializers(uint64_t Offset) override {
+    for (auto *S : Sources)
+      if (auto *R = S->GetExternalCXXCtorInitializers(Offset))
+        return R;
+    return nullptr;
+  }
+
+  ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+    for (const auto &S : Sources)
+      if (auto EK = S->hasExternalDefinitions(D))
+        if (EK != EK_ReplyHazy)
+          return EK;
+    return EK_ReplyHazy;
+  }
+
+  bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+                                      clang::DeclarationName Name) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (Sources[i]->FindExternalVisibleDeclsByName(DC, Name))
+        return true;
+    return false;
+  }
+
+  void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+    // FIXME: Only one source should be able to complete the decls map.
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->completeVisibleDeclsMap(DC);
+  }
+
+  void FindExternalLexicalDecls(
+      const clang::DeclContext *DC,
+      llvm::function_ref<bool(clang::Decl::Kind)> IsKindWeWant,
+      llvm::SmallVectorImpl<clang::Decl *> &Result) override {
+    for (size_t i = 0; i < Sources.size(); ++i) {
+      Sources[i]->FindExternalLexicalDecls(DC, IsKindWeWant, Result);
+      if (!Result.empty())
+        return;
+    }
+  }
+
+  void
+  FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+                      llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls);
+  }
+
+  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;
+      }
+  }
+
+  void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->CompleteType(Class);
+  }
+
+  void ReadComments() override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadComments();
+  }
+
+  void StartedDeserializing() override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->StartedDeserializing();
+  }
+
+  void FinishedDeserializing() override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->FinishedDeserializing();
+  }
+
+  void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->StartTranslationUnit(Consumer);
+  }
+
+  void PrintStats() override;
+
+  clang::Module *getModule(unsigned ID) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (auto M = Sources[i]->getModule(ID))
+        return M;
+    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,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &BaseOffsets,
+      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
+          &VirtualBaseOffsets) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets,
+                                       BaseOffsets, VirtualBaseOffsets))
+        return true;
+    return false;
+  }
+
+  void getMemoryBufferSizes(MemoryBufferSizes &sizes) const override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->getMemoryBufferSizes(sizes);
+  }
+
+  //===--------------------------------------------------------------------===//
+  // ExternalSemaSource.
+  //===--------------------------------------------------------------------===//
+
+  void InitializeSema(clang::Sema &S) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->InitializeSema(S);
+  }
+
+  void ForgetSema() override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ForgetSema();
+  }
+
+  void ReadMethodPool(clang::Selector Sel) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadMethodPool(Sel);
+  }
+
+  void updateOutOfDateSelector(clang::Selector Sel) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->updateOutOfDateSelector(Sel);
+  }
+
+  void ReadKnownNamespaces(
+      llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadKnownNamespaces(Namespaces);
+  }
+
+  void ReadUndefinedButUsed(
+      llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined)
+      override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadUndefinedButUsed(Undefined);
+  }
+
+  void ReadMismatchingDeleteExpressions(
+      llvm::MapVector<clang::FieldDecl *,
+                      llvm::SmallVector<std::pair<clang::SourceLocation, bool>,
+                                        4>> &Exprs) override {
+    for (auto &Source : Sources)
+      Source->ReadMismatchingDeleteExpressions(Exprs);
+  }
+
+  bool LookupUnqualified(clang::LookupResult &R, clang::Scope *S) override {
+    for (size_t i = 0; i < Sources.size(); ++i) {
+      Sources[i]->LookupUnqualified(R, S);
+      if (!R.empty())
+        break;
+    }
+
+    return !R.empty();
+  }
+
+  void ReadTentativeDefinitions(
+      llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadTentativeDefinitions(Defs);
+  }
+
+  void ReadUnusedFileScopedDecls(
+      llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadUnusedFileScopedDecls(Decls);
+  }
+
+  void ReadDelegatingConstructors(
+      llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadDelegatingConstructors(Decls);
+  }
+
+  void ReadExtVectorDecls(
+      llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadExtVectorDecls(Decls);
+  }
+
+  void ReadUnusedLocalTypedefNameCandidates(
+      llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadUnusedLocalTypedefNameCandidates(Decls);
+  }
+
+  void ReadReferencedSelectors(
+      llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>>
+          &Sels) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadReferencedSelectors(Sels);
+  }
+
+  void ReadWeakUndeclaredIdentifiers(
+      llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>>
+          &WI) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadWeakUndeclaredIdentifiers(WI);
+  }
+
+  void ReadUsedVTables(
+      llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadUsedVTables(VTables);
+  }
+
+  void ReadPendingInstantiations(
+      llvm::SmallVectorImpl<
+          std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending)
+      override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadPendingInstantiations(Pending);
+  }
+
+  void ReadLateParsedTemplates(
+      llvm::MapVector<const clang::FunctionDecl *,
+                      std::unique_ptr<clang::LateParsedTemplate>> &LPTMap)
+      override {
+    for (size_t i = 0; i < Sources.size(); ++i)
+      Sources[i]->ReadLateParsedTemplates(LPTMap);
+  }
+
+  clang::TypoCorrection
+  CorrectTypo(const clang::DeclarationNameInfo &Typo, int LookupKind,
+              clang::Scope *S, clang::CXXScopeSpec *SS,
+              clang::CorrectionCandidateCallback &CCC,
+              clang::DeclContext *MemberContext, bool EnteringContext,
+              const clang::ObjCObjectPointerType *OPT) override {
+    for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+      if (clang::TypoCorrection C =
+              Sources[I]->CorrectTypo(Typo, LookupKind, S, SS, CCC,
+                                      MemberContext, EnteringContext, OPT))
+        return C;
+    }
+    return clang::TypoCorrection();
+  }
+
+  bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+                                        clang::QualType T) override {
+    for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+      if (Sources[I]->MaybeDiagnoseMissingCompleteType(Loc, T))
+        return true;
+    }
+    return false;
+  }
+};
+
+} // namespace lldb_private
+#endif // liblldb_ASTConsumerUtils_h_
Index: lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/ExpressionParser/Clang/ASTConsumerUtils.cpp
@@ -0,0 +1,26 @@
+//===-- ASTConsumerUtils.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ASTConsumerUtils.h"
+
+lldb_private::ExternalASTSourceWrapper::~ExternalASTSourceWrapper() {}
+
+void lldb_private::ExternalASTSourceWrapper::PrintStats() {
+  m_Source->PrintStats();
+}
+
+lldb_private::ASTConsumerForwarder::~ASTConsumerForwarder() {}
+
+void lldb_private::ASTConsumerForwarder::PrintStats() { m_c->PrintStats(); }
+
+lldb_private::SemaSourceWithPriorities::~SemaSourceWithPriorities() {}
+
+void lldb_private::SemaSourceWithPriorities::PrintStats() {
+  for (size_t i = 0; i < Sources.size(); ++i)
+    Sources[i]->PrintStats();
+}
Index: lldb/source/Expression/ExpressionSourceCode.cpp
===================================================================
--- lldb/source/Expression/ExpressionSourceCode.cpp
+++ lldb/source/Expression/ExpressionSourceCode.cpp
@@ -178,8 +178,8 @@
 bool ExpressionSourceCode::GetText(std::string &text,
                                    lldb::LanguageType wrapping_language,
                                    bool static_method,
-                                   ExecutionContext &exe_ctx,
-                                   bool add_locals) const {
+                                   ExecutionContext &exe_ctx, bool add_locals,
+                                   std::vector<std::string> modules) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
 
@@ -273,6 +273,15 @@
       break;
     }
 
+    // Generate a list of @import statements that will import the specified
+    // module into our expression.
+    std::string module_imports;
+    for (std::string module : modules) {
+      module_imports.append("@import ");
+      module_imports.append(module);
+      module_imports.append(";\n");
+    }
+
     StreamString wrap_stream;
 
     wrap_stream.Printf("%s\n%s\n%s\n%s\n%s\n", module_macros.c_str(),
@@ -298,28 +307,31 @@
     default:
       break;
     case lldb::eLanguageTypeC:
-      wrap_stream.Printf("void                           \n"
+      wrap_stream.Printf("%s"
+                         "void                           \n"
                          "%s(void *$__lldb_arg)          \n"
                          "{                              \n"
                          "    %s;                        \n"
                          "%s"
                          "}                              \n",
-                         m_name.c_str(), lldb_local_var_decls.GetData(),
-                         tagged_body.c_str());
+                         module_imports.c_str(), m_name.c_str(),
+                         lldb_local_var_decls.GetData(), tagged_body.c_str());
       break;
     case lldb::eLanguageTypeC_plus_plus:
-      wrap_stream.Printf("void                                   \n"
+      wrap_stream.Printf("%s"
+                         "void                                   \n"
                          "$__lldb_class::%s(void *$__lldb_arg)   \n"
                          "{                                      \n"
                          "    %s;                                \n"
                          "%s"
                          "}                                      \n",
-                         m_name.c_str(), lldb_local_var_decls.GetData(),
-                         tagged_body.c_str());
+                         module_imports.c_str(), m_name.c_str(),
+                         lldb_local_var_decls.GetData(), tagged_body.c_str());
       break;
     case lldb::eLanguageTypeObjC:
       if (static_method) {
         wrap_stream.Printf(
+            "%s"
             "@interface $__lldb_objc_class ($__lldb_category)        \n"
             "+(void)%s:(void *)$__lldb_arg;                          \n"
             "@end                                                    \n"
@@ -329,9 +341,11 @@
             "%s"
             "}                                                       \n"
             "@end                                                    \n",
-            m_name.c_str(), m_name.c_str(), tagged_body.c_str());
+            module_imports.c_str(), m_name.c_str(), m_name.c_str(),
+            tagged_body.c_str());
       } else {
         wrap_stream.Printf(
+            "%s"
             "@interface $__lldb_objc_class ($__lldb_category)       \n"
             "-(void)%s:(void *)$__lldb_arg;                         \n"
             "@end                                                   \n"
@@ -341,7 +355,8 @@
             "%s"
             "}                                                      \n"
             "@end                                                   \n",
-            m_name.c_str(), m_name.c_str(), tagged_body.c_str());
+            module_imports.c_str(), m_name.c_str(), m_name.c_str(),
+            tagged_body.c_str());
       }
       break;
     }
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
@@ -0,0 +1,5 @@
+// We don't import any std module here.
+
+int main(int argc, char **argv) {
+  return 0; // Set break point at this line.
+}
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestImportStdModule.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestImportStdModule.py
@@ -0,0 +1,51 @@
+"""
+Test that importing the std module on a compile unit
+that doesn't use the std module will not break LLDB.
+
+It's not really specified at the moment what kind of
+error we should report back to the user in this
+situation. Currently Clang will just complain that
+the std module doesn't exist or can't be loaded.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class STLTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        TestBase.setUp(self)
+        self.source = 'main.cpp'
+        self.line = line_number(
+            self.source, '// Set break point at this line.')
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build(dictionary=self.getBuildFlags())
+        exe = self.getBuildArtifact("a.out")
+
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # Activate importing of std module.
+        self.runCmd("settings set target.import-std-module true")
+
+        # Run some commands that should all fail without our std module.
+        self.expect("expr std::abs(-42)", error=True)
+        self.expect("expr std::div(2, 1).quot", error=True)
+        self.expect("expr (std::size_t)33U", error=True)
+        self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+                    error=True)
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += -std=c++11 -fmodules -glldb -fimplicit-module-maps
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
@@ -0,0 +1,10 @@
+#include <cstdlib>
+#include <utility>
+
+int main(int argc, char **argv) {
+  std::size_t f = argc;
+  f = std::abs(argc);
+  f = std::div(argc * 2, argc).quot;
+  std::swap(f, f);
+  return f; // Set break point at this line.
+}
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestImportStdModule.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestImportStdModule.py
@@ -0,0 +1,47 @@
+"""
+Test importing the 'std' C++ module and check if we can handle
+prioritizing the conflicting functions from debug info and std
+module.
+
+See also import-std-module/basic/TestImportStdModule.py for
+the same test on a 'clean' code base without conflicts.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class TestImportStdModuleConflicts(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        TestBase.setUp(self)
+        self.source = 'main.cpp'
+        self.line = line_number(
+            self.source, '// Set break point at this line.')
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build(dictionary=self.getBuildFlags())
+        exe = self.getBuildArtifact("a.out")
+
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        self.runCmd("settings set target.import-std-module true")
+        self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42'])
+        self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2'])
+        self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33'])
+        self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+                    substrs=["(char) $3 = 'a'"])
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += -std=c++11 -fmodules -glldb -fimplicit-module-maps
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
@@ -0,0 +1,6 @@
+#include <iostream>
+
+int main(int argc, char **argv) {
+  std::cout << "Test" << std::endl;
+  return 0; // Set break point at this line.
+}
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
@@ -0,0 +1,72 @@
+"""
+Test importing the 'std' C++ module and evaluate expressions with it.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class ImportStdModule(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def setUp(self):
+        TestBase.setUp(self)
+        self.source = 'main.cpp'
+        self.line = line_number(
+            self.source, '// Set break point at this line.')
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build(dictionary=self.getBuildFlags())
+        exe = self.getBuildArtifact("a.out")
+
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # Activate importing of std module.
+        self.runCmd("settings set target.import-std-module true")
+        # Calling some normal std functions that return non-template types.
+        self.expect("expr std::abs(-42)", substrs=['(int) $0 = 42'])
+        self.expect("expr std::div(2, 1).quot", substrs=['(int) $1 = 2'])
+        # Using types from std.
+        self.expect("expr (std::size_t)33U", substrs=['(size_t) $2 = 33'])
+        # Calling templated functions that return non-template types.
+        self.expect("expr char a = 'b'; char b = 'a'; std::swap(a, b); a",
+                    substrs=["(char) $3 = 'a'"])
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test_non_cpp_language(self):
+        self.build(dictionary=self.getBuildFlags())
+        exe = self.getBuildArtifact("a.out")
+
+        self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line(
+            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
+
+        self.runCmd("run", RUN_SUCCEEDED)
+
+        # Activate importing of std module.
+        self.runCmd("settings set target.import-std-module true")
+        # These languages don't support C++ modules, so they shouldn't
+        # be able to evaluate the expression.
+        self.expect("expr -l C -- std::abs(-42)", error=True)
+        self.expect("expr -l C99 -- std::abs(-42)", error=True)
+        self.expect("expr -l C11 -- std::abs(-42)", error=True)
+        self.expect("expr -l ObjC -- std::abs(-42)", error=True)
Index: lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
===================================================================
--- /dev/null
+++ lldb/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += -std=c++11 -fmodules -glldb -fimplicit-module-maps
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules
Index: lldb/include/lldb/Target/Target.h
===================================================================
--- lldb/include/lldb/Target/Target.h
+++ lldb/include/lldb/Target/Target.h
@@ -129,6 +129,8 @@
 
   bool GetEnableAutoImportClangModules() const;
 
+  bool GetEnableImportStdModule() const;
+
   bool GetEnableAutoApplyFixIts() const;
 
   bool GetEnableNotifyAboutFixIts() const;
Index: lldb/include/lldb/Target/Platform.h
===================================================================
--- lldb/include/lldb/Target/Platform.h
+++ lldb/include/lldb/Target/Platform.h
@@ -276,6 +276,19 @@
 
   virtual bool SetRemoteWorkingDirectory(const FileSpec &working_dir);
 
+  //------------------------------------------------------------------
+  /// Retrieve the system include directories on this platform for the
+  /// given language.
+  ///
+  /// @param[in] lang
+  ///     The language for which the include directories should be queried.
+  ///
+  /// @param[out] directories
+  ///     The include directories for this system.
+  //------------------------------------------------------------------
+  virtual void GetSystemIncludeDirectoriesForLanguage(
+      lldb::LanguageType lang, std::vector<std::string> &directories) {}
+
   virtual const char *GetUserName(uint32_t uid);
 
   virtual const char *GetGroupName(uint32_t gid);
Index: lldb/include/lldb/Symbol/SymbolVendor.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolVendor.h
+++ lldb/include/lldb/Symbol/SymbolVendor.h
@@ -60,8 +60,10 @@
 
   virtual size_t ParseTypes(CompileUnit &comp_unit);
 
+  typedef std::vector<lldb_private::ConstString> ModulePath;
   virtual bool ParseImportedModules(const SymbolContext &sc,
-                                    std::vector<ConstString> &imported_modules);
+                                    std::vector<ModulePath> &imported_modules,
+                                    std::vector<ConstString> &module_includes);
 
   virtual size_t ParseBlocksRecursive(Function &func);
 
Index: lldb/include/lldb/Symbol/SymbolFile.h
===================================================================
--- lldb/include/lldb/Symbol/SymbolFile.h
+++ lldb/include/lldb/Symbol/SymbolFile.h
@@ -133,9 +133,11 @@
   virtual size_t ParseTypes(CompileUnit &comp_unit) = 0;
   virtual bool ParseIsOptimized(CompileUnit &comp_unit) { return false; }
 
+  typedef std::vector<lldb_private::ConstString> ModulePath;
   virtual bool
   ParseImportedModules(const SymbolContext &sc,
-                       std::vector<ConstString> &imported_modules) = 0;
+                       std::vector<ModulePath> &imported_modules,
+                       std::vector<ConstString> &module_includes) = 0;
   virtual size_t ParseBlocksRecursive(Function &func) = 0;
   virtual size_t ParseVariablesForContext(const SymbolContext &sc) = 0;
   virtual Type *ResolveTypeUID(lldb::user_id_t type_uid) = 0;
Index: lldb/include/lldb/Symbol/CompileUnit.h
===================================================================
--- lldb/include/lldb/Symbol/CompileUnit.h
+++ lldb/include/lldb/Symbol/CompileUnit.h
@@ -257,6 +257,7 @@
   //------------------------------------------------------------------
   FileSpecList &GetSupportFiles();
 
+  typedef std::vector<lldb_private::ConstString> ModulePath;
   //------------------------------------------------------------------
   /// Get the compile unit's imported module list.
   ///
@@ -266,7 +267,18 @@
   /// @return
   ///     A list of imported module names.
   //------------------------------------------------------------------
-  const std::vector<ConstString> &GetImportedModules();
+  const std::vector<ModulePath> &GetImportedModules();
+
+  //------------------------------------------------------------------
+  /// Get the compile unit's imported module list.
+  ///
+  /// This reports all the imports that the compile unit made, including the
+  /// current module.
+  ///
+  /// @return
+  ///     A list of imported module names.
+  //------------------------------------------------------------------
+  const std::vector<ConstString> &GetModuleIncludes();
 
   //------------------------------------------------------------------
   /// Get the SymbolFile plug-in user data.
@@ -422,10 +434,14 @@
 
   /// Maps UIDs to functions.
   llvm::DenseMap<lldb::user_id_t, lldb::FunctionSP> m_functions_by_uid;
-  std::vector<ConstString> m_imported_modules; ///< All modules, including the
-                                               ///current module, imported by
-                                               ///this
-                                               ///< compile unit.
+
+  std::vector<ModulePath> m_imported_modules; ///< All modules, including the
+                                              /// current module, imported by
+                                              /// this
+                                              ///< compile unit.
+  /// The include directories of the imported modules.
+  std::vector<ConstString> m_module_includes;
+
   FileSpecList m_support_files; ///< Files associated with this compile unit's
                                 ///line table and declarations.
   std::unique_ptr<LineTable>
@@ -454,6 +470,8 @@
         (1u << 6) ///< Have we parsed the debug macros already?
   };
 
+  void UpdateModules();
+
   DISALLOW_COPY_AND_ASSIGN(CompileUnit);
 };
 
Index: lldb/include/lldb/Expression/ExpressionSourceCode.h
===================================================================
--- lldb/include/lldb/Expression/ExpressionSourceCode.h
+++ lldb/include/lldb/Expression/ExpressionSourceCode.h
@@ -12,6 +12,7 @@
 #include "lldb/lldb-enumerations.h"
 
 #include <string>
+#include <vector>
 
 namespace lldb_private {
 
@@ -35,9 +36,23 @@
 
   const char *GetName() const { return m_name.c_str(); }
 
+  /// Generates the source code that will evaluate the expression.
+  ///
+  /// \param text output parameter containing the source code string.
+  /// \param wrapping_language If the expression is supossed to be wrapped,
+  ///        then this is the language that should be used for that.
+  /// \param static_method True iff the expression is valuated inside a static
+  ///        Objective-C method.
+  /// \param exe_ctx The execution context in which the expression will be
+  ///        evaluated.
+  /// \param add_locals True iff local variables should be injected into the
+  ///        expression source code.
+  /// \param modules A list of (C++) modules that the expression should import.
+  ///
+  /// \return true iff the source code was successfully generated.
   bool GetText(std::string &text, lldb::LanguageType wrapping_language,
-               bool static_method, ExecutionContext &exe_ctx,
-               bool add_locals) const;
+               bool static_method, ExecutionContext &exe_ctx, bool add_locals,
+               std::vector<std::string> modules) const;
 
   // Given a string returned by GetText, find the beginning and end of the body
   // passed to CreateWrapped. Return true if the bounds could be found.  This
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to