From 64edc01755f77f95e324522824f0cac787bcf35e Mon Sep 17 00:00:00 2001
From: David Blaikie <dblaikie@gmail.com>
Date: Mon, 23 Jan 2017 02:24:03 +0000
Subject: [PATCH] DebugInfo: Omit class definitions even in the presence of
 available_externally vtables

To ensure optimization level doesn't pessimize the -fstandalone-debug
vtable debug info optimization (where class definitions are only emitted
where the vtable is emitted - reducing redundant debug info) ensure the
debug info class definition is still omitted when an
available_externally vtable definition is emitted for optimization
purposes.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@292768 91177308-0d34-0410-b5e6-96231b3b80d8
---
 lib/CodeGen/CGDebugInfo.cpp                 | 29 ++++++++++++++-------
 lib/CodeGen/CGDebugInfo.h                   |  1 +
 lib/CodeGen/CGVTables.cpp                   |  7 ++---
 test/CodeGenCXX/debug-info-class-optzns.cpp | 16 ++++++++++++
 4 files changed, 40 insertions(+), 13 deletions(-)
 create mode 100644 test/CodeGenCXX/debug-info-class-optzns.cpp

diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp
index c3dd53f12e2..702ae01acf3 100644
--- a/lib/CodeGen/CGDebugInfo.cpp
+++ b/lib/CodeGen/CGDebugInfo.cpp
@@ -1714,7 +1714,26 @@ void CGDebugInfo::completeType(const RecordDecl *RD) {
     completeRequiredType(RD);
 }
 
+/// Return true if the class or any of its methods are marked dllimport.
+static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
+  if (RD->hasAttr<DLLImportAttr>())
+    return true;
+  for (const CXXMethodDecl *MD : RD->methods())
+    if (MD->hasAttr<DLLImportAttr>())
+      return true;
+  return false;
+}
+
 void CGDebugInfo::completeClassData(const RecordDecl *RD) {
+  if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+    if (CGM.getVTableLinkage(CXXRD) ==
+            llvm::GlobalValue::AvailableExternallyLinkage &&
+        !isClassOrMethodDLLImport(CXXRD))
+      return;
+  completeClass(RD);
+}
+
+void CGDebugInfo::completeClass(const RecordDecl *RD) {
   if (DebugKind <= codegenoptions::DebugLineTablesOnly)
     return;
   QualType Ty = CGM.getContext().getRecordType(RD);
@@ -1760,16 +1779,6 @@ static bool isDefinedInClangModule(const RecordDecl *RD) {
   return true;
 }
 
-/// Return true if the class or any of its methods are marked dllimport.
-static bool isClassOrMethodDLLImport(const CXXRecordDecl *RD) {
-  if (RD->hasAttr<DLLImportAttr>())
-    return true;
-  for (const CXXMethodDecl *MD : RD->methods())
-    if (MD->hasAttr<DLLImportAttr>())
-      return true;
-  return false;
-}
-
 static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind,
                                  bool DebugTypeExtRefs, const RecordDecl *RD,
                                  const LangOptions &LangOpts) {
diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h
index ac2e8dd2e0a..ea451d0548c 100644
--- a/lib/CodeGen/CGDebugInfo.h
+++ b/lib/CodeGen/CGDebugInfo.h
@@ -409,6 +409,7 @@ public:
   void completeType(const RecordDecl *RD);
   void completeRequiredType(const RecordDecl *RD);
   void completeClassData(const RecordDecl *RD);
+  void completeClass(const RecordDecl *RD);
 
   void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD);
 
diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp
index 04c5cfe5365..24c7f15a084 100644
--- a/lib/CodeGen/CGVTables.cpp
+++ b/lib/CodeGen/CGVTables.cpp
@@ -744,9 +744,10 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
     switch (keyFunction->getTemplateSpecializationKind()) {
       case TSK_Undeclared:
       case TSK_ExplicitSpecialization:
-        assert((def || CodeGenOpts.OptimizationLevel > 0) &&
-               "Shouldn't query vtable linkage without key function or "
-               "optimizations");
+        assert((def || CodeGenOpts.OptimizationLevel > 0 ||
+                CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo) &&
+               "Shouldn't query vtable linkage without key function, "
+               "optimizations, or debug info");
         if (!def && CodeGenOpts.OptimizationLevel > 0)
           return llvm::GlobalVariable::AvailableExternallyLinkage;
 
diff --git a/test/CodeGenCXX/debug-info-class-optzns.cpp b/test/CodeGenCXX/debug-info-class-optzns.cpp
new file mode 100644
index 00000000000..08f045659bc
--- /dev/null
+++ b/test/CodeGenCXX/debug-info-class-optzns.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -triple x86_64-unknown_unknown -emit-llvm -debug-info-kind=limited %s -O1 -o - | FileCheck %s
+
+// Ensure class definitions are not emitted to debug info just because the
+// vtable is emitted for optimization purposes (as available_externally). The
+// class definition debug info should only go where the vtable is actually
+// emitted into the object file.
+
+// CHECK: @_ZTV3foo = available_externally
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "foo"
+// CHECK-SAME: DIFlagFwdDecl
+
+struct foo {
+  virtual void f();
+};
+
+foo f;
-- 
GitLab