<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Fri, Oct 11, 2013 at 12:51 PM, Manman Ren <span dir="ltr"><<a href="mailto:manman.ren@gmail.com" target="_blank">manman.ren@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">Hi, David<div><br></div><div>I just noticed this has great size reduction on xalan (a SPEC benchmark), thanks for the work.</div>
<div>The number of MDNodes in a lto debug build decreased from 29M to 12M.</div></div></blockquote><div><br></div><div>Great - thanks for the stats.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr">
<div>This may degrade the debugger's speed since we are now emitting declarations instead of definitions, and the debugger will have to search for the definition.<br></div></div></blockquote><div><br></div><div>Perhaps. I suppose moreso on Apple platforms where debug info isn't linked, so searching multiple object files' debug info could be more costly. But do the accelerator tables handle this by making it easy to find the object file with the definition?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div></div><div>One example is building XercesWrapperNavigator.cpp with -O0 -g, we are now emitting a forward declaration for XercesDocumentWrapper.</div>

<div>XercesWrapperNavigator has a member (m_d) pointing to XercesDocumentWrapper, and we call m_d->func() inside XercesWrapperNavigator.cpp.<br></div></div></blockquote><div><br></div><div>Do you have any evidence that this adversely affects debugger performance?</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div></div><div>Is it reasonable for this commit to be enabled only for limit-debug-info, when no-limit-debug-info is on, we don't see effects of this patch?<br>
</div></div></blockquote><div><br></div><div>GCC does this by default, at least on Linux - I haven't tested on MacOS. I would guess it does so there too (but as you point out, there are different tradeoffs there, so I might be wrong).<br>
<br> I'd like to understand the performance tradeoff to justify such a large regression in debug info size (it's worth about ~20% on Clang/LLVM based on my experiments).<br><br>- David</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<div dir="ltr"><div></div>
<div><br></div><div>Thanks,</div><div>Manman</div><div><br></div></div><div class=""><div class="h5"><div class="gmail_extra"><br><br><div class="gmail_quote">On Mon, Aug 19, 2013 at 6:28 PM, David Blaikie <span dir="ltr"><<a href="mailto:dblaikie@gmail.com" target="_blank">dblaikie@gmail.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">Author: dblaikie<br>
Date: Mon Aug 19 20:28:15 2013<br>
New Revision: 188739<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=188739&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=188739&view=rev</a><br>
Log:<br>
Revert "Revert "Revert "Revert "DebugInfo: Omit debug info for dynamic classes in TUs that do not have the vtable for that class""""<br>
<br>
This reverts commit r188687 (reverts r188642 (reverts 188600 (reverts<br>
188576))).<br>
<br>
With added test coverage & fix for -gline-tables-only.<br>
<br>
Thanks Michael Gottesman for reverting this patch when it demonstrated<br>
problems & providing a reproduction/details to help me track this down.<br>
<br>
Modified:<br>
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp<br>
    cfe/trunk/lib/CodeGen/CGDebugInfo.h<br>
    cfe/trunk/lib/CodeGen/CGVTables.cpp<br>
    cfe/trunk/test/CodeGenCXX/debug-info-class.cpp<br>
    cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=188739&r1=188738&r2=188739&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=188739&r1=188738&r2=188739&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Mon Aug 19 20:28:15 2013<br>
@@ -644,8 +644,24 @@ llvm::DIDescriptor CGDebugInfo::createCo<br>
<br>
   if (const RecordDecl *RD = dyn_cast<RecordDecl>(Context)) {<br>
     if (!RD->isDependentType()) {<br>
-      llvm::DIType Ty = getOrCreateLimitedType(<br>
-          CGM.getContext().getRecordType(RD)->castAs<RecordType>(), getOrCreateMainFile());<br>
+      llvm::DICompositeType T(getTypeOrNull(CGM.getContext().getRecordType(RD)));<br>
+      llvm::DICompositeType Ty(getOrCreateLimitedType(<br>
+          CGM.getContext().getRecordType(RD)->castAs<RecordType>(),<br>
+          getOrCreateMainFile()));<br>
+      if (!Ty.getTypeArray().getNumElements()) {<br>
+        if (T) {<br>
+          llvm::DIArray PrevMem = T.getTypeArray();<br>
+          unsigned NumElements = PrevMem.getNumElements();<br>
+          if (NumElements == 1 && !PrevMem.getElement(0))<br>
+            NumElements = 0;<br>
+          SmallVector<llvm::Value *, 16> EltTys;<br>
+          EltTys.reserve(NumElements);<br>
+          for (unsigned i = 0; i != NumElements; ++i)<br>
+            EltTys.push_back(PrevMem.getElement(i));<br>
+          llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys);<br>
+          Ty.setTypeArray(Elements);<br>
+        }<br>
+      }<br>
       return llvm::DIDescriptor(Ty);<br>
     }<br>
   }<br>
@@ -865,7 +881,7 @@ CollectRecordLambdaFields(const CXXRecor<br>
   }<br>
 }<br>
<br>
-/// CollectRecordStaticField - Helper for CollectRecordFields.<br>
+/// Helper for CollectRecordFields.<br>
 llvm::DIDerivedType<br>
 CGDebugInfo::CreateRecordStaticField(const VarDecl *Var,<br>
                                      llvm::DIType RecordTy) {<br>
@@ -948,7 +964,7 @@ void CGDebugInfo::CollectRecordFields(co<br>
     for (RecordDecl::decl_iterator I = record->decls_begin(),<br>
            E = record->decls_end(); I != E; ++I)<br>
       if (const VarDecl *V = dyn_cast<VarDecl>(*I))<br>
-        elements.push_back(CreateRecordStaticField(V, RecordTy));<br>
+        elements.push_back(getOrCreateStaticDataMemberDeclaration(V, RecordTy));<br>
       else if (FieldDecl *field = dyn_cast<FieldDecl>(*I)) {<br>
         CollectRecordNormalField(field, layout.getFieldOffset(fieldNo),<br>
                                  tunit, elements, RecordTy);<br>
@@ -1123,8 +1139,14 @@ CollectCXXMemberFunctions(const CXXRecor<br>
     if (D->isImplicit())<br>
       continue;<br>
<br>
-    if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D))<br>
-      EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));<br>
+    if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) {<br>
+      llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator MI =<br>
+          SPCache.find(Method->getCanonicalDecl());<br>
+      if (MI == SPCache.end())<br>
+        EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy));<br>
+      else<br>
+        EltTys.push_back(MI->second);<br>
+    }<br>
   }<br>
 }<br>
<br>
@@ -1408,10 +1430,20 @@ void CGDebugInfo::completeType(const Rec<br>
 }<br>
<br>
 void CGDebugInfo::completeRequiredType(const RecordDecl *RD) {<br>
+  if (const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD))<br>
+    if (CXXDecl->isDynamicClass())<br>
+      return;<br>
+<br>
   QualType Ty = CGM.getContext().getRecordType(RD);<br>
   llvm::DIType T = getTypeOrNull(Ty);<br>
-  if (!T || !T.isForwardDecl())<br>
+  if (T && T.isForwardDecl())<br>
+    completeClassData(RD);<br>
+}<br>
+<br>
+void CGDebugInfo::completeClassData(const RecordDecl *RD) {<br>
+  if (DebugKind <= CodeGenOptions::DebugLineTablesOnly)<br>
     return;<br>
+  QualType Ty = CGM.getContext().getRecordType(RD);<br>
   void* TyPtr = Ty.getAsOpaquePtr();<br>
   if (CompletedTypeCache.count(TyPtr))<br>
     return;<br>
@@ -1424,14 +1456,23 @@ void CGDebugInfo::completeRequiredType(c<br>
 /// CreateType - get structure or union type.<br>
 llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty, bool Declaration) {<br>
   RecordDecl *RD = Ty->getDecl();<br>
+  const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD);<br>
   // Limited debug info should only remove struct definitions that can<br>
   // safely be replaced by a forward declaration in the source code.<br>
-  if (DebugKind <= CodeGenOptions::LimitedDebugInfo && Declaration &&<br>
-      !RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) {<br>
+  if ((DebugKind <= CodeGenOptions::LimitedDebugInfo && Declaration &&<br>
+       !RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) ||<br>
+      (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())) {<br>
     llvm::DIDescriptor FDContext =<br>
       getContextDescriptor(cast<Decl>(RD->getDeclContext()));<br>
     llvm::DIType RetTy = getOrCreateRecordFwdDecl(RD, FDContext);<br>
-    return RetTy;<br>
+    // FIXME: This is conservatively correct. If we return a non-forward decl<br>
+    // that's not a full definition (such as those created by<br>
+    // createContextChain) then getOrCreateType will record is as a complete<br>
+    // type and we'll never record all its members. But this means we're<br>
+    // emitting full debug info in TUs where GCC successfully emits a partial<br>
+    // definition of the type.<br>
+    if (RetTy.isForwardDecl())<br>
+      return RetTy;<br>
   }<br>
<br>
   return CreateTypeDefinition(Ty);<br>
@@ -1469,6 +1510,7 @@ llvm::DIType CGDebugInfo::CreateTypeDefi<br>
<br>
   // Convert all the elements.<br>
   SmallVector<llvm::Value *, 16> EltTys;<br>
+  // what about nested types?<br>
<br>
   // Note: The split of CXXDecl information here is intentional, the<br>
   // gdb tests will depend on a certain ordering at printout. The debug<br>
@@ -2310,7 +2352,7 @@ llvm::DISubprogram CGDebugInfo::getFunct<br>
   llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator<br>
     MI = SPCache.find(FD->getCanonicalDecl());<br>
   if (MI == SPCache.end()) {<br>
-    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {<br>
+    if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD->getCanonicalDecl())) {<br>
       llvm::DICompositeType T(S);<br>
       llvm::DISubprogram SP = CreateCXXMemberFunction(MD, getOrCreateFile(MD->getLocation()), T);<br>
       T.addMember(SP);<br>
@@ -3025,19 +3067,35 @@ void CGDebugInfo::EmitDeclareOfBlockLite<br>
   DbgDecl->setDebugLoc(llvm::DebugLoc::get(line, column, scope));<br>
 }<br>
<br>
-/// getStaticDataMemberDeclaration - If D is an out-of-class definition of<br>
-/// a static data member of a class, find its corresponding in-class<br>
-/// declaration.<br>
-llvm::DIDerivedType CGDebugInfo::getStaticDataMemberDeclaration(const VarDecl *D) {<br>
-  if (D->isStaticDataMember()) {<br>
-    llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator<br>
-      MI = StaticDataMemberCache.find(D->getCanonicalDecl());<br>
-    if (MI != StaticDataMemberCache.end())<br>
-      // Verify the info still exists.<br>
-      if (llvm::Value *V = MI->second)<br>
-        return llvm::DIDerivedType(cast<llvm::MDNode>(V));<br>
+/// If D is an out-of-class definition of a static data member of a class, find<br>
+/// its corresponding in-class declaration.<br>
+llvm::DIDerivedType<br>
+CGDebugInfo::getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D) {<br>
+  if (!D->isStaticDataMember())<br>
+    return llvm::DIDerivedType();<br>
+  llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =<br>
+      StaticDataMemberCache.find(D->getCanonicalDecl());<br>
+  if (MI != StaticDataMemberCache.end()) {<br>
+    assert(MI->second && "Static data member declaration should still exist");<br>
+    return llvm::DIDerivedType(cast<llvm::MDNode>(MI->second));<br>
+  }<br>
+  llvm::DICompositeType Ctxt(<br>
+      getContextDescriptor(cast<Decl>(D->getDeclContext())));<br>
+  llvm::DIDerivedType T = CreateRecordStaticField(D, Ctxt);<br>
+  Ctxt.addMember(T);<br>
+  return T;<br>
+}<br>
+<br>
+llvm::DIDerivedType<br>
+CGDebugInfo::getOrCreateStaticDataMemberDeclaration(const VarDecl *D,<br>
+                                            llvm::DICompositeType Ctxt) {<br>
+  llvm::DenseMap<const Decl *, llvm::WeakVH>::iterator MI =<br>
+      StaticDataMemberCache.find(D->getCanonicalDecl());<br>
+  if (MI != StaticDataMemberCache.end()) {<br>
+    assert(MI->second && "Static data member declaration should still exist");<br>
+    return llvm::DIDerivedType(cast<llvm::MDNode>(MI->second));<br>
   }<br>
-  return llvm::DIDerivedType();<br>
+  return CreateRecordStaticField(D, Ctxt);<br>
 }<br>
<br>
 /// EmitGlobalVariable - Emit information about a global variable.<br>
@@ -3069,11 +3127,10 @@ void CGDebugInfo::EmitGlobalVariable(llv<br>
     LinkageName = StringRef();<br>
   llvm::DIDescriptor DContext =<br>
     getContextDescriptor(dyn_cast<Decl>(D->getDeclContext()));<br>
-  llvm::DIGlobalVariable GV =<br>
-      DBuilder.createStaticVariable(DContext, DeclName, LinkageName, Unit,<br>
-                                    LineNo, getOrCreateType(T, Unit),<br>
-                                    Var->hasInternalLinkage(), Var,<br>
-                                    getStaticDataMemberDeclaration(D));<br>
+  llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(<br>
+      DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),<br>
+      Var->hasInternalLinkage(), Var,<br>
+      getOrCreateStaticDataMemberDeclarationOrNull(D));<br>
   DeclCache.insert(std::make_pair(D->getCanonicalDecl(), llvm::WeakVH(GV)));<br>
 }<br>
<br>
@@ -3121,7 +3178,7 @@ void CGDebugInfo::EmitGlobalVariable(con<br>
     return;<br>
   llvm::DIGlobalVariable GV = DBuilder.createStaticVariable(<br>
       Unit, Name, Name, Unit, getLineNumber(VD->getLocation()), Ty, true, Init,<br>
-      getStaticDataMemberDeclaration(cast<VarDecl>(VD)));<br>
+      getOrCreateStaticDataMemberDeclarationOrNull(cast<VarDecl>(VD)));<br>
   DeclCache.insert(std::make_pair(VD->getCanonicalDecl(), llvm::WeakVH(GV)));<br>
 }<br>
<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=188739&r1=188738&r2=188739&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.h?rev=188739&r1=188738&r2=188739&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGDebugInfo.h (original)<br>
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.h Mon Aug 19 20:28:15 2013<br>
@@ -291,7 +291,7 @@ public:<br>
<br>
   void completeType(const RecordDecl *RD);<br>
   void completeRequiredType(const RecordDecl *RD);<br>
-<br>
+  void completeClassData(const RecordDecl *RD);<br>
<br>
 private:<br>
   /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration.<br>
@@ -354,10 +354,13 @@ private:<br>
   /// declaration for the given method definition.<br>
   llvm::DISubprogram getFunctionDeclaration(const Decl *D);<br>
<br>
-  /// getStaticDataMemberDeclaration - Return debug info descriptor to<br>
-  /// describe in-class static data member declaration for the given<br>
-  /// out-of-class definition.<br>
-  llvm::DIDerivedType getStaticDataMemberDeclaration(const VarDecl *D);<br>
+  /// Return debug info descriptor to describe in-class static data member<br>
+  /// declaration for the given out-of-class definition.<br>
+  llvm::DIDerivedType<br>
+  getOrCreateStaticDataMemberDeclarationOrNull(const VarDecl *D);<br>
+  llvm::DIDerivedType<br>
+  getOrCreateStaticDataMemberDeclaration(const VarDecl *D,<br>
+                                         llvm::DICompositeType Ctxt);<br>
<br>
   /// getFunctionName - Get function name for the given FunctionDecl. If the<br>
   /// name is constructred on demand (e.g. C++ destructor) then the name<br>
<br>
Modified: cfe/trunk/lib/CodeGen/CGVTables.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=188739&r1=188738&r2=188739&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGVTables.cpp?rev=188739&r1=188738&r2=188739&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/lib/CodeGen/CGVTables.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/CGVTables.cpp Mon Aug 19 20:28:15 2013<br>
@@ -828,6 +828,9 @@ CodeGenVTables::GenerateClassData(const<br>
     VFTContext->getVFPtrOffsets(RD);<br>
   }<br>
<br>
+  if (CGDebugInfo *DI = CGM.getModuleDebugInfo())<br>
+    DI->completeClassData(RD);<br>
+<br>
   // First off, check whether we've already emitted the v-table and<br>
   // associated stuff.<br>
   llvm::GlobalVariable *VTable = GetAddrOfVTable(RD);<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/debug-info-class.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-class.cpp?rev=188739&r1=188738&r2=188739&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-class.cpp?rev=188739&r1=188738&r2=188739&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/debug-info-class.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/debug-info-class.cpp Mon Aug 19 20:28:15 2013<br>
@@ -13,7 +13,39 @@ public:<br>
   virtual ~B();<br>
 };<br>
<br>
+B::~B() {<br>
+}<br>
+<br>
 struct C {<br>
+  static int s;<br>
+  virtual ~C();<br>
+};<br>
+<br>
+C::~C() {<br>
+}<br>
+<br>
+struct D {<br>
+  D();<br>
+  virtual ~D();<br>
+  void func() {<br>
+  }<br>
+};<br>
+<br>
+struct E {<br>
+  E();<br>
+  virtual ~E();<br>
+  virtual void func() {<br>
+  }<br>
+};<br>
+<br>
+struct F {<br>
+  struct inner {<br>
+  };<br>
+  static const int i = 2;<br>
+  virtual ~F();<br>
+};<br>
+<br>
+struct G {<br>
   virtual void func();<br>
   struct inner {<br>
     int j;<br>
@@ -29,10 +61,17 @@ struct A {<br>
   }<br>
 };<br>
<br>
+void f1() {<br>
+  D x;<br>
+  x.func();<br>
+  E y;<br>
+  int i = F::i;<br>
+  F::inner z;<br>
+}<br>
<br>
 int main(int argc, char **argv) {<br>
   B b;<br>
-  C::inner c_i;<br>
+  G::inner c_i;<br>
   if (argc) {<br>
     A a;<br>
   }<br>
@@ -49,15 +88,34 @@ int main(int argc, char **argv) {<br>
 // CHECK: DW_TAG_structure_type ] [foo]<br>
 // CHECK: DW_TAG_class_type ] [bar]<br>
 // CHECK: DW_TAG_union_type ] [baz]<br>
-// CHECK: DW_TAG_structure_type ] [A]<br>
-// CHECK: HdrSize<br>
 // CHECK: DW_TAG_class_type ] [B]<br>
 // CHECK: metadata !"_vptr$B", {{.*}}, i32 64, metadata !{{.*}}} ; [ DW_TAG_member ]<br>
-// CHECK: metadata [[C_INNER_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_structure_type ] [inner] {{.*}} [def]<br>
+<br>
+// CHECK: [[C:![0-9]*]] = {{.*}} metadata [[C_MEM:![0-9]*]], i32 0, metadata [[C]], null} ; [ DW_TAG_structure_type ] [C] {{.*}} [def]<br>
+// CHECK: [[C_MEM]] = metadata !{metadata [[C_VPTR:![0-9]*]], metadata [[C_S:![0-9]*]], metadata [[C_DTOR:![0-9]*]]}<br>
+// CHECK: [[C_VPTR]] = {{.*}} ; [ DW_TAG_member ] [_vptr$C] {{.*}} [artificial]<br>
+// CHECK: [[C_S]] = {{.*}} ; [ DW_TAG_member ] [s] {{.*}} [static] [from int]<br>
+// CHECK: [[C_DTOR]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [~C]<br>
+<br>
+// CHECK: ; [ DW_TAG_structure_type ] [A]<br>
+// CHECK: HdrSize<br>
+// CHECK: metadata [[D_MEM:![0-9]*]], i32 0, null} ; [ DW_TAG_structure_type ] [D] {{.*}} [decl]<br>
+// CHECK: [[D_MEM]] = metadata !{metadata [[D_FUNC:![0-9]*]]}<br>
+// CHECK: [[D_FUNC]] = {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]<br>
+<br>
+// CHECK: [[F_I_DEF:![0-9]*]] = {{.*}}, metadata [[F_I:![0-9]*]]} ; [ DW_TAG_variable ] [i]<br>
+// CHECK: [[F_I]] = {{.*}} ; [ DW_TAG_member ] [i]<br>
+// CHECK: [[F:![0-9]*]] = {{.*}} metadata [[F_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_structure_type ] [F] {{.*}} [def]<br>
+// CHECK: [[F_MEM]] = metadata !{metadata [[F_I]]}<br>
+<br>
+// CHECK: null, i32 0, null} ; [ DW_TAG_structure_type ] [E] {{.*}} [decl]<br>
+<br>
+// CHECK: metadata [[G_INNER_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_structure_type ] [inner] [line 50, {{.*}} [def]<br>
 // Context chains (in Clang -flimit-debug-info and in GCC generally) contain<br>
 // definitions without members (& without a vbase 'containing type'):<br>
-// CHECK: null, i32 0, null, null} ; [ DW_TAG_structure_type ] [C] {{.*}} [def]<br>
-// CHECK: [[C_INNER_MEM]] = metadata !{metadata [[C_INNER_I:![0-9]*]]}<br>
-// CHECK: [[C_INNER_I]] = {{.*}} ; [ DW_TAG_member ] [j] {{.*}} [from int]<br>
-// CHECK: ![[EXCEPTLOC]] = metadata !{i32 40,<br>
-// CHECK: ![[RETLOC]] = metadata !{i32 39,<br>
+// CHECK: null, i32 0, null, null} ; [ DW_TAG_structure_type ] [G] {{.*}} [def]<br>
+// CHECK: [[G_INNER_MEM]] = metadata !{metadata [[G_INNER_I:![0-9]*]]}<br>
+// CHECK: [[G_INNER_I]] = {{.*}} ; [ DW_TAG_member ] [j] {{.*}} [from int]<br>
+<br>
+// CHECK: ![[EXCEPTLOC]] = metadata !{i32 79,<br>
+// CHECK: ![[RETLOC]] = metadata !{i32 78,<br>
<br>
Modified: cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp?rev=188739&r1=188738&r2=188739&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp?rev=188739&r1=188738&r2=188739&view=diff</a><br>


==============================================================================<br>
--- cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp (original)<br>
+++ cfe/trunk/test/CodeGenCXX/debug-info-gline-tables-only.cpp Mon Aug 19 20:28:15 2013<br>
@@ -13,9 +13,17 @@ class E : public C {<br>
   // CHECK-NOT: DW_TAG_reference type<br>
   void x(const D& d);<br>
 };<br>
+struct F {<br>
+  enum X { };<br>
+  void func(X);<br>
+  virtual ~F();<br>
+};<br>
+F::~F() {<br>
+}<br>
 }<br>
<br>
 // CHECK-NOT: DW_TAG_variable<br>
 NS::C c;<br>
 NS::D d;<br>
 NS::E e;<br>
+NS::F f;<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div></div>