Skip to content
Snippets Groups Projects
Commit 8d25e29a authored by Adrian Prantl's avatar Adrian Prantl
Browse files

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
parent 4ba745e3
No related branches found
No related tags found
No related merge requests found
......@@ -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);
......
/* -*- 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) {}
}
......@@ -332,6 +332,10 @@ module DebugModule {
header "DebugModule.h"
}
module DebugCXX {
header "DebugCXX.h"
}
module ImportNameInDir {
header "ImportNameInDir.h"
export *
......
// 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.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment