Skip to content

Conversation

kikairoya
Copy link
Contributor

Add test for:

  • shows effect of inlining member functions
  • shows effect of template instantiation methods

Make cleaner a bit:

  • drops unnecessary REQUIRES clause
  • uses %clang_cc1 instead of %clang -Xclang
  • uses simply -O1 instead of -disable-O0-optnone -disable-llvm-passes
    • LTO test remains unchanged since replacing by -O1 changes output even if variables are anchored

@llvmbot llvmbot added the clang Clang issues not falling into any other category label Aug 2, 2025
@kikairoya
Copy link
Contributor Author

I'd like to add test coverage and verify the intended behavior on edge cases before submitting the long-term fix for #149639.

@jmorse @CarlosAlbertoEnciso
Could you take a look at this and check if the new tests reflect the intended behavior?

@llvmbot
Copy link
Member

llvmbot commented Aug 2, 2025

@llvm/pr-subscribers-clang

Author: Tomohiro Kashiwada (kikairoya)

Changes

Add test for:

  • shows effect of inlining member functions
  • shows effect of template instantiation methods

Make cleaner a bit:

  • drops unnecessary REQUIRES clause
  • uses %clang_cc1 instead of %clang -Xclang
  • uses simply -O1 instead of -disable-O0-optnone -disable-llvm-passes
    • LTO test remains unchanged since replacing by -O1 changes output even if variables are anchored

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

