Skip to content
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

[clang][DebugInfo][gmodules] Set runtimeLang on ObjC forward declarations #120154

Merged
merged 2 commits into from
Dec 17, 2024

Conversation

Michael137
Copy link
Member

In Objective-C, forward declarations are currently represented as:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
  DW_AT_APPLE_runtime_class (DW_LANG_ObjC)

However, when compiling with -gmodules, when a class definition is turned into a forward declaration within a DW_TAG_module, the DIE for the forward declaration looks as follows:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)

Note the absence of DW_AT_APPLE_runtime_class. With recent changes in LLDB, not being able to differentiate between C++ and Objective-C forward declarations has become problematic (see attached test-case and explanation in #119860).

@llvmbot llvmbot added clang Clang issues not falling into any other category lldb clang:modules C++20 modules and Clang Header Modules clang:codegen debuginfo labels Dec 16, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 16, 2024

@llvm/pr-subscribers-debuginfo
@llvm/pr-subscribers-lldb

@llvm/pr-subscribers-clang

Author: Michael Buch (Michael137)

Changes

In Objective-C, forward declarations are currently represented as:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
  DW_AT_APPLE_runtime_class (DW_LANG_ObjC)

However, when compiling with -gmodules, when a class definition is turned into a forward declaration within a DW_TAG_module, the DIE for the forward declaration looks as follows:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)

Note the absence of DW_AT_APPLE_runtime_class. With recent changes in LLDB, not being able to differentiate between C++ and Objective-C forward declarations has become problematic (see attached test-case and explanation in #119860).


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

4 Files Affected:

  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+6-5)
  • (modified) clang/test/Modules/ExtDebugInfo.m (+2-1)
  • (modified) clang/test/Modules/ModuleDebugInfo.m (+1)
  • (added) lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test (+34)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 60f32f76109e9a..ff27690d47b080 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2995,20 +2995,21 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
   if (!ID)
     return nullptr;
 
+  auto RuntimeLang =
+      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
+
   // Return a forward declaration if this type was imported from a clang module,
   // and this is not the compile unit with the implementation of the type (which
   // may contain hidden ivars).
   if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() &&
       !ID->getImplementation())
-    return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
-                                      ID->getName(),
-                                      getDeclContextDescriptor(ID), Unit, 0);
+    return DBuilder.createForwardDecl(
+        llvm::dwarf::DW_TAG_structure_type, ID->getName(),
+        getDeclContextDescriptor(ID), Unit, 0, RuntimeLang);
 
   // Get overall information about the record type for the debug info.
   llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
   unsigned Line = getLineNumber(ID->getLocation());
-  auto RuntimeLang =
-      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
 
   // If this is just a forward declaration return a special forward-declaration
   // debug type since we won't be able to lay out the entire type.
diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m
index b6a8b2676e5ba4..e2611ae5300634 100644
--- a/clang/test/Modules/ExtDebugInfo.m
+++ b/clang/test/Modules/ExtDebugInfo.m
@@ -75,7 +75,8 @@ int foo(ObjCClass *c) {
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MOD]],
-// CHECK-SAME:             flags: DIFlagFwdDecl)
+// CHECK-SAME:             flags: DIFlagFwdDecl,
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC)
 
 // CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type,
 // CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
