[Lldb-commits] [lldb] r355939 - Add ability to import std module into expression parser to improve C++ debugging

Raphael Isemann via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 12 10:09:33 PDT 2019


Author: teemperor
Date: Tue Mar 12 10:09:33 2019
New Revision: 355939

URL: http://llvm.org/viewvc/llvm-project?rev=355939&view=rev
Log:
Add ability to import std module into expression parser to improve C++ debugging

Summary:
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.

Reviewers: aprantl, jingham, shafik, friss, davide, serge-sans-paille

Reviewed By: aprantl

Subscribers: labath, mgorny, abidh, jdoerfert, lldb-commits

Tags: #c_modules_in_lldb, #lldb

Differential Revision: https://reviews.llvm.org/D58125

Added:
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap
    lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.h
Modified:
    lldb/trunk/include/lldb/Expression/ExpressionSourceCode.h
    lldb/trunk/include/lldb/Target/Platform.h
    lldb/trunk/include/lldb/Target/Target.h
    lldb/trunk/packages/Python/lldbsuite/test/make/Makefile.rules
    lldb/trunk/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
    lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
    lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
    lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
    lldb/trunk/source/Target/Target.cpp

Modified: lldb/trunk/include/lldb/Expression/ExpressionSourceCode.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Expression/ExpressionSourceCode.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Expression/ExpressionSourceCode.h (original)
+++ lldb/trunk/include/lldb/Expression/ExpressionSourceCode.h Tue Mar 12 10:09:33 2019
@@ -10,6 +10,7 @@
 #define liblldb_ExpressionSourceCode_h
 
 #include "lldb/lldb-enumerations.h"
+#include "llvm/ADT/ArrayRef.h"
 
 #include <string>
 

Modified: lldb/trunk/include/lldb/Target/Platform.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Platform.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Platform.h (original)
+++ lldb/trunk/include/lldb/Target/Platform.h Tue Mar 12 10:09:33 2019
@@ -281,6 +281,21 @@ public:
 
   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 std::vector<std::string>
+  GetSystemIncludeDirectories(lldb::LanguageType lang) {
+    return {};
+  }
+
   virtual UserIDResolver &GetUserIDResolver() = 0;
 
   //------------------------------------------------------------------

Modified: lldb/trunk/include/lldb/Target/Target.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Target/Target.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Target/Target.h (original)
+++ lldb/trunk/include/lldb/Target/Target.h Tue Mar 12 10:09:33 2019
@@ -129,6 +129,8 @@ public:
 
   bool GetEnableAutoImportClangModules() const;
 
