diff options
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.cpp | 69 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGDebugInfo.h | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenModule.cpp | 10 | ||||
-rw-r--r-- | clang/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp | 72 |
4 files changed, 134 insertions, 19 deletions
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 633078fb3bb..6c24e8f8653 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1458,28 +1458,53 @@ void CGDebugInfo::completeClassData(const RecordDecl *RD) { TypeCache[TyPtr] = Res; } +static bool hasExplicitMemberDefinition(CXXRecordDecl::method_iterator I, + CXXRecordDecl::method_iterator End) { + for (; I != End; ++I) + if (FunctionDecl *Tmpl = I->getInstantiatedFromMemberFunction()) + if (!Tmpl->isImplicit() && Tmpl->hasBody()) + return true; + return false; +} + +static bool shouldOmitDefinition(CodeGenOptions::DebugInfoKind DebugKind, + const RecordDecl *RD, + const LangOptions &LangOpts) { + if (DebugKind > CodeGenOptions::LimitedDebugInfo) + return false; + + if (!LangOpts.CPlusPlus) + return false; + + if (!RD->isCompleteDefinitionRequired()) + return true; + + const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); + + if (!CXXDecl) + return false; + + if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass()) + return true; + + TemplateSpecializationKind Spec = TSK_Undeclared; + if (const ClassTemplateSpecializationDecl *SD = + dyn_cast<ClassTemplateSpecializationDecl>(RD)) + Spec = SD->getSpecializationKind(); + + if (Spec == TSK_ExplicitInstantiationDeclaration && + hasExplicitMemberDefinition(CXXDecl->method_begin(), + CXXDecl->method_end())) + return true; + + return false; +} + /// CreateType - get structure or union type. llvm::DIType CGDebugInfo::CreateType(const RecordType *Ty) { RecordDecl *RD = Ty->getDecl(); - const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); - // Always emit declarations for types that aren't required to be complete when - // in limit-debug-info mode. If the type is later found to be required to be - // complete this declaration will be upgraded to a definition by - // `completeRequiredType`. - // If the type is dynamic, only emit the definition in TUs that require class - // data. This is handled by `completeClassData`. llvm::DICompositeType T(getTypeOrNull(QualType(Ty, 0))); - // If we've already emitted the type, just use that, even if it's only a - // declaration. The completeType, completeRequiredType, and completeClassData - // callbacks will handle promoting the declaration to a definition. - if (T || - // Under -fno-standalone-debug: - (DebugKind <= CodeGenOptions::LimitedDebugInfo && - // Emit only a forward declaration unless the type is required. - ((!RD->isCompleteDefinitionRequired() && CGM.getLangOpts().CPlusPlus) || - // If the class is dynamic, only emit a declaration. A definition will - // be emitted whenever the vtable is emitted. - (CXXDecl && CXXDecl->hasDefinition() && CXXDecl->isDynamicClass())))) { + if (T || shouldOmitDefinition(DebugKind, RD, CGM.getLangOpts())) { if (!T) T = getOrCreateRecordFwdDecl( Ty, getContextDescriptor(cast<Decl>(RD->getDeclContext()))); @@ -2014,6 +2039,14 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { return llvm::DIType(cast_or_null<llvm::MDNode>(V)); } +void CGDebugInfo::completeTemplateDefinition( + const ClassTemplateSpecializationDecl &SD) { + completeClassData(&SD); + // In case this type has no member function definitions being emitted, ensure + // it is retained + RetainedTypes.push_back(CGM.getContext().getRecordType(&SD).getAsOpaquePtr()); +} + /// getCachedInterfaceTypeOrNull - Get the type from the interface /// cache, unless it needs to regenerated. Otherwise return null. llvm::Value *CGDebugInfo::getCachedInterfaceTypeOrNull(QualType Ty) { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index fce56c0513c..56fc9754d7a 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -288,6 +288,8 @@ public: void completeRequiredType(const RecordDecl *RD); void completeClassData(const RecordDecl *RD); + void completeTemplateDefinition(const ClassTemplateSpecializationDecl &SD); + private: /// EmitDeclare - Emit call to llvm.dbg.declare for a variable declaration. void EmitDeclare(const VarDecl *decl, unsigned Tag, llvm::Value *AI, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index f7b518abc57..61734899930 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3000,7 +3000,15 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { ImportedModules.insert(Import->getImportedModule()); break; - } + } + + case Decl::ClassTemplateSpecialization: { + const ClassTemplateSpecializationDecl *Spec = + cast<ClassTemplateSpecializationDecl>(D); + if (DebugInfo && + Spec->getSpecializationKind() == TSK_ExplicitInstantiationDefinition) + DebugInfo->completeTemplateDefinition(*Spec); + } default: // Make sure we handled everything we should, every other kind is a diff --git a/clang/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp b/clang/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp new file mode 100644 index 00000000000..13d60de184e --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-template-explicit-specialization.cpp @@ -0,0 +1,72 @@ +// RUN: %clang_cc1 -S -emit-llvm -g %s -o - | FileCheck %s + +template <typename T> +struct a { +}; +extern template class a<int>; +// CHECK-NOT: ; [ DW_TAG_structure_type ] [a<int>] + +template <typename T> +struct b { +}; +extern template class b<int>; +b<int> bi; +// CHECK: ; [ DW_TAG_structure_type ] [b<int>] {{.*}} [def] + +template <typename T> +struct c { + void f() {} +}; +extern template class c<int>; +c<int> ci; +// CHECK: ; [ DW_TAG_structure_type ] [c<int>] {{.*}} [decl] + +template <typename T> +struct d { + void f(); +}; +extern template class d<int>; +d<int> di; +// CHECK: ; [ DW_TAG_structure_type ] [d<int>] {{.*}} [def] + +template <typename T> +struct e { + void f(); +}; +template <typename T> +void e<T>::f() { +} +extern template class e<int>; +e<int> ei; +// CHECK: ; [ DW_TAG_structure_type ] [e<int>] {{.*}} [decl] + +template <typename T> +struct f { + void g(); +}; +extern template class f<int>; +template <typename T> +void f<T>::g() { +} +f<int> fi; +// Is this right? We don't seem to emit a def for 'f<int>::g' (even if it is +// called in this translation unit) so I guess if we're relying on its +// definition to be wherever the explicit instantiation definition is, we can do +// the same for the debug info. +// CHECK: ; [ DW_TAG_structure_type ] [f<int>] {{.*}} [decl] + +template <typename T> +struct g { + void f(); +}; +template <> +void g<int>::f(); +extern template class g<int>; +g<int> gi; +// CHECK: ; [ DW_TAG_structure_type ] [g<int>] {{.*}} [def] + +template <typename T> +struct h { +}; +template class h<int>; +// CHECK: ; [ DW_TAG_structure_type ] [h<int>] {{.*}} [def] |