]> granicus.if.org Git - clang/commitdiff
DebugInfo: Avoid duplicating types that may be created during the process of creating...
authorDavid Blaikie <dblaikie@gmail.com>
Sun, 18 Aug 2013 17:36:19 +0000 (17:36 +0000)
committerDavid Blaikie <dblaikie@gmail.com>
Sun, 18 Aug 2013 17:36:19 +0000 (17:36 +0000)
A partner to r188639, this is a somewhat heavy-handed fix to the general
issue, since even after that prior change the issue does still
unavoidably arise with template parameters (see test case).

There are other ways we could consider addressing this (see FIXME).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188640 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGDebugInfo.cpp
test/CodeGenCXX/debug-info-template-member.cpp

index 31422830f19f34c2079f629d03d60c3f7ed35508..7ffaf7d1dd20457b913518597c40bbabd6089b80 100644 (file)
@@ -2183,6 +2183,19 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) {
   else
     RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext()));
 
+  // If we ended up creating the type during the context chain construction,
+  // just return that.
+  // FIXME: this could be dealt with better if the type was recorded as
+  // completed before we started this (see the CompletedTypeCache usage in
+  // CGDebugInfo::CreateTypeDefinition(const RecordType*) - that would need to
+  // be pushed to before context creation, but after it was known to be
+  // destined for completion (might still have an issue if this caller only
+  // required a declaration but the context construction ended up creating a
+  // definition)
+  if (llvm::DIType T = getTypeOrNull(CGM.getContext().getRecordType(RD)))
+    if (!T.isForwardDecl() || !RD->getDefinition())
+      return T;
+
   // If this is just a forward declaration, construct an appropriately
   // marked node and just return it.
   if (!RD->getDefinition())
index 2354a1a51250ff95d734f10090583de33cbe39b2..0e702ac8f82eb087a99508d513895f9ff95e5ae5 100644 (file)
@@ -17,3 +17,31 @@ inline int add3(int x) {
 // CHECK: metadata [[C_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_structure_type ] [MyClass]
 // CHECK: [[C_MEM]] = metadata !{metadata [[C_TEMP:![0-9]*]]}
 // CHECK: [[C_TEMP]] = {{.*}} ; [ DW_TAG_subprogram ] [line 4] [add<2>]
+
+template<typename T>
+struct outer {
+  struct inner {
+    int i;
+  };
+};
+
+struct foo {
+  void func(outer<foo>::inner);
+};
+
+inline void func() {
+  // require 'foo' to be complete before the emission of 'inner' so that, when
+  // constructing the context chain for 'x' we emit the full definition of
+  // 'foo', which requires the definition of 'inner' again
+  foo f;
+}
+
+outer<foo>::inner x;
+
+// CHECK: metadata [[OUTER_FOO_INNER:![0-9]*]], i32 {{[0-9]*}}, i32 {{[0-9]*}}, %"struct.outer<foo>::inner"* @x, {{.*}} ; [ DW_TAG_variable ] [x]
+// CHECK: [[OUTER_FOO_INNER]] = {{.*}} ; [ DW_TAG_structure_type ] [inner]
+// CHECK: [[FOO_MEM:![0-9]*]], i32 0, null, null} ; [ DW_TAG_structure_type ] [foo]
+// CHECK: [[FOO_MEM]] = metadata !{metadata [[FOO_FUNC:![0-9]*]]}
+// CHECK: [[FOO_FUNC]] = {{.*}}, metadata !"_ZN3foo4funcEN5outerIS_E5innerE", i32 {{[0-9]*}}, metadata [[FOO_FUNC_TYPE:![0-9]*]], {{.*}} ; [ DW_TAG_subprogram ] {{.*}} [func]
+// CHECK: [[FOO_FUNC_TYPE]] = {{.*}}, metadata [[FOO_FUNC_PARAMS:![0-9]*]], i32 0, i32 0} ; [ DW_TAG_subroutine_type ]
+// CHECK: [[FOO_FUNC_PARAMS]] = metadata !{null, metadata !{{[0-9]*}}, metadata [[OUTER_FOO_INNER]]}