+  bool GetEnableImportStdModule() const;
+
   bool GetEnableAutoApplyFixIts() const;
 
   bool GetEnableNotifyAboutFixIts() const;

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/Makefile Tue Mar 12 10:09:33 2019
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/TestImportStdModule.py Tue Mar 12 10:09:33 2019
@@ -0,0 +1,56 @@
+"""
+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__)
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(self,
+            "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+        # 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()
+
+        lldbutil.run_to_source_breakpoint(self,
+            "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+        # 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)

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/basic/main.cpp Tue Mar 12 10:09:33 2019
@@ -0,0 +1,7 @@
+// We need to import any std module. It doesn't matter which one.
+#include <iostream>
+
+int main(int argc, char **argv) {
+  std::cout << "Test" << std::endl;
+  return 0; // Set break point at this line.
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/Makefile Tue Mar 12 10:09:33 2019
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/TestStdModuleWithConflicts.py Tue Mar 12 10:09:33 2019
@@ -0,0 +1,36 @@
+"""
+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__)
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(self,
+            "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+        self.runCmd("settings set target.import-std-module true")
+        self.expect("expr 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'"])

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/conflicts/main.cpp Tue Mar 12 10:09:33 2019
@@ -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.
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/Makefile Tue Mar 12 10:09:33 2019
@@ -0,0 +1,5 @@
+LEVEL = ../../../make
+USE_LIBCPP := 1
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/TestMissingStdModule.py Tue Mar 12 10:09:33 2019
@@ -0,0 +1,40 @@
+"""
+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__)
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @add_test_categories(["libc++"])
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build()
+
+        lldbutil.run_to_source_breakpoint(self,
+            "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+        # 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)

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/no-std-module/main.cpp Tue Mar 12 10:09:33 2019
@@ -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.
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/Makefile Tue Mar 12 10:09:33 2019
@@ -0,0 +1,10 @@
+LEVEL = ../../../make
+# We don't have any standard include directories, so we can't
+# parse the test_common.h header we usually inject as it includes
+# system headers.
+NO_TEST_COMMON_H := 1
+
+CXXFLAGS += $(MANDATORY_CXXMODULE_BUILD_CFLAGS)
+CXXFLAGS += -I $(SRCDIR)/root/usr/include/c++/include/ -I $(SRCDIR)/root/usr/include/ -nostdinc -nostdinc++ -nostdlib++
+CXX_SOURCES := main.cpp
+include $(LEVEL)/Makefile.rules

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/TestStdModuleSysroot.py Tue Mar 12 10:09:33 2019
@@ -0,0 +1,34 @@
+"""
+Test that we respect the sysroot when building the std module.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import os
+
+class ImportStdModule(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    # FIXME: This should work on more setups, so remove these
+    # skipIf's in the future.
+    @skipIf(compiler=no_match("clang"))
+    @skipIf(oslist=no_match(["linux"]))
+    @skipIf(debug_info=no_match(["dwarf"]))
+    def test(self):
+        self.build()
+
+        sysroot = os.path.join(os.getcwd(), "root")
+
+        # Set the sysroot.
+        self.runCmd("platform select --sysroot '" + sysroot + "' host", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_to_source_breakpoint(self,
+            "// Set break point at this line.", lldb.SBFileSpec("main.cpp"))
+
+        self.runCmd("settings set target.import-std-module true")
+
+        # Call our custom function in our sysroot std module.
+        # If this gives us the correct result, then we used the sysroot.
+        self.expect("expr std::myabs(-42)", substrs=['(int) $0 = 42'])

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/main.cpp Tue Mar 12 10:09:33 2019
@@ -0,0 +1,6 @@
+#include <algorithm>
+
+int main(int argc, char **argv) {
+  libc_struct s;
+  return 0; // Set break point at this line.
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c%2B%2B/include/algorithm?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/algorithm Tue Mar 12 10:09:33 2019
@@ -0,0 +1,7 @@
+#include "libc_header.h"
+
+namespace std {
+  int myabs(int i) {
+    return i < 0 ? -i : i;
+  }
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c%2B%2B/include/module.modulemap?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/c++/include/module.modulemap Tue Mar 12 10:09:33 2019
@@ -0,0 +1,3 @@
+module std {
+  module "algorithm" { header "algorithm" export * }
+}

Added: lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h?rev=355939&view=auto
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h (added)
+++ lldb/trunk/packages/Python/lldbsuite/test/expression_command/import-std-module/sysroot/root/usr/include/libc_header.h Tue Mar 12 10:09:33 2019
@@ -0,0 +1 @@
+struct libc_struct {};

Modified: lldb/trunk/packages/Python/lldbsuite/test/make/Makefile.rules
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/make/Makefile.rules?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/make/Makefile.rules (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/make/Makefile.rules Tue Mar 12 10:09:33 2019
@@ -272,7 +272,12 @@ else
 	CFLAGS += $(ARCHFLAG)$(ARCH) $(FRAMEWORK_INCLUDES) -I$(LLDB_BASE_DIR)include
 endif
 
-CFLAGS += -I$(SRCDIR) -include $(THIS_FILE_DIR)test_common.h -I$(THIS_FILE_DIR)
+CFLAGS += -I$(SRCDIR) -I$(THIS_FILE_DIR)
+
+ifndef NO_TEST_COMMON_H
+  CFLAGS += -include $(THIS_FILE_DIR)test_common.h
+endif
+
 CFLAGS += $(NO_LIMIT_DEBUG_INFO_FLAGS) $(ARCH_CFLAGS) $(CFLAGS_EXTRAS)
 
 # If the OS is Windows, we need to pass -gdwarf to clang, otherwise it will build
@@ -300,7 +305,11 @@ CLANG_MODULE_CACHE_DIR := $(BUILDDIR)/mo
 $(warning failed to set the shared clang module cache dir)
 endif
 
-MANDATORY_MODULE_BUILD_CFLAGS := -fmodules -gmodules -fmodules-cache-path=$(CLANG_MODULE_CACHE_DIR)
+MODULE_BASE_FLAGS := -fmodules -gmodules -fmodules-cache-path=$(CLANG_MODULE_CACHE_DIR)
+MANDATORY_MODULE_BUILD_CFLAGS := $(MODULE_BASE_FLAGS) -gmodules
+# Build flags for building with C++ modules.
+# -glldb is necessary for emitting information about what modules were imported.
+MANDATORY_CXXMODULE_BUILD_CFLAGS := $(MODULE_BASE_FLAGS) -fcxx-modules -glldb
 
 ifeq "$(OS)" "Darwin"
 	MANDATORY_MODULE_BUILD_CFLAGS += -fcxx-modules

Added: lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp?rev=355939&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp (added)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.cpp Tue Mar 12 10:09:33 2019
@@ -0,0 +1,26 @@
+//===-- ASTUtils.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 "ASTUtils.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();
+}

Added: lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.h?rev=355939&view=auto
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.h (added)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ASTUtils.h Tue Mar 12 10:09:33 2019
@@ -0,0 +1,579 @@
+//===-- ASTUtils.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_ASTUtils_h_
+#define liblldb_ASTUtils_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;
+
+  clang::Decl *GetExternalDecl(uint32_t ID) override {
+    return m_Source->GetExternalDecl(ID);
+  }
+
+  clang::Selector GetExternalSelector(uint32_t ID) override {
+    return m_Source->GetExternalSelector(ID);
+  }
+
+  uint32_t GetNumExternalSelectors() override {
+    return m_Source->GetNumExternalSelectors();
+  }
+
+  clang::Stmt *GetExternalDeclStmt(uint64_t Offset) override {
+    return m_Source->GetExternalDeclStmt(Offset);
+  }
+
+  clang::CXXCtorInitializer **
+  GetExternalCXXCtorInitializers(uint64_t Offset) override {
+    return m_Source->GetExternalCXXCtorInitializers(Offset);
+  }
+
+  clang::CXXBaseSpecifier *
+  GetExternalCXXBaseSpecifiers(uint64_t Offset) override {
+    return m_Source->GetExternalCXXBaseSpecifiers(Offset);
+  }
+
+  void updateOutOfDateIdentifier(clang::IdentifierInfo &II) override {
+    m_Source->updateOutOfDateIdentifier(II);
+  }
+
+  bool FindExternalVisibleDeclsByName(const clang::DeclContext *DC,
+                                      clang::DeclarationName Name) override {
+    return m_Source->FindExternalVisibleDeclsByName(DC, Name);
+  }
+
+  void completeVisibleDeclsMap(const clang::DeclContext *DC) override {
+    m_Source->completeVisibleDeclsMap(DC);
+  }
+
+  clang::Module *getModule(unsigned ID) override {
+    return m_Source->getModule(ID);
+  }
+
+  llvm::Optional<ASTSourceDescriptor>
+  getSourceDescriptor(unsigned ID) override {
+    return m_Source->getSourceDescriptor(ID);
+  }
+
+  ExtKind hasExternalDefinitions(const clang::Decl *D) override {
+    return m_Source->hasExternalDefinitions(D);
+  }
+
+  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);
+  }
+
+  void
+  FindFileRegionDecls(clang::FileID File, unsigned Offset, unsigned Length,
+                      llvm::SmallVectorImpl<clang::Decl *> &Decls) override {
+    m_Source->FindFileRegionDecls(File, Offset, Length, Decls);
+  }
+
+  void CompleteRedeclChain(const clang::Decl *D) override {
+    m_Source->CompleteRedeclChain(D);
+  }
+
+  void CompleteType(clang::TagDecl *Tag) override {
+    m_Source->CompleteType(Tag);
+  }
+
+  void CompleteType(clang::ObjCInterfaceDecl *Class) override {
+    m_Source->CompleteType(Class);
+  }
+
+  void ReadComments() override { m_Source->ReadComments(); }
+
+  void StartedDeserializing() override { m_Source->StartedDeserializing(); }
+
+  void FinishedDeserializing() override { m_Source->FinishedDeserializing(); }
+
+  void StartTranslationUnit(clang::ASTConsumer *Consumer) override {
+    m_Source->StartTranslationUnit(Consumer);
+  }
+
+  void PrintStats() override;
+
+  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 (auto &Source : Sources)
+      Source->getMemoryBufferSizes(sizes);
+  }
+
+  //===--------------------------------------------------------------------===//
+  // ExternalSemaSource.
+  //===--------------------------------------------------------------------===//
+
+  void InitializeSema(clang::Sema &S) override {
+    for (auto &Source : Sources)
+      Source->InitializeSema(S);
+  }
+
+  void ForgetSema() override {
+    for (auto &Source : Sources)
+      Source->ForgetSema();
+  }
+
+  void ReadMethodPool(clang::Selector Sel) override {
+    for (auto &Source : Sources)
+      Source->ReadMethodPool(Sel);
+  }
+
+  void updateOutOfDateSelector(clang::Selector Sel) override {
+    for (auto &Source : Sources)
+      Source->updateOutOfDateSelector(Sel);
+  }
+
+  void ReadKnownNamespaces(
+      llvm::SmallVectorImpl<clang::NamespaceDecl *> &Namespaces) override {
+    for (auto &Source : Sources)
+      Source->ReadKnownNamespaces(Namespaces);
+  }
+
+  void ReadUndefinedButUsed(
+      llvm::MapVector<clang::NamedDecl *, clang::SourceLocation> &Undefined)
+      override {
+    for (auto &Source : Sources)
+      Source->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 (auto &Source : Sources) {
+      Source->LookupUnqualified(R, S);
+      if (!R.empty())
+        break;
+    }
+
+    return !R.empty();
+  }
+
+  void ReadTentativeDefinitions(
+      llvm::SmallVectorImpl<clang::VarDecl *> &Defs) override {
+    for (auto &Source : Sources)
+      Source->ReadTentativeDefinitions(Defs);
+  }
+
+  void ReadUnusedFileScopedDecls(
+      llvm::SmallVectorImpl<const clang::DeclaratorDecl *> &Decls) override {
+    for (auto &Source : Sources)
+      Source->ReadUnusedFileScopedDecls(Decls);
+  }
+
+  void ReadDelegatingConstructors(
+      llvm::SmallVectorImpl<clang::CXXConstructorDecl *> &Decls) override {
+    for (auto &Source : Sources)
+      Source->ReadDelegatingConstructors(Decls);
+  }
+
+  void ReadExtVectorDecls(
+      llvm::SmallVectorImpl<clang::TypedefNameDecl *> &Decls) override {
+    for (auto &Source : Sources)
+      Source->ReadExtVectorDecls(Decls);
+  }
+
+  void ReadUnusedLocalTypedefNameCandidates(
+      llvm::SmallSetVector<const clang::TypedefNameDecl *, 4> &Decls) override {
+    for (auto &Source : Sources)
+      Source->ReadUnusedLocalTypedefNameCandidates(Decls);
+  }
+
+  void ReadReferencedSelectors(
+      llvm::SmallVectorImpl<std::pair<clang::Selector, clang::SourceLocation>>
+          &Sels) override {
+    for (auto &Source : Sources)
+      Source->ReadReferencedSelectors(Sels);
+  }
+
+  void ReadWeakUndeclaredIdentifiers(
+      llvm::SmallVectorImpl<std::pair<clang::IdentifierInfo *, clang::WeakInfo>>
+          &WI) override {
+    for (auto &Source : Sources)
+      Source->ReadWeakUndeclaredIdentifiers(WI);
+  }
+
+  void ReadUsedVTables(
+      llvm::SmallVectorImpl<clang::ExternalVTableUse> &VTables) override {
+    for (auto &Source : Sources)
+      Source->ReadUsedVTables(VTables);
+  }
+
+  void ReadPendingInstantiations(
+      llvm::SmallVectorImpl<
+          std::pair<clang::ValueDecl *, clang::SourceLocation>> &Pending)
+      override {
+    for (auto &Source : Sources)
+      Source->ReadPendingInstantiations(Pending);
+  }
+
+  void ReadLateParsedTemplates(
+      llvm::MapVector<const clang::FunctionDecl *,
+                      std::unique_ptr<clang::LateParsedTemplate>> &LPTMap)
+      override {
+    for (auto &Source : Sources)
+      Source->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 (auto &Source : Sources) {
+      if (clang::TypoCorrection C =
+              Source->CorrectTypo(Typo, LookupKind, S, SS, CCC,
+                                      MemberContext, EnteringContext, OPT))
+        return C;
+    }
+    return clang::TypoCorrection();
+  }
+
+  bool MaybeDiagnoseMissingCompleteType(clang::SourceLocation Loc,
+                                        clang::QualType T) override {
+    for (auto &Source : Sources) {
+      if (Source->MaybeDiagnoseMissingCompleteType(Loc, T))
+        return true;
+    }
+    return false;
+  }
+};
+
+} // namespace lldb_private
+#endif // liblldb_ASTUtils_h_

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/CMakeLists.txt?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/CMakeLists.txt (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/CMakeLists.txt Tue Mar 12 10:09:33 2019
@@ -6,6 +6,7 @@ add_lldb_library(lldbPluginExpressionPar
   ASTDumper.cpp
   ASTResultSynthesizer.cpp
   ASTStructExtractor.cpp
+  ASTUtils.cpp
   ClangASTSource.cpp
   ClangExpressionDeclMap.cpp
   ClangExpressionParser.cpp

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp Tue Mar 12 10:09:33 2019
@@ -36,6 +36,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"
@@ -53,11 +54,17 @@
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/Signals.h"
 
+#include "ClangDiagnostic.h"
+#include "ClangExpressionParser.h"
+#include "ClangUserExpression.h"
+
+#include "ASTUtils.h"
 #include "ClangASTSource.h"
 #include "ClangDiagnostic.h"
 #include "ClangExpressionDeclMap.h"
 #include "ClangExpressionHelper.h"
 #include "ClangExpressionParser.h"
+#include "ClangHost.h"
 #include "ClangModulesDeclVendor.h"
 #include "ClangPersistentVariables.h"
 #include "IRForTarget.h"
@@ -210,15 +217,58 @@ private:
   std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough;
 };
 
+static void
+SetupModuleHeaderPaths(CompilerInstance *compiler,
+                       std::vector<ConstString> include_directories,
+                       lldb::TargetSP target_sp) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  HeaderSearchOptions &search_opts = compiler->getHeaderSearchOpts();
+
+  for (ConstString dir : include_directories) {
+    search_opts.AddPath(dir.AsCString(), frontend::System, false, true);
+    LLDB_LOG(log, "Added user include dir: {0}", dir);
+  }
+
+  llvm::SmallString<128> module_cache;
+  auto props = ModuleList::GetGlobalModuleListProperties();
+  props.GetClangModulesCachePath().GetPath(module_cache);
+  search_opts.ModuleCachePath = module_cache.str();
+  LLDB_LOG(log, "Using module cache path: {0}", module_cache.c_str());
+
+  FileSpec clang_resource_dir = GetClangResourceDir();
+  std::string resource_dir = clang_resource_dir.GetPath();
+  if (FileSystem::Instance().IsDirectory(resource_dir)) {
+    search_opts.ResourceDir = resource_dir;
+    std::string resource_include = resource_dir + "/include";
+    search_opts.AddPath(resource_include, frontend::System, false, true);
+
+    LLDB_LOG(log, "Added resource include dir: {0}", resource_include);
+  }
+
+  search_opts.ImplicitModuleMaps = true;
+
+  std::vector<std::string> system_include_directories =
+      target_sp->GetPlatform()->GetSystemIncludeDirectories(
+          lldb::eLanguageTypeC_plus_plus);
+
+  for (const std::string &include_dir : system_include_directories) {
+    search_opts.AddPath(include_dir, frontend::System, false, true);
+
+    LLDB_LOG(log, "Added system include dir: {0}", include_dir);
+  }
+}
+
 //===----------------------------------------------------------------------===//
 // 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(std::move(include_directories)) {
   Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
 
   // We can't compile expressions without a target.  So if the exe_scope is