diff --git a/clang/test/Modules/ModuleDebugInfo.m b/clang/test/Modules/ModuleDebugInfo.m
index 62c6fd68dd8546..c527c43a0f4a2c 100644
--- a/clang/test/Modules/ModuleDebugInfo.m
+++ b/clang/test/Modules/ModuleDebugInfo.m
@@ -39,6 +39,7 @@
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "FwdDecl",
 // CHECK-SAME:             scope: ![[MODULE]],
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MODULE]],
diff --git a/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
new file mode 100644
index 00000000000000..330a6b338c4723
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
@@ -0,0 +1,34 @@
+# REQUIRES: system-darwin
+
+# Test that we can set a breakpoint in a method of a class extension.
+# This requires us to parse the method into an AST type, and the context
+# too (which in DWARF is just a forward declaration).
+#
+# RUN: split-file %s %t
+# RUN: %clangxx_host %t/lib.m  -c -g -gmodules -fmodules -o %t/lib.o
+# RUN: %clangxx_host %t/main.m -g -gmodules -fmodules %t/lib.o -o %t/a.out -framework Foundation
+#
+# RUN: %lldb %t/a.out -o "breakpoint set -f lib.m -l 6" -o exit | FileCheck %s
+
+# CHECK: (lldb) breakpoint set -f lib.m -l 6
+# CHECK: Breakpoint 1: where = a.out`-[NSObject(Foo) func]
+
+#--- main.m
+int main() {
+  return 0;
+}
+
+#--- lib.m
+#import <Foundation/Foundation.h>
+
+@implementation NSObject (Foo)
+- (NSError *)func {
+    NSLog(@"Hello, World!");
+    return 0;
+}
+@end
+
+NSObject * func() {
+  return 0;
+}
+

@llvmbot
Copy link
Member

llvmbot commented Dec 16, 2024

@llvm/pr-subscribers-clang-modules

Author: Michael Buch (Michael137)

Changes

In Objective-C, forward declarations are currently represented as:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
  DW_AT_APPLE_runtime_class (DW_LANG_ObjC)

However, when compiling with -gmodules, when a class definition is turned into a forward declaration within a DW_TAG_module, the DIE for the forward declaration looks as follows:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)

Note the absence of DW_AT_APPLE_runtime_class. With recent changes in LLDB, not being able to differentiate between C++ and Objective-C forward declarations has become problematic (see attached test-case and explanation in #119860).


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

4 Files Affected:

  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+6-5)
  • (modified) clang/test/Modules/ExtDebugInfo.m (+2-1)
  • (modified) clang/test/Modules/ModuleDebugInfo.m (+1)
  • (added) lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test (+34)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 60f32f76109e9a..ff27690d47b080 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2995,20 +2995,21 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
   if (!ID)
     return nullptr;
 
+  auto RuntimeLang =
+      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
+
   // Return a forward declaration if this type was imported from a clang module,
   // and this is not the compile unit with the implementation of the type (which
   // may contain hidden ivars).
   if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() &&
       !ID->getImplementation())
-    return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
-                                      ID->getName(),
-                                      getDeclContextDescriptor(ID), Unit, 0);
+    return DBuilder.createForwardDecl(
+        llvm::dwarf::DW_TAG_structure_type, ID->getName(),
+        getDeclContextDescriptor(ID), Unit, 0, RuntimeLang);
 
   // Get overall information about the record type for the debug info.
   llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
   unsigned Line = getLineNumber(ID->getLocation());
-  auto RuntimeLang =
-      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
 
   // If this is just a forward declaration return a special forward-declaration
   // debug type since we won't be able to lay out the entire type.
diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m
index b6a8b2676e5ba4..e2611ae5300634 100644
--- a/clang/test/Modules/ExtDebugInfo.m
+++ b/clang/test/Modules/ExtDebugInfo.m
@@ -75,7 +75,8 @@ int foo(ObjCClass *c) {
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MOD]],
-// CHECK-SAME:             flags: DIFlagFwdDecl)
+// CHECK-SAME:             flags: DIFlagFwdDecl,
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC)
 
 // CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type,
 // CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
