From 8d25e29a9eaf6d1a719e624e84101020dfc465ae Mon Sep 17 00:00:00 2001 From: Adrian Prantl <aprantl@apple.com> Date: Tue, 8 Sep 2015 19:20:27 +0000 Subject: [PATCH] Module Debugging: Emit debug type information into clang modules. When -fmodule-format is set to "obj", emit debug info for all types declared in a module or referenced by a declaration into the module's object file container. This patch adds support for C and C++ types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@247049 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../ObjectFilePCHContainerOperations.cpp | 58 +++++++++++++++++++ test/Modules/Inputs/DebugCXX.h | 52 +++++++++++++++++ test/Modules/Inputs/module.map | 4 ++ test/Modules/ModuleDebugInfo.cpp | 41 +++++++++++++ 4 files changed, 155 insertions(+) create mode 100644 test/Modules/Inputs/DebugCXX.h create mode 100644 test/Modules/ModuleDebugInfo.cpp diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp index 8342359b9ff..a7c8230dc66 100644 --- a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp +++ b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp @@ -50,6 +50,34 @@ class PCHContainerGenerator : public ASTConsumer { raw_pwrite_stream *OS; std::shared_ptr<PCHBuffer> Buffer; + /// Visit every type and emit debug info for it. + struct DebugTypeVisitor : public RecursiveASTVisitor<DebugTypeVisitor> { + clang::CodeGen::CGDebugInfo &DI; + ASTContext &Ctx; + DebugTypeVisitor(clang::CodeGen::CGDebugInfo &DI, ASTContext &Ctx) + : DI(DI), Ctx(Ctx) {} + + /// Determine whether this type can be represented in DWARF. + static bool CanRepresent(const Type *Ty) { + return !Ty->isDependentType() && !Ty->isUndeducedType(); + } + + bool VisitTypeDecl(TypeDecl *D) { + QualType QualTy = Ctx.getTypeDeclType(D); + if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr())) + DI.getOrCreateStandaloneType(QualTy, D->getLocation()); + return true; + } + + bool VisitValueDecl(ValueDecl *D) { + QualType QualTy = D->getType(); + if (!QualTy.isNull() && CanRepresent(QualTy.getTypePtr())) + DI.getOrCreateStandaloneType(QualTy, D->getLocation()); + return true; + } + + }; + public: PCHContainerGenerator(DiagnosticsEngine &diags, const HeaderSearchOptions &HSO, @@ -82,6 +110,36 @@ public: *Ctx, HeaderSearchOpts, PreprocessorOpts, CodeGenOpts, *M, Diags)); } + bool HandleTopLevelDecl(DeclGroupRef D) override { + if (Diags.hasErrorOccurred() || + (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo)) + return true; + + // Collect debug info for all decls in this group. + for (auto *I : D) + if (!I->isFromASTFile()) { + DebugTypeVisitor DTV(*Builder->getModuleDebugInfo(), *Ctx); + DTV.TraverseDecl(I); + } + return true; + } + + void HandleTagDeclDefinition(TagDecl *D) override { + if (Diags.hasErrorOccurred()) + return; + + Builder->UpdateCompletedType(D); + } + + void HandleTagDeclRequiredDefinition(const TagDecl *D) override { + if (Diags.hasErrorOccurred()) + return; + + if (CodeGen::CGDebugInfo *DI = Builder->getModuleDebugInfo()) + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) + DI->completeRequiredType(RD); + } + /// Emit a container holding the serialized AST. void HandleTranslationUnit(ASTContext &Ctx) override { assert(M && VMContext && Builder); diff --git a/test/Modules/Inputs/DebugCXX.h b/test/Modules/Inputs/DebugCXX.h new file mode 100644 index 00000000000..6ef4445cb97 --- /dev/null +++ b/test/Modules/Inputs/DebugCXX.h @@ -0,0 +1,52 @@ +/* -*- C++ -*- */ +namespace DebugCXX { + // Records. + struct Struct { + int i; + static int static_member; + }; + + // Enums. + enum Enum { + Enumerator + }; + enum { + e1 = '1' + }; + enum { + e2 = '2' + }; + + // Templates (instatiations). + template<typename T> struct traits {}; + template<typename T, + typename Traits = traits<T> + > class Template { + T member; + }; + extern template class Template<int>; + + extern template struct traits<float>; + typedef class Template<float> FloatInstatiation; + + inline void fn() { + Template<long> invisible; + } + + // Non-template inside a template. + template <class> struct Outer { + Outer(); + struct Inner { + Inner(Outer) {} + }; + }; + template <class T> Outer<T>::Outer() { + Inner a(*this); + }; + + // Partial template specialization. + template <typename...> class A; + template <typename T> class A<T> {}; + typedef A<void> B; + void foo(B) {} +} diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 323e2cc85b9..ba1178efc36 100644 --- a/test/Modules/Inputs/module.map +++ b/test/Modules/Inputs/module.map @@ -332,6 +332,10 @@ module DebugModule { header "DebugModule.h" } +module DebugCXX { + header "DebugCXX.h" +} + module ImportNameInDir { header "ImportNameInDir.h" export * diff --git a/test/Modules/ModuleDebugInfo.cpp b/test/Modules/ModuleDebugInfo.cpp new file mode 100644 index 00000000000..4a0e69a27ae --- /dev/null +++ b/test/Modules/ModuleDebugInfo.cpp @@ -0,0 +1,41 @@ +// Test that (the same) debug info is emitted for an Objective-C++ +// module and a C++ precompiled header. + +// REQUIRES: asserts, shell + +// Modules: +// RUN: rm -rf %t +// 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 +// RUN: cat %t-mod.ll | FileCheck %s + +// PCH: +// 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 +// RUN: cat %t-pch.ll | FileCheck %s + +#ifdef MODULES +@import DebugCXX; +#endif + +// CHECK: distinct !DICompileUnit(language: DW_LANG_{{.*}}C_plus_plus, +// CHECK-SAME: isOptimized: false, +// CHECK-SAME: splitDebugFilename: +// CHECK: !DICompositeType(tag: DW_TAG_enumeration_type, name: "Enum" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX4EnumE") +// CHECK: !DINamespace(name: "DebugCXX" +// CHECK: !DICompositeType(tag: DW_TAG_structure_type, name: "Struct" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX6StructE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template<int, DebugCXX::traits<int> >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template<float, DebugCXX::traits<float> >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template<long, DebugCXX::traits<long> >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A<void>" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX1AIJvEEE") +// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "FloatInstatiation" +// no mangled name here yet. +// CHECK: !DIDerivedType(tag: DW_TAG_typedef, name: "B", +// no mangled name here yet. -- GitLab