@@ -442,6 +492,31 @@ ClangExpressionParser::ClangExpressionPa
   // long time parsing and importing debug information.
   lang_opts.SpellChecking = false;
 
+  auto &clang_expr = *static_cast<ClangUserExpression *>(&m_expr);
+  if (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.DoubleSquareBracketAttributes = true;
+    lang_opts.CPlusPlus11 = true;
+
+    SetupModuleHeaderPaths(m_compiler.get(), m_include_directories,
+                           target_sp);
+  }
+
   if (process_sp && lang_opts.ObjC) {
     if (process_sp->GetObjCLanguageRuntime()) {
       if (process_sp->GetObjCLanguageRuntime()->GetRuntimeVersion() ==
@@ -522,17 +597,6 @@ ClangExpressionParser::ClangExpressionPa
   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);
@@ -874,12 +938,6 @@ ClangExpressionParser::ParseInternal(Dia
   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
@@ -894,18 +952,66 @@ ClangExpressionParser::ParseInternal(Dia
     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();
 
   unsigned num_errors = diag_buf->getNumErrors();

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.h Tue Mar 12 10:09:33 2019
@@ -52,9 +52,14 @@ public:
   ///
   /// \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
@@ -187,6 +192,8 @@ private:
   LLDBPreprocessorCallbacks *m_pp_callbacks; ///< Called when the preprocessor
                                              ///encounters module imports
   std::unique_ptr<ClangASTContext> m_ast_context;
+
+  std::vector<ConstString> m_include_directories;
 };
 }
 

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.cpp Tue Mar 12 10:09:33 2019
@@ -178,8 +178,8 @@ static void AddLocalVariableDecls(const
 bool ClangExpressionSourceCode::GetText(std::string &text,
                                    lldb::LanguageType wrapping_language,
                                    bool static_method,
-                                   ExecutionContext &exe_ctx,
-                                   bool add_locals) const {
+                                   ExecutionContext &exe_ctx, bool add_locals,
+                                   llvm::ArrayRef<std::string> modules) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
 
@@ -273,6 +273,15 @@ bool ClangExpressionSourceCode::GetText(
       break;
     }
 
+    // Generate a list of @import statements that will import the specified
+    // module into our expression.
+    std::string module_imports;
+    for (const 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 @@ bool ClangExpressionSourceCode::GetText(
     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 @@ bool ClangExpressionSourceCode::GetText(
             "%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 @@ bool ClangExpressionSourceCode::GetText(
             "%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;
     }

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangExpressionSourceCode.h Tue Mar 12 10:09:33 2019
@@ -32,10 +32,25 @@ public:
 
   uint32_t GetNumBodyLines();
 
+  /// 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 add_locals,
+               llvm::ArrayRef<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

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp Tue Mar 12 10:09:33 2019
@@ -37,6 +37,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"
@@ -397,7 +398,8 @@ static void SetupDeclVendor(ExecutionCon
 }
 
 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;
@@ -417,8 +419,8 @@ void ClangUserExpression::UpdateLanguage
       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;
@@ -436,8 +438,67 @@ void ClangUserExpression::UpdateLanguage
   }
 }
 
+static bool SupportsCxxModuleImport(lldb::LanguageType language) {
+  switch (language) {
+  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:
+    return true;
+  default:
+    return false;
+  }
+}
+
+std::vector<std::string>
+ClangUserExpression::GetModulesToImport(ExecutionContext &exe_ctx) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  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 {};
+
+  if (log) {
+    for (const SourceModule &m : sc.comp_unit->GetImportedModules()) {
+      LLDB_LOG(log, "Found module in compile unit: {0:$[.]} - include dir: {1}",
+                  llvm::make_range(m.path.begin(), m.path.end()), m.search_path);
+    }
+  }
+
+  for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+    m_include_directories.push_back(m.search_path);
+
+  // Check if we imported 'std' or any of its submodules.
+  // We currently don't support importing any other modules in the expression
+  // parser.
+  for (const SourceModule &m : sc.comp_unit->GetImportedModules())
+    if (!m.path.empty() && m.path.front() == ConstString("std"))
+      return {"std"};
+
+  return {};
+}
+
 bool ClangUserExpression::PrepareForParsing(
     DiagnosticManager &diagnostic_manager, ExecutionContext &exe_ctx) {
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
   InstallContext(exe_ctx);
 
   if (!SetupPersistentState(diagnostic_manager, exe_ctx))
@@ -458,7 +519,13 @@ bool ClangUserExpression::PrepareForPars
 
   SetupDeclVendor(exe_ctx, m_target);
 
-  UpdateLanguageForExpr(diagnostic_manager, exe_ctx);
+  std::vector<std::string> used_modules = GetModulesToImport(exe_ctx);
+  m_imported_cpp_modules = !used_modules.empty();
+
+  LLDB_LOG(log, "List of imported modules in expression: {0}",
+           llvm::make_range(used_modules.begin(), used_modules.end()));
+
+  UpdateLanguageForExpr(diagnostic_manager, exe_ctx, used_modules);
   return true;
 }
 
@@ -517,7 +584,8 @@ bool ClangUserExpression::Parse(Diagnost
   // 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);
 

Modified: lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h (original)
+++ lldb/trunk/source/Plugins/ExpressionParser/Clang/ClangUserExpression.h Tue Mar 12 10:09:33 2019
@@ -167,6 +167,8 @@ public:
   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 @@ private:
                     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 @@ private:
 
   /// 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 @@ private:
   /// 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

Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp Tue Mar 12 10:09:33 2019
@@ -263,6 +263,25 @@ bool PlatformLinux::CanDebugProcess() {
   }
 }
 
+std::vector<std::string>
+PlatformLinux::GetSystemIncludeDirectories(lldb::LanguageType lang) {
+  std::string sys_root = GetSDKRootDirectory().AsCString("");
+  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:
+    return {sys_root + "/usr/include/"};
+  default:
+    return {};
+  }
+}
+
 // 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.

Modified: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h (original)
+++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.h Tue Mar 12 10:09:33 2019
@@ -52,6 +52,9 @@ public:
 
   bool CanDebugProcess() override;
 
+  std::vector<std::string>
+  GetSystemIncludeDirectories(lldb::LanguageType lang) override;
+
   lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
                                Debugger &debugger, Target *target,
                                Status &error) override;

Modified: lldb/trunk/source/Target/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Target.cpp?rev=355939&r1=355938&r2=355939&view=diff
==============================================================================
--- lldb/trunk/source/Target/Target.cpp (original)
+++ lldb/trunk/source/Target/Target.cpp Tue Mar 12 10:09:33 2019
@@ -3327,6 +3327,9 @@ static constexpr PropertyDefinition g_pr
     {"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,
@@ -3465,6 +3468,7 @@ enum {
   ePropertyDebugFileSearchPaths,
   ePropertyClangModuleSearchPaths,
   ePropertyAutoImportClangModules,
+  ePropertyImportStdModule,
   ePropertyAutoApplyFixIts,
   ePropertyNotifyAboutFixIts,
   ePropertySaveObjects,
@@ -3886,6 +3890,12 @@ bool TargetProperties::GetEnableAutoImpo
   return m_collection_sp->GetPropertyAtIndexAsBoolean(
       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;




More information about the lldb-commits mailing list