7 Files Affected:

  • (added) clang/test/CodeGenCXX/vtable-debug-info-external.cpp (+93)
  • (modified) clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp (+8-7)
  • (modified) clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp (+6-6)
  • (modified) clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp (-2)
  • (modified) clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp (+6-3)
  • (modified) clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp (+8-7)
  • (added) clang/test/CodeGenCXX/vtable-debug-info-template-instantiation.cpp (+88)
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-external.cpp b/clang/test/CodeGenCXX/vtable-debug-info-external.cpp
new file mode 100644
index 0000000000000..c4138e720ccae
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-debug-info-external.cpp
@@ -0,0 +1,93 @@
+// The debug info of vtable is attached conditionally to whether
+// - Member functions are inlined or not
+// - Definition of destructor is visible or not
+
+struct CInlined {
+  virtual void f1() noexcept {}
+  virtual void f2() noexcept {}
+  virtual ~CInlined() noexcept;
+};
+#ifndef NO_DTOR_BODY
+inline CInlined::~CInlined() noexcept {}
+#endif
+
+struct CNoInline {
+  virtual void g1() noexcept;
+  virtual void g2() noexcept;
+  virtual ~CNoInline() noexcept;
+};
+
+void CNoInline::g1() noexcept {}
+void CNoInline::g2() noexcept {}
+#ifndef NO_DTOR_BODY
+CNoInline::~CNoInline() noexcept {}
+#endif
+
+struct CNoFnDef {
+  virtual void h1() noexcept;
+  virtual void h2() noexcept;
+  virtual ~CNoFnDef() noexcept;
+};
+
+#ifndef NO_DTOR_BODY
+CNoFnDef::~CNoFnDef() noexcept {}
+#endif
+
+void use(void *, ...);
+
+int main() {
+  CInlined Inlined;
+  CNoInline NoInline;
+  CNoFnDef NoFnDef;
+  use(&Inlined, &NoInline, &NoFnDef);
+
+  return 0;
+}
+
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s -check-prefix CHECK-HAS-DTOR
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 -DNO_DTOR_BODY %s -o - | FileCheck %s -check-prefixes CHECK-NO-DTOR
+
+// CHECK-HAS-DTOR: $_ZTV8CInlined = comdat any
+// CHECK-HAS-DTOR-NOT: $_ZTV9CNoInline
+// CHECK-HAS-DTOR-NOT: $_ZTV8CNoFnDef
+
+// CHECK-HAS-DTOR-DAG: @_ZTV8CInlined = linkonce_odr {{.*}}constant {{{ \[[^]]*\] } { \[[^]]*\] \[[^]]*\] }}}, comdat, align 8, !dbg [[INLINED_VTABLE_VAR:![0-9]+]]
+// CHECK-HAS-DTOR-DAG: @_ZTV9CNoInline = {{.*}}constant {{{ \[[^]]*\] } { \[[^]]*\] \[[^]]*\] }}}, align 8, !dbg [[NOINLINE_VTABLE_VAR:![0-9]+]]
+// CHECK-HAS-DTOR-DAG: @_ZTV8CNoFnDef = external {{.*}}constant {{{ \[[^]]*\] }}}, align 8
+
+// CHECK-HAS-DTOR: !llvm.dbg.cu
+
+// CHECK-HAS-DTOR-DAG: [[INLINED_VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CInlined"
+// CHECK-HAS-DTOR-DAG: [[INLINED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[INLINED_VTABLE]], expr: !DIExpression())
+// CHECK-HAS-DTOR-DAG: [[INLINED:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CInlined"
+// CHECK-HAS-DTOR-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[INLINED]], file: {{.*}}, baseType: {{![0-9]+}}, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+
+// CHECK-HAS-DTOR-DAG: [[NOINLINE_VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CNoInline"
+// CHECK-HAS-DTOR-DAG: [[NOINLINE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[NOINLINE_VTABLE]], expr: !DIExpression())
+// CHECK-HAS-DTOR-DAG: [[NOINLINE:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CNoInline"
+// CHECK-HAS-DTOR-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[NOINLINE]], file: {{.*}}, baseType: {{![0-9]+}}, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+
+// CHECK-HAS-DTOR-DAG: !llvm.ident
+
+// CHECK-HAS-DTOR-NOT: !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CNoFnDef"
+
+
+// CHECK-NO-DTOR-NOT: $_ZTV8CInlined
+// CHECK-NO-DTOR-NOT: $_ZTV9CNoInline
+// CHECK-NO-DTOR-NOT: $_ZTV8CNoFnDef
+
+// CHECK-NO-DTOR-DAG: @_ZTV8CInlined = external {{.*}}constant {{.*}}, align 8{{$}}
+// CHECK-NO-DTOR-DAG: @_ZTV9CNoInline = {{.*}}constant {{{ \[[^]]*\] } { \[[^]]*\] \[[^]]*\] }}}, align 8, !dbg [[NOINLINE_VTABLE_VAR:![0-9]+]]
+// CHECK-NO-DTOR-DAG: @_ZTV8CNoFnDef = external {{.*}}constant {{{ \[[^]]*\] }}}, align 8, !dbg [[NOFNDEF_VTABLE_VAR:![0-9]+]]
+
+// CHECK-NO-DTOR: !llvm.dbg.cu
+
+// CHECK-NO-DTOR-DAG: [[NOINLINE_VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CNoInline"
+// CHECK-NO-DTOR-DAG: [[NOINLINE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[NOINLINE_VTABLE]], expr: !DIExpression())
+// CHECK-NO-DTOR-DAG: [[NOINLINE:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CNoInline"
+// CHECK-NO-DTOR-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[NOINLINE]], file: {{.*}}, baseType: {{![0-9]+}}, flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+
+// CHECK-NO-DTOR-DAG: !llvm.ident
+
+// CHECK-NO-DTOR-NOT: !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CInlined"
+// CHECK-NO-DTOR-NOT: !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CNoFnDef"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp
index 5ed1353eebb10..53a24a2d1b15e 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-diamond.cpp
@@ -1,5 +1,3 @@
-// REQUIRES: target={{x86_64.*-linux.*}}
-
 // Diamond inheritance case:
 // For CBase, CLeft, CRight and CDerived we check:
 // - Generation of their vtables (including attributes).
@@ -35,26 +33,29 @@ struct CDerived : NSP_1::CLeft, NSP_2::CRight {
   int fooDerived() { return 3; };
 };
 
+void use(void *, ...);
+
 int main() {
   NSP::CBase Base;
   NSP_1::CLeft Left;
   NSP_2::CRight Right;
   CDerived Derived;
+  use(&Base, &Left, &Right, &Derived);
 
   return 0;
 }
 
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s
 
 // CHECK: $_ZTVN3NSP5CBaseE = comdat any
 // CHECK: $_ZTVN5NSP_15CLeftE = comdat any
 // CHECK: $_ZTVN5NSP_26CRightE = comdat any
 // CHECK: $_ZTV8CDerived = comdat any
 
-// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTV8CDerived = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
 
 // CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
 // CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp
