Michael137 updated this revision to Diff 506588.
Michael137 added a comment.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

- Fix cycle in `DIDerivedType` when we deal with forward declarations and 
complete explicitly via `completeClassData` (e.g., with `-gmodules`)
- Add tests for `-gmodules`


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D145803/new/

https://reviews.llvm.org/D145803

Files:
  clang/lib/CodeGen/CGDebugInfo.cpp
  clang/lib/CodeGen/CGDebugInfo.h
  clang/test/CodeGen/preferred_name.cpp
  clang/test/Modules/Inputs/gmodules-preferred-name-alias.h
  clang/test/Modules/Inputs/gmodules-preferred-name-alias.modulemap
  clang/test/Modules/Inputs/gmodules-preferred-name-typedef.h
  clang/test/Modules/Inputs/gmodules-preferred-name-typedef.modulemap
  clang/test/Modules/gmodules-preferred-name-alias.cpp
  clang/test/Modules/gmodules-preferred-name-typedef.cpp
  
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py
  
lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py

Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py
@@ -22,7 +22,7 @@
 
     def make_expected_basic_string_ptr(self) -> str:
         if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(['>', '16.0']):
-            return f'std::unique_ptr<std::basic_string<char> >'
+            return f'std::unique_ptr<std::string>'
         else:
             return 'std::unique_ptr<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, ' \
                    'std::default_delete<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >'
Index: lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py
===================================================================
--- lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py
+++ lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py
@@ -59,13 +59,13 @@
         self.assertNotEqual(valobj.child[0].unsigned, 0)
 
         if self.expectedCompiler(["clang"]) and self.expectedCompilerVersion(['>', '16.0']):
-            string_type = "std::basic_string<char>"
+            string_type = "std::string"
         else:
-            string_type = "std::basic_string<char, std::char_traits<char>, std::allocator<char> >"
+            string_type = "std::basic_string<char, std::char_traits<char>, std::allocator<char> > "
 
         valobj = self.expect_var_path(
             "sp_str",
-            type="std::shared_ptr<" + string_type + " >",
+            type="std::shared_ptr<" + string_type + ">",
             children=[ValueCheck(name="__ptr_", summary='"hello"')],
         )
         self.assertRegex(valobj.summary, r'^"hello"( strong=1)? weak=1$')
