From 0a050f7d56039bab7556e08b359e06d329977b6b Mon Sep 17 00:00:00 2001 From: Adrian Prantl Date: Thu, 9 May 2013 23:16:27 +0000 Subject: [PATCH] Debug Info: Fix a problem that resulted in missing DW_AT_specifications for C++ constructors. If the DIType for a class was generated by CGDebugInfo::createContextChain(), the cache contains only a limited DIType wihtout any declarations. Since EmitFunctionStart() needs to find the canonical declaration for each method, we construct the complete type before emitting any method. rdar://problem/13116508 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181561 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenModule.cpp | 18 +++++++ lib/CodeGen/CodeGenModule.h | 1 + test/CodeGenCXX/debug-info-decl-nested.cpp | 61 ++++++++++++++++++++++ 3 files changed, 80 insertions(+) create mode 100644 test/CodeGenCXX/debug-info-decl-nested.cpp diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 1da4e87c0a..717ed17dd4 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -1232,6 +1232,23 @@ CodeGenModule::shouldEmitFunction(const FunctionDecl *F) { return !isTriviallyRecursive(F); } +/// If the type for the method's class was generated by +/// CGDebugInfo::createContextChain(), the cache contains only a +/// limited DIType without any declarations. Since EmitFunctionStart() +/// needs to find the canonical declaration for each method, we need +/// to construct the complete type prior to emitting the method. +void CodeGenModule::CompleteDIClassType(const CXXMethodDecl* D) { + if (!D->isInstance()) + return; + + if (CGDebugInfo *DI = getModuleDebugInfo()) + if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { + const PointerType *ThisPtr = + cast(D->getThisType(getContext())); + DI->getOrCreateRecordType(ThisPtr->getPointeeType(), D->getLocation()); + } +} + void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { const ValueDecl *D = cast(GD.getDecl()); @@ -1246,6 +1263,7 @@ void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) { return; if (const CXXMethodDecl *Method = dyn_cast(D)) { + CompleteDIClassType(Method); // Make sure to emit the definition(s) before we emit the thunks. // This is necessary for the generation of certain thunks. if (const CXXConstructorDecl *CD = dyn_cast(Method)) diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 1d6c7e98e5..e4e29a8d6b 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -1025,6 +1025,7 @@ private: void EmitNamespace(const NamespaceDecl *D); void EmitLinkageSpec(const LinkageSpecDecl *D); + void CompleteDIClassType(const CXXMethodDecl* D); /// EmitCXXConstructors - Emit constructors (base, complete) from a /// C++ constructor Decl. diff --git a/test/CodeGenCXX/debug-info-decl-nested.cpp b/test/CodeGenCXX/debug-info-decl-nested.cpp new file mode 100644 index 0000000000..7c8bd1facf --- /dev/null +++ b/test/CodeGenCXX/debug-info-decl-nested.cpp @@ -0,0 +1,61 @@ +// RUN: %clang_cc1 -std=c++11 -g -O0 -emit-llvm -g -triple x86_64-apple-darwin %s -o %t +// RUN: cat %t | FileCheck %s -check-prefix=CHECK0 +// RUN: cat %t | FileCheck %s -check-prefix=CHECK1 +// RUN: cat %t | FileCheck %s -check-prefix=CHECK2 +// +// This test ensures that we associate a declaration with the +// definition of the constructor for OuterClass. The declaration is +// necessary so the backend can emit the DW_AT_specification attribute +// for the definition. +// +// rdar://problem/13116508 + +class Foo; +class OuterClass +{ + static class InnerClass { + public: + InnerClass(); // Here createContextChain() generates a limited type for OuterClass. + } theInnerClass; +// CHECK0: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [OuterClass] + OuterClass(const Foo *); // line 10 +}; +OuterClass::InnerClass OuterClass::theInnerClass; // This toplevel decl causes InnerClass to be generated. +// CHECK0: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [OuterClass] +OuterClass::OuterClass(const Foo *meta) { } // line 13 + + + + + +class Foo1; +class OuterClass1 +{ + static class InnerClass1 { + public: + InnerClass1(); + } theInnerClass1; +// CHECK1: metadata {{.*}}, metadata ![[DECL:[0-9]+]], metadata {{.*}}, i32 [[@LINE+5]]} ; [ DW_TAG_subprogram ] [line [[@LINE+5]]] [def] [Bar] + void Bar(const Foo1 *); +}; +OuterClass1::InnerClass1 OuterClass1::theInnerClass1; +// CHECK1: [[DECL]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE-3]]] [private] [Bar] +void OuterClass1::Bar(const Foo1 *meta) { } + + + + + +class Foo2; +class OuterClass2 +{ + static class InnerClass2 { + public: + InnerClass2(); + } theInnerClass2; +// CHECK2: [[DECL:[0-9]+]] = {{.*}} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [private] [~OuterClass2] + ~OuterClass2(); // line 10 +}; +OuterClass2::InnerClass2 OuterClass2::theInnerClass2; +// CHECK2: metadata {{.*}}, metadata ![[DECL]], metadata {{.*}}, i32 [[@LINE+1]]} ; [ DW_TAG_subprogram ] [line [[@LINE+1]]] [def] [~OuterClass2] +OuterClass2::~OuterClass2() { } -- 2.40.0