index 23973a35d0e17..69fa096324651 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-multiple.cpp
@@ -1,5 +1,3 @@
-// REQUIRES: target={{x86_64.*-linux.*}}
-
 // Multiple inheritance case:
 // For CBaseOne, CBaseTwo and CDerived we check:
 // - Generation of their vtables (including attributes).
@@ -30,23 +28,25 @@ struct CDerived : NSP_1::CBaseOne, NSP_2::CBaseTwo {
   int six() override { return 66; }
 };
 
+void use(void *, ...);
 int main() {
   NSP_1::CBaseOne BaseOne;
   NSP_2::CBaseTwo BaseTwo;
   CDerived Derived;
+  use(&BaseOne, &BaseTwo, &Derived);
 
   return 0;
 }
 
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s
 
 // CHECK: $_ZTVN5NSP_18CBaseOneE = comdat any
 // CHECK: $_ZTVN5NSP_28CBaseTwoE = comdat any
 // CHECK: $_ZTV8CDerived = comdat any
 
-// CHECK: @_ZTVN5NSP_18CBaseOneE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_ONE_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTVN5NSP_28CBaseTwoE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_TWO_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_18CBaseOneE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_ONE_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_28CBaseTwoE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_TWO_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTV8CDerived = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
 
 // CHECK: [[BASE_ONE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_ONE_VTABLE:![0-9]*]], expr: !DIExpression())
 // CHECK-NEXT: [[BASE_ONE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_18CBaseOneE"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
index d64e711dddfa0..5d93719b60699 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple-main.cpp
@@ -1,5 +1,3 @@
-// REQUIRES: target={{x86_64.*-linux.*}}
-
 // Simple inheritance case:
 // For CBase and CDerived we check:
 // - Generation of their vtables (including attributes).
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
index 249586f5991f1..a0485f48ab8b8 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-simple.cpp
@@ -23,20 +23,23 @@ struct CDerived : NSP::CBase {
   int three() override { return 33; }
 };
 
+void use(void *, ...);
+
 int main() {
   NSP::CBase Base;
   CDerived Derived;
+  use(&Base, &Derived);
 
   return 0;
 }
 
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s
 
 // CHECK: $_ZTVN3NSP5CBaseE = comdat any
 // CHECK: $_ZTV8CDerived = comdat any
 
-// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTV8CDerived = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
 
 // CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
 // CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
index b01f156b7f654..fc8c15aabd616 100644
--- a/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
+++ b/clang/test/CodeGenCXX/vtable-debug-info-inheritance-virtual.cpp
@@ -1,5 +1,3 @@
-// REQUIRES: target={{x86_64.*-linux.*}}
-
 // Virtual inheritance case:
 // For CBase, CLeft, CRight and CDerived we check:
 // - Generation of their vtables (including attributes).
@@ -35,26 +33,29 @@ struct CDerived : NSP_1::CLeft, NSP_2::CRight {
   int fooDerived() { return 3; };
 };
 
+void use(void *, ...);
+
 int main() {
   NSP::CBase Base;
   NSP_1::CLeft Left;
   NSP_2::CRight Right;
   CDerived Derived;
+  use(&Base, &Left, &Right, &Derived);
 
   return 0;
 }
 
-// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s
 
 // CHECK: $_ZTVN3NSP5CBaseE = comdat any
 // CHECK: $_ZTVN5NSP_15CLeftE = comdat any
 // CHECK: $_ZTVN5NSP_26CRightE = comdat any
 // CHECK: $_ZTV8CDerived = comdat any
 
-// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]]
-// CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]]
+// CHECK: @_ZTV8CDerived = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]]
 
 // CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression())
 // CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE"