Index: clang/test/Modules/gmodules-preferred-name-typedef.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/gmodules-preferred-name-typedef.cpp
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -std=c++11 -dwarf-ext-refs -fmodule-format=obj \
+// RUN:     -fmodule-map-file=%S/Inputs/gmodules-preferred-name-typedef.modulemap \
+// RUN:     -fmodules-cache-path=%t -debug-info-kind=standalone -debugger-tuning=lldb \
+// RUN:     -fmodules -mllvm -debug-only=pchcontainer -x c++ \
+// RUN:     -I %S/Inputs %s &> %t.ll
+// RUN: cat %t.ll | FileCheck %s
+
+#include "gmodules-preferred-name-typedef.h"
+
+// CHECK: ![[#]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[PREF_BASE:[0-9]+]])
+// CHECK: ![[PREF_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<char>"
Index: clang/test/Modules/gmodules-preferred-name-alias.cpp
===================================================================
--- /dev/null
+++ clang/test/Modules/gmodules-preferred-name-alias.cpp
@@ -0,0 +1,12 @@
+// RUN: rm -rf %t
+// RUN: %clang_cc1 -std=c++11 -dwarf-ext-refs -fmodule-format=obj \
+// RUN:     -fmodule-map-file=%S/Inputs/gmodules-preferred-name-alias.modulemap \
+// RUN:     -fmodules-cache-path=%t -debug-info-kind=standalone -debugger-tuning=lldb \
+// RUN:     -fmodules -mllvm -debug-only=pchcontainer -x c++ \
+// RUN:     -I %S/Inputs %s &> %t.ll
+// RUN: cat %t.ll | FileCheck %s
+
+#include "gmodules-preferred-name-alias.h"
+
+// CHECK: ![[#]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>", scope: ![[#]], file: ![[#]], line: [[#]], baseType: ![[PREF_BASE:[0-9]+]])
+// CHECK: ![[PREF_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<char>"
Index: clang/test/Modules/Inputs/gmodules-preferred-name-typedef.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/gmodules-preferred-name-typedef.modulemap
@@ -0,0 +1,4 @@
+module PreferredNameModule {
+  header "gmodules-preferred-name-typedef.h"
+  export *
+}
Index: clang/test/Modules/Inputs/gmodules-preferred-name-typedef.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/gmodules-preferred-name-typedef.h
@@ -0,0 +1,7 @@
+template<typename T> struct Foo;
+
+typedef Foo<char> Bar;
+
+template<typename T> struct [[clang::preferred_name(Bar)]] Foo {};
+
+template <typename T> struct Baz { Foo<char> member; };
Index: clang/test/Modules/Inputs/gmodules-preferred-name-alias.modulemap
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/gmodules-preferred-name-alias.modulemap
@@ -0,0 +1,4 @@
+module PreferredNameModule {
+  header "gmodules-preferred-name-alias.h"
+  export *
+}
Index: clang/test/Modules/Inputs/gmodules-preferred-name-alias.h
===================================================================
--- /dev/null
+++ clang/test/Modules/Inputs/gmodules-preferred-name-alias.h
@@ -0,0 +1,8 @@
+template<typename T> struct Foo;
+
+template<typename T>
+using Bar = Foo<T>;
+
+template<typename T> struct [[clang::preferred_name(Bar<T>)]] Foo {};
+
+template <typename T> struct Baz { Foo<char> member; };
Index: clang/test/CodeGen/preferred_name.cpp
===================================================================
--- /dev/null
+++ clang/test/CodeGen/preferred_name.cpp
@@ -0,0 +1,85 @@
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -debugger-tuning=lldb %s | FileCheck %s --check-prefixes=COMMON,LLDB
+// RUN: %clang_cc1 -triple x86_64-unk-unk -o - -emit-llvm -debug-info-kind=standalone -debugger-tuning=gdb %s | FileCheck %s --check-prefixes=COMMON,GDB
+
+template <typename T>
+struct Foo;
+
+typedef Foo<int> BarInt;
+typedef Foo<double> BarDouble;
+
+template <typename T>
+using Bar = Foo<T>;
+
+template <typename T>
+struct [[clang::preferred_name(BarInt),
+         clang::preferred_name(BarDouble),
+         clang::preferred_name(Bar<short>),
+         clang::preferred_name(Bar<char>)]] Foo{
+         };
+
+int main() {
+    Foo<int> varInt;
+
+// COMMON: !DILocalVariable(name: "varInt", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_INT_TY:[0-9]+]])
+// LLDB:   ![[BAR_INT_TY]] = !DIDerivedType(tag: DW_TAG_typedef, name: "BarInt", file: ![[#]], line: [[#]], baseType: ![[BAR_INT_BASE:[0-9]+]])
+// LLDB:   ![[BAR_INT_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<int>", file: ![[#]], line: [[#]], size: [[#]]
+// GDB:    ![[BAR_INT_TY]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<int>", file: ![[#]], line: [[#]], size: [[#]]
+
+    Foo<double> varDouble;
+
+// COMMON: !DILocalVariable(name: "varDouble", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_DOUBLE_TY:[0-9]+]])
+// LLDB:   ![[BAR_DOUBLE_TY]] = !DIDerivedType(tag: DW_TAG_typedef, name: "BarDouble", file: ![[#]], line: [[#]], baseType: ![[BAR_DOUBLE_BASE:[0-9]+]])
+// LLDB:   ![[BAR_DOUBLE_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<double>"
+// GDB:    ![[BAR_DOUBLE_TY]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<double>"
+
+    Foo<short> varShort;
+
+// COMMON: !DILocalVariable(name: "varShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY:[0-9]+]])
+// LLDB:   ![[BAR_SHORT_TY]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>", file: ![[#]], line: [[#]], baseType: ![[BAR_SHORT_BASE:[0-9]+]])
+// LLDB:   ![[BAR_SHORT_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<short>"
+// GDB:    ![[BAR_SHORT_TY]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<short>"
+
+    Foo<char> varChar;
+
+// COMMON: !DILocalVariable(name: "varChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY:[0-9]+]])
+// LLDB:   ![[BAR_CHAR_TY]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>", file: ![[#]], line: [[#]], baseType: ![[BAR_CHAR_BASE:[0-9]+]])
+// LLDB:   ![[BAR_CHAR_BASE]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<char>"
+// GDB:    ![[BAR_CHAR_TY]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<char>"
+
+    Foo<Foo<int>> varFooInt;
+
+// COMMON: !DILocalVariable(name: "varFooInt", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_FOO_INT_TY:[0-9]+]])
+// COMMON: ![[BAR_FOO_INT_TY]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo<Foo<int> >"
+
+    BarInt barInt;
+
+// LLDB:   !DILocalVariable(name: "barInt", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_INT_TY]])
+// GDB:    !DILocalVariable(name: "barInt", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_INT_TYPEDEF:[0-9]+]])
+// GDB:    ![[BAR_INT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "BarInt"
+
+    BarDouble barDouble;
+
+// LLDB:   !DILocalVariable(name: "barDouble", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_DOUBLE_TY]])
+// GDB:    !DILocalVariable(name: "barDouble", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_DOUBLE_TYPEDEF:[0-9]+]])
+// GDB:    ![[BAR_DOUBLE_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "BarDouble"
+
+    Bar<short> barShort;
+
+// LLDB:   !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TY_2:[0-9]+]])
+// GDB:    !DILocalVariable(name: "barShort", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_SHORT_TYPEDEF:[0-9]+]])
+// GDB:    ![[BAR_SHORT_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>"
+
+    Bar<char> barChar;
+
+// LLDB:   ![[BAR_SHORT_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<short>", file: ![[#]], line: [[#]], baseType: ![[BAR_SHORT_TY]])
+
+// LLDB:   !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TY_2:[0-9]+]])
+// GDB:    !DILocalVariable(name: "barChar", scope: ![[#]], file: ![[#]], line: [[#]], type: ![[BAR_CHAR_TYPEDEF:[0-9]+]])
+// GDB:    ![[BAR_CHAR_TYPEDEF]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>"
+
+// LLDB:   ![[BAR_CHAR_TY_2]] = !DIDerivedType(tag: DW_TAG_typedef, name: "Bar<char>", file: ![[#]], line: [[#]], baseType: ![[BAR_CHAR_TY]])
+
+    return 0;
+}
+
+
Index: clang/lib/CodeGen/CGDebugInfo.h
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.h
+++ clang/lib/CodeGen/CGDebugInfo.h
@@ -192,7 +192,15 @@
   llvm::DIType *CreateType(const FunctionType *Ty, llvm::DIFile *F);
   /// Get structure or union type.
   llvm::DIType *CreateType(const RecordType *Tyg);
