summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp58
-rw-r--r--clang/test/Modules/Inputs/DebugCXX.h52
-rw-r--r--clang/test/Modules/Inputs/module.map4
-rw-r--r--clang/test/Modules/ModuleDebugInfo.cpp41
4 files changed, 155 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp b/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
index 8342359b9ff..a7c8230dc66 100644
--- a/clang/lib/CodeGen/ObjectFilePCHContainerOperations.cpp
+++ b/clang/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/clang/test/Modules/Inputs/DebugCXX.h b/clang/test/Modules/Inputs/DebugCXX.h
new file mode 100644
index 00000000000..6ef4445cb97
--- /dev/null
+++ b/clang/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/clang/test/Modules/Inputs/module.map b/clang/test/Modules/Inputs/module.map
index 323e2cc85b9..ba1178efc36 100644
--- a/clang/test/Modules/Inputs/module.map
+++ b/clang/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/clang/test/Modules/ModuleDebugInfo.cpp b/clang/test/Modules/ModuleDebugInfo.cpp
new file mode 100644
index 00000000000..4a0e69a27ae
--- /dev/null
+++ b/clang/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.
OpenPOWER on IntegriCloud