<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Sep 8, 2015 at 12:20 PM, Adrian Prantl via cfe-commits <span dir="ltr"><<a href="mailto:cfe-commits@lists.llvm.org" target="_blank">cfe-commits@lists.llvm.org</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: adrian<br>
Date: Tue Sep  8 14:20:27 2015<br>
New Revision: 247049<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=247049&view=rev" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project?rev=247049&view=rev</a><br>
Log:<br>
Module Debugging: Emit debug type information into clang modules.<br>
<br>
When -fmodule-format is set to "obj", emit debug info for all types<br>
declared in a module or referenced by a declaration into the module's<br>
object file container.<br>
<br>
This patch adds support for C and C++ types.<br>
<br>
Added:<br>
    cfe/trunk/test/Modules/Inputs/DebugCXX.h<br>
    cfe/trunk/test/Modules/ModuleDebugInfo.cpp<br>
Modified:<br>
    cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp<br>
    cfe/trunk/test/Modules/Inputs/module.map<br>
<br>
Modified: cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp?rev=247049&r1=247048&r2=247049&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp?rev=247049&r1=247048&r2=247049&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp (original)<br>
+++ cfe/trunk/lib/CodeGen/ObjectFilePCHContainerOperations.cpp Tue Sep  8 14:20:27 2015<br>
@@ -50,6 +50,34 @@ class PCHContainerGenerator : public AST<br>
   raw_pwrite_stream *OS;<br>
   std::shared_ptr<PCHBuffer> Buffer;<br>
<br>
+  /// Visit every type and emit debug info for it.<br>
+  struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> {<br>
+    clang::CodeGen::CGDebugInfo &DI;<br>
+    ASTContext &Ctx;<br>
+    DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx)<br>
+        : DI(DI), Ctx(Ctx) {}<br>
+<br>
+    /// Determine whether this type can be represented in DWARF.<br>
+    static bool CanRepresent(const Type *Ty) {<br>
+      return !Ty->isDependentType() && !Ty->isUndeducedType();<br>
+    }<br>
+<br>
+    bool VisitTypeDecl(TypeDecl *D) {<br></blockquote><div><br></div><div>Does this only visit types defined in this module? Or also types otherwise referenced by this module? (does it only visit definitions, or also declarations?)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      QualType QualTy = Ctx.getTypeDeclType(D);<br>
+      if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))<br>
+        DI.getOrCreateStandaloneType(QualTy, D->getLocation());<br>
+      return true;<br>
+    }<br>
+<br>
+    bool VisitValueDecl(ValueDecl *D) {<br></blockquote><div><br></div><div>This seems strange - why would we put this type into the module debug info? (the type may be defined elsewhere, in another module, etc - just because there's a variable of that type defined in the module wouldn't imply that the module should contain a definition of the type, would it? That would seem to result in a lot of duplicate info)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      QualType QualTy = D->getType();<br>
+      if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr()))<br>
+        DI.getOrCreateStandaloneType(QualTy, D->getLocation());<br>
+      return true;<br>
+    }<br>
+<br>
+  };<br>
+<br>
 public:<br>
   PCHContainerGenerator(DiagnosticsEngine &diags,<br>
                         const HeaderSearchOptions &HSO,<br>
@@ -82,6 +110,36 @@ public:<br>
         *Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags));<br>
   }<br>
<br>
+  bool HandleTopLevelDecl(DeclGroupRef D) override {<br>
+    if (Diags.hasErrorOccurred() ||<br>
+        (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo))<br>
+      return true;<br>
+<br>
+    // Collect debug info for all decls in this group.<br>
+    for (auto *I : D)<br>
+      if (!I->isFromASTFile()) {<br>
+        DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx);<br>
+        DTV.TraverseDecl(I);<br>
+      }<br>
+    return true;<br>
+  }<br>
+<br>
+  void HandleTagDeclDefinition(TagDecl *D) override {<br>
+    if (Diags.hasErrorOccurred())<br></blockquote><div><br></div><div>Is it particularly useful to check for errors here (& in HandleTagDeclRequiredDefinition below)? That seems like a speed optimization for the slow case (we're emitting diagnostics anyway, the speed isn't too important - and we'll still have to be able to discard this work later in case we haven't seen errors yet, but we do see them later/by the end of the module?)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+      return;<br>
+<br>
+    Builder->UpdateCompletedType(D);<br>
+  }<br>
+<br>
+  void HandleTagDeclRequiredDefinition(const TagDecl *D) override {<br>
+    if (Diags.hasErrorOccurred())<br>
+      return;<br>
+<br>
+    if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo())<br>
+      if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))<br>
+        DI->completeRequiredType(RD);<br>
+  }<br>
+<br>
   /// Emit a container holding the serialized AST.<br>
   void HandleTranslationUnit(ASTContext &Ctx) override {<br>
     assert(M && VMContext && Builder);<br>
<br>
Added: cfe/trunk/test/Modules/Inputs/DebugCXX.h<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DebugCXX.h?rev=247049&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/DebugCXX.h?rev=247049&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Modules/Inputs/DebugCXX.h (added)<br>
+++ cfe/trunk/test/Modules/Inputs/DebugCXX.h Tue Sep  8 14:20:27 2015<br></blockquote><div><br></div><div>A test case involving two modules (where one module depends on the other and uses its types) would be useful to demonstrate that we aren't redundantly emitting types into modules that didn't define them, perhaps?</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
@@ -0,0 +1,52 @@<br>
+/* -*- C++ -*- */<br>
+namespace DebugCXX {<br>
+  // Records.<br>
+  struct Struct {<br>
+    int i;<br>
+    static int static_member;<br>
+  };<br>
+<br>
+  // Enums.<br>
+  enum Enum {<br>
+    Enumerator<br>
+  };<br>
+  enum {<br>
+    e1 = '1'<br>
+  };<br>
+  enum {<br>
+    e2 = '2'<br>
+  };<br>
+<br>
+  // Templates (instatiations).<br>
+  template<typename T> struct traits {};<br>
+  template<typename T,<br>
+           typename Traits = traits<T><br>
+          > class Template {<br>
+    T member;<br>
+  };<br>
+  extern template class Template<int>;<br>
+<br>
+  extern template struct traits<float>;<br>
+  typedef class Template<float> FloatInstatiation;<br>
+<br>
+  inline void fn() {<br>
+    Template<long> invisible;<br>
+  }<br>
+<br>
+  // Non-template inside a template.<br>
+  template <class> struct Outer {<br>
+    Outer();<br>
+    struct Inner {<br>
+      Inner(Outer) {}<br>
+    };<br>
+  };<br>
+  template <class T> Outer<T>::Outer() {<br>
+    Inner a(*this);<br>
+  };<br>
+<br>
+  // Partial template specialization.<br>
+  template <typename...> class A;<br>
+  template <typename T> class A<T> {};<br>
+  typedef A<void> B;<br>
+  void foo(B) {}<br>
+}<br>
<br>
Modified: cfe/trunk/test/Modules/Inputs/module.map<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=247049&r1=247048&r2=247049&view=diff" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/Inputs/module.map?rev=247049&r1=247048&r2=247049&view=diff</a><br>
==============================================================================<br>
--- cfe/trunk/test/Modules/Inputs/module.map (original)<br>
+++ cfe/trunk/test/Modules/Inputs/module.map Tue Sep  8 14:20:27 2015<br>
@@ -332,6 +332,10 @@ module DebugModule {<br>
   header "DebugModule.h"<br>
 }<br>
<br>
+module DebugCXX {<br>
+  header "DebugCXX.h"<br>
+}<br>
+<br>
 module ImportNameInDir {<br>
   header "ImportNameInDir.h"<br>
   export *<br>
<br>
Added: cfe/trunk/test/Modules/ModuleDebugInfo.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/ModuleDebugInfo.cpp?rev=247049&view=auto" rel="noreferrer" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Modules/ModuleDebugInfo.cpp?rev=247049&view=auto</a><br>
==============================================================================<br>
--- cfe/trunk/test/Modules/ModuleDebugInfo.cpp (added)<br>
+++ cfe/trunk/test/Modules/ModuleDebugInfo.cpp Tue Sep  8 14:20:27 2015<br>
@@ -0,0 +1,41 @@<br>
+// Test that (the same) debug info is emitted for an Objective-C++<br>
+// module and a C++ precompiled header.<br>
+<br>
+// REQUIRES: asserts, shell<br>
+<br>
+// Modules:<br>
+// RUN: rm -rf %t<br>
+// RUN: %clang_cc1 -x objective-c++ -std=c++11 -g -fmodules -fmodule-format=obj -fimplicit-module-maps -DMODULES -fmodules-cache-path=%t %s -I %S/Inputs -I %t -emit-llvm -o %t.ll -mllvm -debug-only=pchcontainer &>%t-mod.ll<br>
+// RUN: cat %t-mod.ll | FileCheck %s<br>
+<br>
+// PCH:<br>
+// RUN: %clang_cc1 -x c++ -std=c++11 -emit-pch -fmodule-format=obj -I %S/Inputs -o %t.pch %S/Inputs/DebugCXX.h -mllvm -debug-only=pchcontainer &>%t-pch.ll<br>
+// RUN: cat %t-pch.ll | FileCheck %s<br>
+<br>
+#ifdef MODULES<br>
+@import DebugCXX;<br>
+#endif<br>
+<br></blockquote><div><br></div><div>If practical, it'd be nice to have these checks near the things tehy're checking for - it'd make the code easier to read/understand. (haven't looked at related tests in the same directory to see what the convention's like)</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+// CHECK: distinct !DICompileUnit(language: DW_LANG_{{.*}}C_plus_plus,<br>
+// CHECK-SAME:                    isOptimized: false,<br>
+// CHECK-SAME:                    splitDebugFilename:<br>
+// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX4EnumE")<br>
+// CHECK: !DINamespace(name: "DebugCXX"<br>
+// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX6StructE")<br>
+// CHECK: !DICompositeType(tag: DW_TAG_class_type,<br>
+// CHECK-SAME:             name: "Template<int, DebugCXX::traits<int> >"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE")<br>
+// CHECK: !DICompositeType(tag: DW_TAG_class_type,<br>
+// CHECK-SAME:             name: "Template<float, DebugCXX::traits<float> >"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE")<br>
+// CHECK: !DICompositeType(tag: DW_TAG_class_type,<br>
+// CHECK-SAME:             name: "Template<long, DebugCXX::traits<long> >"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE")<br>
+// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>"<br>
+// CHECK-SAME:             identifier: "_ZTSN8DebugCXX1AIJvEEE")<br>
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "FloatInstatiation"<br>
+// no mangled name here yet.<br></blockquote><div><br>Is this a 'fixme'? (might be good to phrase it that way) - any idea why they're missing?<br> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
+// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "B",<br>
+// no mangled name here yet.<br>
<br>
<br>
_______________________________________________<br>
cfe-commits mailing list<br>
<a href="mailto:cfe-commits@lists.llvm.org">cfe-commits@lists.llvm.org</a><br>
<a href="http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits" rel="noreferrer" target="_blank">http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits</a><br>
</blockquote></div><br></div></div>