diff --git a/clang/test/Modules/ModuleDebugInfo.m b/clang/test/Modules/ModuleDebugInfo.m
index 62c6fd68dd8546..c527c43a0f4a2c 100644
--- a/clang/test/Modules/ModuleDebugInfo.m
+++ b/clang/test/Modules/ModuleDebugInfo.m
@@ -39,6 +39,7 @@
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "FwdDecl",
 // CHECK-SAME:             scope: ![[MODULE]],
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MODULE]],
diff --git a/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
new file mode 100644
index 00000000000000..330a6b338c4723
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
@@ -0,0 +1,34 @@
+# REQUIRES: system-darwin
+
+# Test that we can set a breakpoint in a method of a class extension.
+# This requires us to parse the method into an AST type, and the context
+# too (which in DWARF is just a forward declaration).
+#
+# RUN: split-file %s %t
+# RUN: %clangxx_host %t/lib.m  -c -g -gmodules -fmodules -o %t/lib.o
+# RUN: %clangxx_host %t/main.m -g -gmodules -fmodules %t/lib.o -o %t/a.out -framework Foundation
+#
+# RUN: %lldb %t/a.out -o "breakpoint set -f lib.m -l 6" -o exit | FileCheck %s
+
+# CHECK: (lldb) breakpoint set -f lib.m -l 6
+# CHECK: Breakpoint 1: where = a.out`-[NSObject(Foo) func]
+
+#--- main.m
+int main() {
+  return 0;
+}
+
+#--- lib.m
+#import <Foundation/Foundation.h>
+
+@implementation NSObject (Foo)
+- (NSError *)func {
+    NSLog(@"Hello, World!");
+    return 0;
+}
+@end
+
+NSObject * func() {
+  return 0;
+}
+

@llvmbot
Copy link
Member

llvmbot commented Dec 16, 2024

@llvm/pr-subscribers-clang-codegen

Author: Michael Buch (Michael137)

Changes

In Objective-C, forward declarations are currently represented as:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
  DW_AT_APPLE_runtime_class (DW_LANG_ObjC)

However, when compiling with -gmodules, when a class definition is turned into a forward declaration within a DW_TAG_module, the DIE for the forward declaration looks as follows:

DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)

Note the absence of DW_AT_APPLE_runtime_class. With recent changes in LLDB, not being able to differentiate between C++ and Objective-C forward declarations has become problematic (see attached test-case and explanation in #119860).


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

4 Files Affected:

  • (modified) clang/lib/CodeGen/CGDebugInfo.cpp (+6-5)
  • (modified) clang/test/Modules/ExtDebugInfo.m (+2-1)
  • (modified) clang/test/Modules/ModuleDebugInfo.m (+1)
  • (added) lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test (+34)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 60f32f76109e9a..ff27690d47b080 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2995,20 +2995,21 @@ llvm::DIType *CGDebugInfo::CreateType(const ObjCInterfaceType *Ty,
   if (!ID)
     return nullptr;
 
+  auto RuntimeLang =
+      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
+
   // Return a forward declaration if this type was imported from a clang module,
   // and this is not the compile unit with the implementation of the type (which
   // may contain hidden ivars).
   if (DebugTypeExtRefs && ID->isFromASTFile() && ID->getDefinition() &&
       !ID->getImplementation())
-    return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type,
-                                      ID->getName(),
-                                      getDeclContextDescriptor(ID), Unit, 0);
+    return DBuilder.createForwardDecl(
+        llvm::dwarf::DW_TAG_structure_type, ID->getName(),
+        getDeclContextDescriptor(ID), Unit, 0, RuntimeLang);
 
   // Get overall information about the record type for the debug info.
   llvm::DIFile *DefUnit = getOrCreateFile(ID->getLocation());
   unsigned Line = getLineNumber(ID->getLocation());
-  auto RuntimeLang =
-      static_cast<llvm::dwarf::SourceLanguage>(TheCU->getSourceLanguage());
 
   // If this is just a forward declaration return a special forward-declaration
   // debug type since we won't be able to lay out the entire type.
diff --git a/clang/test/Modules/ExtDebugInfo.m b/clang/test/Modules/ExtDebugInfo.m
index b6a8b2676e5ba4..e2611ae5300634 100644
--- a/clang/test/Modules/ExtDebugInfo.m
+++ b/clang/test/Modules/ExtDebugInfo.m
@@ -75,7 +75,8 @@ int foo(ObjCClass *c) {
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MOD]],
-// CHECK-SAME:             flags: DIFlagFwdDecl)
+// CHECK-SAME:             flags: DIFlagFwdDecl,
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC)
 
 // CHECK-NOT: !DICompositeType(tag: DW_TAG_structure_type,
 // CHECK: !DICompositeType(tag: DW_TAG_enumeration_type,