-  llvm::DIType *CreateTypeDefinition(const RecordType *Ty);
+
+  /// Create definition for the specified 'Ty'.
+  ///
+  /// \returns A pair of 'llvm::DIType's. The first is the definition
+  /// of the 'Ty'. The second is the type specified by the preferred_name
+  /// attribute on 'Ty', which can be a nullptr if no such attribute
+  /// exists.
+  std::pair<llvm::DIType *, llvm::DIType *>
+  CreateTypeDefinition(const RecordType *Ty);
   llvm::DICompositeType *CreateLimitedType(const RecordType *Ty);
   void CollectContainingType(const CXXRecordDecl *RD,
                              llvm::DICompositeType *CT);
@@ -276,6 +284,12 @@
       llvm::DenseSet<CanonicalDeclPtr<const CXXRecordDecl>> &SeenTypes,
       llvm::DINode::DIFlags StartingFlags);
 
+  /// Helper class that retrieves returns llvm::DIType the that
+  /// PreferredNameAttr attribute on \ref RD refers to. If no such
+  /// attribute exists, returns nullptr.
+  llvm::DIType *GetPreferredNameType(const CXXRecordDecl *RD,
+                                     llvm::DIFile *Unit);
+
   struct TemplateArgs {
     const TemplateParameterList *TList;
     llvm::ArrayRef<TemplateArgument> Args;
Index: clang/lib/CodeGen/CGDebugInfo.cpp
===================================================================
--- clang/lib/CodeGen/CGDebugInfo.cpp
+++ clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2479,7 +2479,11 @@
   auto I = TypeCache.find(TyPtr);
   if (I != TypeCache.end() && !cast<llvm::DIType>(I->second)->isForwardDecl())
     return;
-  llvm::DIType *Res = CreateTypeDefinition(Ty->castAs<RecordType>());
+
+  // We want the canonical definition of the structure to not
+  // be the typedef. Since that would lead to circular typedef
+  // metadata.
+  auto [Res, PrefRes] = CreateTypeDefinition(Ty->castAs<RecordType>());
   assert(!Res->isForwardDecl());
   TypeCache[TyPtr].reset(Res);
 }
