diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 633078fb3bbc..6c24e8f86534 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(RD); + + if (!CXXDecl) + return false; + + if (CXXDecl->hasDefinition() && CXXDecl->isDynamicClass()) + return true; + + TemplateSpecializationKind Spec = TSK_Undeclared; + if (const ClassTemplateSpecializationDecl *SD = + dyn_cast(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(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(RD->getDeclContext()))); @@ -2014,6 +2039,14 @@ llvm::DIType CGDebugInfo::getCompletedTypeOrNull(QualType Ty) { return llvm::DIType(cast_or_null(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 fce56c0513ce..56fc9754d7a3 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 f7b518abc57b..617348999309 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(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 000000000000..13d60de184e6 --- /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 +struct a { +}; +extern template class a; +// CHECK-NOT: ; [ DW_TAG_structure_type ] [a] + +template +struct b { +}; +extern template class b; +b bi; +// CHECK: ; [ DW_TAG_structure_type ] [b] {{.*}} [def] + +template +struct c { + void f() {} +}; +extern template class c; +c ci; +// CHECK: ; [ DW_TAG_structure_type ] [c] {{.*}} [decl] + +template +struct d { + void f(); +}; +extern template class d; +d di; +// CHECK: ; [ DW_TAG_structure_type ] [d] {{.*}} [def] + +template +struct e { + void f(); +}; +template +void e::f() { +} +extern template class e; +e ei; +// CHECK: ; [ DW_TAG_structure_type ] [e] {{.*}} [decl] + +template +struct f { + void g(); +}; +extern template class f; +template +void f::g() { +} +f fi; +// Is this right? We don't seem to emit a def for 'f::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] {{.*}} [decl] + +template +struct g { + void f(); +}; +template <> +void g::f(); +extern template class g; +g gi; +// CHECK: ; [ DW_TAG_structure_type ] [g] {{.*}} [def] + +template +struct h { +}; +template class h; +// CHECK: ; [ DW_TAG_structure_type ] [h] {{.*}} [def]