diff --git a/clang/test/Modules/ModuleDebugInfo.m b/clang/test/Modules/ModuleDebugInfo.m
index 62c6fd68dd8546..c527c43a0f4a2c 100644
--- a/clang/test/Modules/ModuleDebugInfo.m
+++ b/clang/test/Modules/ModuleDebugInfo.m
@@ -39,6 +39,7 @@
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "FwdDecl",
 // CHECK-SAME:             scope: ![[MODULE]],
+// CHECK-SAME:             runtimeLang: DW_LANG_ObjC
 
 // CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "ObjCClass",
 // CHECK-SAME:             scope: ![[MODULE]],
diff --git a/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
new file mode 100644
index 00000000000000..330a6b338c4723
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/DWARF/objc-gmodules-class-extension.test
@@ -0,0 +1,34 @@
+# REQUIRES: system-darwin
+
+# Test that we can set a breakpoint in a method of a class extension.
+# This requires us to parse the method into an AST type, and the context
+# too (which in DWARF is just a forward declaration).
+#
+# RUN: split-file %s %t
+# RUN: %clangxx_host %t/lib.m  -c -g -gmodules -fmodules -o %t/lib.o
+# RUN: %clangxx_host %t/main.m -g -gmodules -fmodules %t/lib.o -o %t/a.out -framework Foundation
+#
+# RUN: %lldb %t/a.out -o "breakpoint set -f lib.m -l 6" -o exit | FileCheck %s
+
+# CHECK: (lldb) breakpoint set -f lib.m -l 6
+# CHECK: Breakpoint 1: where = a.out`-[NSObject(Foo) func]
+
+#--- main.m
+int main() {
+  return 0;
+}
+
+#--- lib.m
+#import <Foundation/Foundation.h>
+
+@implementation NSObject (Foo)
+- (NSError *)func {
+    NSLog(@"Hello, World!");
+    return 0;
+}
+@end
+
+NSObject * func() {
+  return 0;
+}
+

getDeclContextDescriptor(ID), Unit, 0);
return DBuilder.createForwardDecl(
llvm::dwarf::DW_TAG_structure_type, ID->getName(),
getDeclContextDescriptor(ID), Unit, 0, RuntimeLang);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Two things:

  1. Shouldn't we do this only for ObjC class types?
  2. Shouldn't — even in an ObjC++ CU — the runtimelang on an ObjC class be ObjC?

Copy link
Member Author

Choose a reason for hiding this comment

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

This overload is specifically for const ObjCInterfaceType *Ty. So we're always dealing with ObjC classes here.

On line 3021 we're setting the RuntimeLang in the same way. I think we should stay consistent with whatever we attach to a definition. All the places in dsymutil and LLDB that read DW_AT_APPLE_runtime_class check for both ObjC and ObjC++. So looks like both are valid

…ions

In Objective-C, forward declarations are currently represented as:
```
DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
  DW_AT_APPLE_runtime_class (DW_LANG_ObjC)
```
However, when compiling with `-gmodules`, when a class definition
is turned into a forward declaration within a `DW_TAG_module`, the
DIE for the forward declaration looks as follows:
```
DW_TAG_structure_type
  DW_AT_name                ("Foo")
  DW_AT_declaration         (true)
```

Note the absence of `DW_AT_APPLE_runtime_class`. With recent changes in
LLDB, not being able to differentiate between C++ and Objective-C
forward declarations has become problematic (see attached test-case
and explanation in llvm#119860).
@Michael137 Michael137 force-pushed the clang/gmodules-fwd-decl-language branch from 7c7fd60 to f4ad496 Compare December 17, 2024 13:55
@Michael137 Michael137 merged commit 9fc54c0 into llvm:main Dec 17, 2024
8 checks passed
@Michael137 Michael137 deleted the clang/gmodules-fwd-decl-language branch December 17, 2024 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category debuginfo lldb
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants