r221704 - PR16091 continued: Debug Info for member functions with undeduced return types.

David Blaikie dblaikie at gmail.com
Tue Nov 11 12:44:46 PST 2014


Author: dblaikie
Date: Tue Nov 11 14:44:45 2014
New Revision: 221704

URL: http://llvm.org/viewvc/llvm-project?rev=221704&view=rev
Log:
PR16091 continued: Debug Info for member functions with undeduced return types.

So DWARF5 specs out auto deduced return types as DW_TAG_unspecified_type
with DW_AT_name "auto", and GCC implements this somewhat, but it
presents a few problems to do this with Clang.

GCC's implementation only applies to member functions where the auto
return type isn't deduced immediately (ie: member functions of templates
or member functions defined out of line). In the common case of an
inline deduced return type function, GCC emits the DW_AT_type as the
deduced return type.

Currently GDB doesn't seem to behave too well with this debug info - it
treats the return type as 'void', even though the definition of the
function has the correctly deduced return type (I guess it sees the
return type the declaration has, doesn't understand it, and assumes
void). This means the function's ABI might be broken (non-trivial return
types, etc), etc.

Clang, on the other hand doesn't track this particular case of a
deducable return type that is deduced immediately versus one that is
deduced 'later'. So if we implement the DWARF5 representation, all
deducible return type functions would get adverse GDB behavior
(including deduced return type lambda functions, inline deduced return
type functions, etc).

Also, we can't just do this for auto types that are not deduced -
because Clang marks even the declaration's return type as deduced (&
provides the underlying type) once a definition is seen that allows the
deduction. So we have to ignore even deduced types - but we can't do
that for auto variables (because this representation only applies to
function declarations - variables and function definitions need the real
type so the function can be called, etc) so we'd need to add an extra
flag to the type unwrapping/creation code to indicate when we want to
see through deduced types and when we don't. It's also not as simple as
just checking at the top level when building a function type (for one
thing, we reuse the function type building for building function pointer
types which might also have 'auto' in them - but be the type of a
variable instead) because the auto might be arbitrarily deeply nested
("auto &", "auto (*)()", etc...)

So, with all that said, let's do the simple thing that works in existing
debuggers for now and treat these functions the same way we do function
templates and implicit special members: omit them from the member list,
since they can't be correctly called anyway (without knowing the return
type the ABI isn't know and a function call could put the arguments in
the wrong place) so they're not much use to the user.

At some point in the future, when GDB understands the DWARF5
representation better it might be worth plumbing through the extra type
builder handling to avoid looking through AutoType for some callers,
etc...

Modified:
    cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
    cfe/trunk/test/CodeGenCXX/debug-info-cxx1y.cpp

Modified: cfe/trunk/lib/CodeGen/CGDebugInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDebugInfo.cpp?rev=221704&r1=221703&r2=221704&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGDebugInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGDebugInfo.cpp Tue Nov 11 14:44:45 2014
@@ -1175,6 +1175,10 @@ void CGDebugInfo::CollectCXXMemberFuncti
     // referenced)
     if (!Method || Method->isImplicit())
       continue;
+
+    if (Method->getType()->getAs<FunctionProtoType>()->getContainedAutoType())
+      continue;
+
     // Reuse the existing member function declaration if it exists.
     // It may be associated with the declaration of the type & should be
     // reused as we're building the definition.
@@ -2013,8 +2017,7 @@ static QualType UnwrapTypeForDebugInfo(Q
       break;
     case Type::Auto:
       QualType DT = cast<AutoType>(T)->getDeducedType();
-      if (DT.isNull())
-        return T;
+      assert(!DT.isNull() && "Undeduced types shouldn't reach here.");
       T = DT;
       break;
     }
@@ -2106,8 +2109,6 @@ llvm::DIType CGDebugInfo::CreateTypeNode
   if (Ty.hasLocalQualifiers())
     return CreateQualifiedType(Ty, Unit);
 
-  const char *Diag = nullptr;
-
   // Work out details of type.
   switch (Ty->getTypeClass()) {
 #define TYPE(Class, Base)
@@ -2167,6 +2168,7 @@ llvm::DIType CGDebugInfo::CreateTypeNode
   case Type::TemplateSpecialization:
     return CreateType(cast<TemplateSpecializationType>(Ty), Unit);
 
+  case Type::Auto:
   case Type::Attributed:
   case Type::Elaborated:
   case Type::Paren:
@@ -2176,18 +2178,10 @@ llvm::DIType CGDebugInfo::CreateTypeNode
   case Type::Decltype:
   case Type::UnaryTransform:
   case Type::PackExpansion:
-    llvm_unreachable("type should have been unwrapped!");
-  case Type::Auto:
-    Diag = "auto";
     break;
   }
 
-  assert(Diag && "Fall through without a diagnostic?");
-  unsigned DiagID = CGM.getDiags().getCustomDiagID(
-      DiagnosticsEngine::Error,
-      "debug information for %0 is not yet supported");
-  CGM.getDiags().Report(DiagID) << Diag;
-  return llvm::DIType();
+  llvm_unreachable("type should have been unwrapped!");
 }
 
 /// getOrCreateLimitedType - Get the type from the cache or create a new

Modified: cfe/trunk/test/CodeGenCXX/debug-info-cxx1y.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/debug-info-cxx1y.cpp?rev=221704&r1=221703&r2=221704&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/debug-info-cxx1y.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/debug-info-cxx1y.cpp Tue Nov 11 14:44:45 2014
@@ -1,7 +1,20 @@
-// RUN: not %clang_cc1 -emit-llvm-only -std=c++1y -g %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -emit-llvm-only -std=c++14 -emit-llvm -g %s -o - | FileCheck %s
+
+// CHECK: [[EMPTY:![0-9]*]] = metadata !{}
+// CHECK: \00foo\00{{.*}}, metadata [[EMPTY]], {{.*}}} ; [ DW_TAG_structure_type ]
+// FIXME: The context of this definition should be the CU/file scope, not the class.
+// CHECK: metadata !"_ZTS3foo", metadata [[SUBROUTINE_TYPE:![0-9]*]], {{.*}}, metadata [[FUNC_DECL:![0-9]*]], metadata {{![0-9]*}}} ; [ DW_TAG_subprogram ] {{.*}} [def] [func]
+// CHECK: [[SUBROUTINE_TYPE]] = {{.*}}, metadata [[TYPE_LIST:![0-9]*]],
+// CHECK: [[TYPE_LIST]] = metadata !{metadata [[INT:![0-9]*]]}
+// CHECK: [[INT]] = {{.*}} ; [ DW_TAG_base_type ] [int]
+// CHECK: [[FUNC_DECL]] = {{.*}}, metadata !"_ZTS3foo", metadata [[SUBROUTINE_TYPE]], {{.*}}} ; [ DW_TAG_subprogram ] {{.*}} [func]
 
 struct foo {
-  auto func(); // CHECK: error: debug information for auto is not yet supported
+  static auto func();
 };
 
 foo f;
+
+auto foo::func() {
+  return 1;
+}





More information about the cfe-commits mailing list