diff --git a/clang/test/CodeGenCXX/vtable-debug-info-template-instantiation.cpp b/clang/test/CodeGenCXX/vtable-debug-info-template-instantiation.cpp
new file mode 100644
index 0000000000000..2f02861c7f465
--- /dev/null
+++ b/clang/test/CodeGenCXX/vtable-debug-info-template-instantiation.cpp
@@ -0,0 +1,88 @@
+// For CTemplate we check in case of:
+// - Implicitly instantiate whole class by up-casting:
+//   * The vtable is generated with comdat
+//   * Its '_vtable$' is generated
+// - Implicitly instantiate member function only:
+//   * The vtable is NOT generated
+//   * Its '_vtable$' is generated
+// - Define explicitly instantiation:
+//   * The vtable is generated with comdat
+//   * Its '_vtable$' is generated
+// - Declare explicitly instantiation as extern:
+//  # for COFF targets:
+//   * The vtable is declared but NOT associated with '_vtable$'
+//  # for non-COFF targets:
+//   * The vtable is declared
+//   * Its '_vtable$' is generated
+
+struct CBase {
+  virtual void f() noexcept {}
+};
+
+template <typename T>
+struct CTemplate: CBase {
+  void f() noexcept override;
+  virtual ~CTemplate() noexcept;
+};
+template <typename T>
+void CTemplate<T>::f() noexcept {}
+template <typename T>
+CTemplate<T>::~CTemplate() noexcept {}
+
+#ifdef EXPLICIT
+template struct CTemplate<void>;
+#endif
+#ifdef EXTERN
+extern template struct CTemplate<void>;
+#endif
+
+CTemplate<void> *get(CBase *) noexcept;
+
+int main() {
+  CTemplate<void> Template;
+#ifdef NOCAST
+  get(nullptr)->f();
+#else
+  get(&Template)->f();
+#endif
+
+  return 0;
+}
+
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o -             | FileCheck %s -check-prefix IMPLICIT
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - -DNOCAST    | FileCheck %s -check-prefix NOCAST
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - -DEXPLICIT  | FileCheck %s -check-prefix EXPLICIT
+// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - -DEXTERN    | FileCheck %s -check-prefix EXTERN
+
+// IMPLICIT: $_ZTV9CTemplateIvE = comdat any
+// IMPLICIT: @_ZTV9CTemplateIvE = linkonce_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[VTABLE_VAR:![0-9]*]]
+// IMPLICIT-DAG: [[VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CTemplateIvE"
+// IMPLICIT-DAG: !DIGlobalVariableExpression(var: [[VTABLE]], expr: !DIExpression())
+// IMPLICIT-DAG: [[TYPE:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CTemplate<void>"
+// IMPLICIT-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[TYPE]], file: {{.*}}, baseType: [[PVOID:![0-9]+]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// IMPLICIT-DAG: [[PVOID]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// NOCAST-NOT: $_ZTV9CTemplateIvE
+// NOCAST-NOT: @_ZTV9CTemplateIvE
+// NOCAST-DAG: [[VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CTemplateIvE"
+// NOCAST-DAG: !DIGlobalVariableExpression(var: [[VTABLE]], expr: !DIExpression())
+// NOCAST-DAG: [[TYPE:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CTemplate<void>"
+// NOCAST-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[TYPE]], file: {{.*}}, baseType: [[PVOID:![0-9]+]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// NOCAST-DAG: [[PVOID]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// EXPLICIT: $_ZTV9CTemplateIvE = comdat any
+// EXPLICIT: @_ZTV9CTemplateIvE = weak_odr {{.*}}unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[VTABLE_VAR:![0-9]*]]
+// EXPLICIT-DAG: [[VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CTemplateIvE"
+// EXPLICIT-DAG: [[VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[VTABLE]], expr: !DIExpression())
+// EXPLICIT-DAG: [[TYPE:![0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CTemplate<void>"
+// EXPLICIT-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[TYPE]], file: {{.*}}, baseType: [[PVOID:![0-9]+]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// EXPLICIT-DAG: [[PVOID]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+
+// EXTERN-NOT: $_ZTV9CTemplateIvE
+// EXTERN: @_ZTV9CTemplateIvE = external {{.*}}unnamed_addr constant {{.*}}, align 8, !dbg [[VTABLE_VAR:![0-9]*]]
+// EXTERN-DAG: [[VTABLE:![0-9]+]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV9CTemplateIvE"
+// EXTERN-DAG: [[VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[VTABLE]], expr: !DIExpression())
+// EXTERN-DAG: [[TYPE:![0-9]+]] = !DICompositeType(tag: DW_TAG_structure_type, name: "CTemplate<void>"
+// EXTERN-DAG: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[TYPE]], file: {{.*}}, baseType: [[PVOID:![0-9]+]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember)
+// EXTERN-DAG: [[PVOID]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
+