@@ -2599,10 +2603,25 @@
     return T;
   }
 
-  return CreateTypeDefinition(Ty);
+  auto [Def, Pref] = CreateTypeDefinition(Ty);
+
+  return Pref ? Pref : Def;
 }
 
-llvm::DIType *CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
+llvm::DIType *CGDebugInfo::GetPreferredNameType(const CXXRecordDecl *RD,
+                                                llvm::DIFile *Unit) {
+  if (!RD)
+    return nullptr;
+
+  auto const *PNA = RD->getAttr<PreferredNameAttr>();
+  if (!PNA)
+    return nullptr;
+
+  return getOrCreateType(PNA->getTypedefType(), Unit);
+}
+
+std::pair<llvm::DIType *, llvm::DIType *>
+CGDebugInfo::CreateTypeDefinition(const RecordType *Ty) {
   RecordDecl *RD = Ty->getDecl();
 
   // Get overall information about the record type for the debug info.
@@ -2618,7 +2637,7 @@
 
   const RecordDecl *D = RD->getDefinition();
   if (!D || !D->isCompleteDefinition())
-    return FwdDecl;
+    return {FwdDecl, nullptr};
 
   if (const auto *CXXDecl = dyn_cast<CXXRecordDecl>(RD))
     CollectContainingType(CXXDecl, FwdDecl);
@@ -2657,7 +2676,12 @@
         llvm::MDNode::replaceWithPermanent(llvm::TempDICompositeType(FwdDecl));
 
   RegionMap[Ty->getDecl()].reset(FwdDecl);
-  return FwdDecl;
+
+  if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB)
+    if (auto *PrefDI = GetPreferredNameType(CXXDecl, DefUnit))
+      return {FwdDecl, PrefDI};
+
+  return {FwdDecl, nullptr};
 }
 
 llvm::DIType *CGDebugInfo::CreateType(const ObjCObjectType *Ty,
@@ -3685,7 +3709,7 @@
 void CGDebugInfo::CollectContainingType(const CXXRecordDecl *RD,
                                         llvm::DICompositeType *RealDecl) {
   // A class's primary base or the class itself contains the vtable.
-  llvm::DICompositeType *ContainingType = nullptr;
+  llvm::DIType *ContainingType = nullptr;
   const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD);
   if (const CXXRecordDecl *PBase = RL.getPrimaryBase()) {
     // Seek non-virtual primary base root.
@@ -3697,9 +3721,8 @@
       else
         break;
     }
-    ContainingType = cast<llvm::DICompositeType>(
-        getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
-                        getOrCreateFile(RD->getLocation())));
+    ContainingType = getOrCreateType(QualType(PBase->getTypeForDecl(), 0),
+                                     getOrCreateFile(RD->getLocation()));
   } else if (RD->isDynamicClass())
     ContainingType = RealDecl;
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to