Skip to content

[lldb][SymbolFileDWARF] Fall back to using parent DW_AT_LLVM_include_path for submodules #142044

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 30, 2025

Conversation

Michael137
Copy link
Member

@Michael137 Michael137 commented May 29, 2025

Inferred submodule declarations are emitted in DWARF as DW_TAG_modules without DW_AT_LLVM_include_paths. Instead the parent DIE will have the include path. This patch adds support for such setups. Without this, the ClangModulesDeclVendor would fail to AddModule the submodules (i.e., compile and load the submodules). This would cause errors such as:

note: error: Header search couldn't locate module 'TopLevel'

The test added here also tests #141220. Without that patch we'd fail with:

note: error: No module map file in /Users/jonas/Git/llvm-worktrees/llvm-project/lldb/test/API/lang/cpp/decl-from-submodule

Unfortunately the embedded clang instance doesn't allow us to use the decls we find in the modules. But we'll try to fix that in a separate patch.

rdar://151022173

…path for submodules

Inferred submodule declarations are emitted in DWARF as `DW_TAG_module`s
without `DW_AT_LLVM_include_path`s. Instead the parent DIE will have the
include path. This patch adds support for such setups. Without this, the
`ClangModulesDeclVendor` would fail to `AddModule` the submodules (i.e.,
compile and load the submodules). This would cause errors such as:
```
note: error: Header search couldn't locate module 'TopLevel'
```

The test added here also tests llvm#141220.

Unfortunately the embedded clang instance doesn't allow us to use the decls we find in the modules. But we'll try to fix that in a separate patch.
@Michael137 Michael137 requested a review from adrian-prantl May 29, 2025 21:50
@Michael137 Michael137 requested a review from JDevlieghere as a code owner May 29, 2025 21:50
@llvmbot llvmbot added the lldb label May 29, 2025
@llvmbot
Copy link
Member

llvmbot commented May 29, 2025

@llvm/pr-subscribers-lldb

Author: Michael Buch (Michael137)

Changes

Inferred submodule declarations are emitted in DWARF as DW_TAG_modules without DW_AT_LLVM_include_paths. Instead the parent DIE will have the include path. This patch adds support for such setups. Without this, the ClangModulesDeclVendor would fail to AddModule the submodules (i.e., compile and load the submodules). This would cause errors such as:

note: error: Header search couldn't locate module 'TopLevel'

The test added here also tests #141220.

Unfortunately the embedded clang instance doesn't allow us to use the decls we find in the modules. But we'll try to fix that in a separate patch.

rdar://151022173


Full diff: https://github.com/llvm/llvm-project/pull/142044.diff