@kikairoya kikairoya force-pushed the add-vtable-debuginfo-tests branch from 1c98eaa to 429fa5d Compare August 6, 2025 09:37
@CarlosAlbertoEnciso
Copy link
Member

@kikairoya I am sorry for my delay but currently I am on PTO. I will have a look early next week.

@CarlosAlbertoEnciso
Copy link
Member

It seems that there are conflicts that must be resolved.

Copy link
Member

@CarlosAlbertoEnciso CarlosAlbertoEnciso left a comment

Choose a reason for hiding this comment

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

Are you removing the REQUIRES because #150938 (platforms that don't generate DWARF)?

Add test for:
- shows effect of inlining member functions
- shows effect of template instantiation methods

Make cleaner a bit:
- drops unnecessary REQUIRES clause
- uses %clang_cc1 instead of %clang -Xclang
- uses simply -O1 instead of -disable-O0-optnone -disable-llvm-passes
  * LTO test remains unchanged since replacing by -O1 changes output even if variables are anchored
@kikairoya kikairoya force-pushed the add-vtable-debuginfo-tests branch from 429fa5d to ed08f7d Compare August 22, 2025 21:59
@kikairoya
Copy link
Contributor Author

Thank you for looking this.

Are you removing the REQUIRES because #150938 (platforms that don't generate DWARF)?

I believe these tests should be run in any configuration because they can be run. And, yes, we'll need to cover COFF cases, which will be added in a next PR.

@CarlosAlbertoEnciso
Copy link
Member

CarlosAlbertoEnciso commented Aug 28, 2025

The tests look good.
Just a minor point: the original tests assumed normal debug info generation. Now they use -debug-info-kind=limited -dwarf-version=5 -O1. Can we run the tests with the original options and the new ones? Any specific reason for the options change?

Copy link
Member

@jmorse jmorse left a comment

Choose a reason for hiding this comment

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

I think adding / adjusting this coverage is good -- a few questions / requests inline.


return 0;
}

// RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux -emit-llvm -debug-info-kind=limited -dwarf-version=5 -O1 %s -o - | FileCheck %s
Copy link
Member

Choose a reason for hiding this comment

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

Is the use of -O1 needed here? Ideally we would only test clang behaviours in the clang tests, without making use of LLVM transformations as well. If it's necessary to cover optimisation behaviours, we might need specific tests in the llvm/test directory. (Similar with a few RUN lines below).

(This is a neatness objective rather than something specifically technical).

Comment on lines +1 to +3
// The debug info of vtable is attached conditionally to whether
// - Member functions are inlined or not
// - Definition of destructor is visible or not
Copy link
Member

Choose a reason for hiding this comment

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

Would you be able to give a sentence summarising what the CHECK-lines below are seeking, i.e. "expect to see the variable attached to...", as it's hard to immediately work out what's being checked. Something like your leading comment on vtable-template-instantiation.cpp. This'll help a lot if we come to refactoring the representation in metadata.

@@ -1,5 +1,3 @@
// REQUIRES: target={{x86_64.*-linux.*}}
Copy link
Member

Choose a reason for hiding this comment

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

Do the RUN lines need updating to not hard-code the x86_64 triple too? Otherwise buildbots that don't build for x86 might trip up on this? Broadening out this test coverage to not be fixed on x86 is a good plan.

Comment on lines +1 to +16
// For CTemplate we check in case of:
// - Implicitly instantiate whole class by up-casting:
// * The vtable is generated with comdat
// * Its '_vtable$' is generated
// - Implicitly instantiate member function only:
// * The vtable is NOT generated
// * Its '_vtable$' is generated
// - Define explicitly instantiation:
// * The vtable is generated with comdat
// * Its '_vtable$' is generated
// - Declare explicitly instantiation as extern:
// # for COFF targets:
// * The vtable is declared but NOT associated with '_vtable$'
// # for non-COFF targets:
// * The vtable is declared
// * Its '_vtable$' is generated
Copy link
Member

Choose a reason for hiding this comment

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

To confirm my understanding -- what's interesting here is that the _vtable$ variable is generated in various scenarios where the vtable itself isn't generated -- thus the test is checking that _vtable$ references are generated for an external symbol?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants