From: Adrian Prantl Date: Tue, 8 Sep 2015 19:20:27 +0000 (+0000) Subject: Module Debugging: Emit debug type information into clang modules. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8d25e29a9eaf6d1a719e624e84101020dfc465ae;p=clang 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 --- diff --git a/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/lib/CodeGen/ObjectFilePCHContainerOperations.cpp index 8342359b9f..a7c8230dc6 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 Buffer; + /// Visit every type and emit debug info for it. + struct DebugTypeVisitor : public RecursiveASTVisitor { + 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(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 0000000000..6ef4445cb9 --- /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 struct traits {}; + template + > class Template { + T member; + }; + extern template class Template; + + extern template struct traits; + typedef class Template FloatInstatiation; + + inline void fn() { + Template invisible; + } + + // Non-template inside a template. + template struct Outer { + Outer(); + struct Inner { + Inner(Outer) {} + }; + }; + template Outer::Outer() { + Inner a(*this); + }; + + // Partial template specialization. + template class A; + template class A {}; + typedef A B; + void foo(B) {} +} diff --git a/test/Modules/Inputs/module.map b/test/Modules/Inputs/module.map index 323e2cc85b..ba1178efc3 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 0000000000..4a0e69a27a --- /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 >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIiNS_6traitsIiEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIfNS_6traitsIfEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, +// CHECK-SAME: name: "Template >" +// CHECK-SAME: identifier: "_ZTSN8DebugCXX8TemplateIlNS_6traitsIlEEEE") +// CHECK: !DICompositeType(tag: DW_TAG_class_type, name: "A" +// 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.