7 Files Affected:

  • (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+10-2)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/Makefile (+4)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/TestDeclFromSubmodule.py (+25)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module1.h (+2)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module2.h (+2)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/main.cpp (+9)
  • (added) lldb/test/API/lang/cpp/decl-from-submodule/module.modulemap (+6)
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index d2049161fb5ad..24f905a023317 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -1188,6 +1188,8 @@ bool SymbolFileDWARF::ParseImportedModules(
       SourceModule module;
       module.path.push_back(ConstString(name));
 
+      const char *include_path = module_die.GetAttributeValueAsString(
+          DW_AT_LLVM_include_path, nullptr);
       DWARFDIE parent_die = module_die;
       while ((parent_die = parent_die.GetParent())) {
         if (parent_die.Tag() != DW_TAG_module)
@@ -1195,10 +1197,16 @@ bool SymbolFileDWARF::ParseImportedModules(
         if (const char *name =
                 parent_die.GetAttributeValueAsString(DW_AT_name, nullptr))
           module.path.push_back(ConstString(name));
+
+        // Inferred submodule declarations may not have a
+        // DW_AT_LLVM_include_path. Pick the parent (aka umbrella) module's
+        // include path instead.
+        if (!include_path)
+          include_path = parent_die.GetAttributeValueAsString(
+              DW_AT_LLVM_include_path, nullptr);
       }
       std::reverse(module.path.begin(), module.path.end());
-      if (const char *include_path = module_die.GetAttributeValueAsString(
-              DW_AT_LLVM_include_path, nullptr)) {
+      if (include_path) {
         FileSpec include_spec(include_path, dwarf_cu->GetPathStyle());
         MakeAbsoluteAndRemap(include_spec, *dwarf_cu,
                              m_objfile_sp->GetModule());
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/Makefile b/lldb/test/API/lang/cpp/decl-from-submodule/Makefile
new file mode 100644
index 0000000000000..e1e28fa0efebb
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+CXXFLAGS_EXTRAS = $(MANDATORY_MODULE_BUILD_CFLAGS)
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/TestDeclFromSubmodule.py b/lldb/test/API/lang/cpp/decl-from-submodule/TestDeclFromSubmodule.py
new file mode 100644
index 0000000000000..2819e59b1a1e5
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/TestDeclFromSubmodule.py
@@ -0,0 +1,25 @@
+"""Test that decl lookup into submodules in C++ works as expected."""
+
+import lldb
+import shutil
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class DeclFromSubmoduleTestCase(TestBase):
+    def test_expr(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "return 0", lldb.SBFileSpec("main.cpp"))
+
+        # FIXME: LLDB finds the decl for 'func' in the submodules correctly and hands it to Clang
+        # but Sema rejects using the decl during name lookup because it is not marked "Visible".
+        # However, this assertions still ensures that we at least don't fail to compile the
+        # submodule (which would cause other errors to appear before the expression error, hence
+        # we use "startstr").
+        self.expect(
+            "expr func(1, 2)",
+            error=True,
+            startstr="error: <user expression 0>:1:1: 'func' has unknown return type",
+        )
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module1.h b/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module1.h
new file mode 100644
index 0000000000000..38d9d120847c9
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module1.h
@@ -0,0 +1,2 @@
+// nodebug to force LLDB to find the decls in modules
+[[gnu::nodebug]] inline int func(int x) { return x; }
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module2.h b/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module2.h
new file mode 100644
index 0000000000000..440c76dd50c77
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/TopLevel/module2.h
@@ -0,0 +1,2 @@
+// nodebug to force LLDB to find the decls in modules
+[[gnu::nodebug]] inline int func(int x, int y) { return x + y; }
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/main.cpp b/lldb/test/API/lang/cpp/decl-from-submodule/main.cpp
new file mode 100644
index 0000000000000..5e05b6980169a
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/main.cpp
@@ -0,0 +1,9 @@
+#include "TopLevel/module1.h"
+#include "TopLevel/module2.h"
+
+int main() {
+  func(1);
+  func(2, 3);
+
+  return 0;
+}
diff --git a/lldb/test/API/lang/cpp/decl-from-submodule/module.modulemap b/lldb/test/API/lang/cpp/decl-from-submodule/module.modulemap
new file mode 100644
index 0000000000000..b00659f7efb67
--- /dev/null
+++ b/lldb/test/API/lang/cpp/decl-from-submodule/module.modulemap
@@ -0,0 +1,6 @@
+module TopLevel {
+  umbrella "TopLevel"
+  explicit module * {
+    export *
+  }
+}

Copy link
Collaborator

@adrian-prantl adrian-prantl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@Michael137 Michael137 merged commit 7b96272 into llvm:main May 30, 2025
12 checks passed
@Michael137 Michael137 deleted the lldb/submodules-search-path branch May 30, 2025 06:16
Michael137 added a commit to swiftlang/llvm-project that referenced this pull request May 30, 2025
…path for submodules (llvm#142044)

Inferred submodule declarations are emitted in DWARF as `DW_TAG_module`s
without `DW_AT_LLVM_include_path`s. Instead the parent DIE will have the
include path. This patch adds support for such setups. Without this, the
`ClangModulesDeclVendor` would fail to `AddModule` the submodules (i.e.,
compile and load the submodules). This would cause errors such as:
```
note: error: Header search couldn't locate module 'TopLevel'
```

The test added here also tests
llvm#141220. Without that patch
we'd fail with:
```
note: error: No module map file in /Users/jonas/Git/llvm-worktrees/llvm-project/lldb/test/API/lang/cpp/decl-from-submodule
```

Unfortunately the embedded clang instance doesn't allow us to use the
decls we find in the modules. But we'll try to fix that in a separate
patch.

rdar://151022173
(cherry picked from commit 7b96272)
@DavidSpickett
Copy link
Collaborator

This test was failing on Windows I think because like many others, we're not making DWARF or we're not retaining it when linking with link.exe. I've skipped it there - 7a66b28.

@Michael137
Copy link
Member Author

This test was failing on Windows I think because like many others, we're not making DWARF or we're not retaining it when linking with link.exe. I've skipped it there - 7a66b28.

Thanks!

adrian-prantl pushed a commit to swiftlang/llvm-project that referenced this pull request May 30, 2025
…_path for submodules (#10764)

* [lldb][SymbolFileDWARF] Fall back to using parent DW_AT_LLVM_include_path for submodules (llvm#142044)

Inferred submodule declarations are emitted in DWARF as `DW_TAG_module`s
without `DW_AT_LLVM_include_path`s. Instead the parent DIE will have the
include path. This patch adds support for such setups. Without this, the
`ClangModulesDeclVendor` would fail to `AddModule` the submodules (i.e.,
compile and load the submodules). This would cause errors such as:
```
note: error: Header search couldn't locate module 'TopLevel'
```

The test added here also tests
llvm#141220. Without that patch
we'd fail with:
```
note: error: No module map file in /Users/jonas/Git/llvm-worktrees/llvm-project/lldb/test/API/lang/cpp/decl-from-submodule
```

Unfortunately the embedded clang instance doesn't allow us to use the
decls we find in the modules. But we'll try to fix that in a separate
patch.

rdar://151022173
(cherry picked from commit 7b96272)

* [lldb][test] Disable DeclFromSubmodule test on Windows

Or more precisely, when linking with link.exe, but Windows
is our closest proxy for that right now.

This test requires the DWARF info to work, on the Windows on Arm
buildbot it fails:
```
AssertionError: Ran command:
"expr func(1, 2)"

Got output:
error: <user expression 0>:1:1: use of undeclared identifier 'func'

    1 | func(1, 2)

      | ^~~~

Expecting start string: "error: <user expression 0>:1:1: 'func' has unknown return type" (was not found)
```

(cherry picked from commit 7a66b28)

---------

Co-authored-by: David Spickett <david.spickett@linaro.org>
sivan-shani pushed a commit to sivan-shani/llvm-project that referenced this pull request Jun 3, 2025
…path for submodules (llvm#142044)

Inferred submodule declarations are emitted in DWARF as `DW_TAG_module`s
without `DW_AT_LLVM_include_path`s. Instead the parent DIE will have the
include path. This patch adds support for such setups. Without this, the
`ClangModulesDeclVendor` would fail to `AddModule` the submodules (i.e.,
compile and load the submodules). This would cause errors such as:
```
note: error: Header search couldn't locate module 'TopLevel'
```

The test added here also tests
llvm#141220. Without that patch
we'd fail with:
```
note: error: No module map file in /Users/jonas/Git/llvm-worktrees/llvm-project/lldb/test/API/lang/cpp/decl-from-submodule
```

Unfortunately the embedded clang instance doesn't allow us to use the
decls we find in the modules. But we'll try to fix that in a separate
patch.

rdar://151022173
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants