https://github.com/ClaytonKnittel updated https://github.com/llvm/llvm-project/pull/218807
>From 3607dd96faae1c55f0853b51117146a1e4125e06 Mon Sep 17 00:00:00 2001 From: Clayton Knittel <[email protected]> Date: Tue, 25 Aug 2026 23:08:05 +0000 Subject: [PATCH] [DebugInfo] Ignore delegating constructors in constructor homing. The constructor homing optimization limits the amount of redundant debug info generated for classes by only emitting forward declarations to debug info in translation units that can't instantiate the class on their own (i.e. they don't see the definitions of any constructors). Currently, classes that have any user-defined constructors are excluded from the optimization. This is being changed to only exclude non-delegating constructors, as we can rely on the delegated constructor to instantiate debug info. Signed-off-by: Clayton Knittel <[email protected]> --- clang/lib/CodeGen/CGDebugInfo.cpp | 23 +++++-- clang/test/DebugInfo/CXX/limited-ctor.cpp | 75 +++++++++++++++++++++++ 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 2c7af395c4562..fdb5d869c441b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2535,10 +2535,17 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( SPFlags |= llvm::DISubprogram::SPFlagOptimized; // In this debug mode, emit type info for a class when its constructor type - // info is emitted. - if (DebugKind == llvm::codegenoptions::DebugInfoConstructor) - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) - completeUnusedClass(*CD->getParent()); + // info is emitted. Delegating constructors are ignored because the target + // constructor's definition will emit the type info. + if (DebugKind == llvm::codegenoptions::DebugInfoConstructor) { + if (const auto *CD = dyn_cast<CXXConstructorDecl>(Method)) { + if (const auto *Def = + dyn_cast_or_null<CXXConstructorDecl>(CD->getDefinition()); + Def && !Def->isDelegatingConstructor()) { + completeUnusedClass(*CD->getParent()); + } + } + } llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); llvm::DISubprogram *SP = DBuilder.createMethod( @@ -3240,6 +3247,14 @@ static bool canUseCtorHoming(const CXXRecordDecl *RD) { for (const CXXConstructorDecl *Ctor : RD->ctors()) { if (Ctor->isCopyOrMoveConstructor()) continue; + if (const FunctionDecl *Def = Ctor->getDefinition()) { + const auto *CtorDef = cast<CXXConstructorDecl>(Def); + // Ignore delegating constructors, the target constructor will either be + // a non-deleted custom constructor that enables homing, or could be a + // copy/move constructor, which does not enable homing. + if (CtorDef->isDelegatingConstructor()) + continue; + } if (!Ctor->isDeleted()) return true; } diff --git a/clang/test/DebugInfo/CXX/limited-ctor.cpp b/clang/test/DebugInfo/CXX/limited-ctor.cpp index 18adfdeed0480..29269e06c042d 100644 --- a/clang/test/DebugInfo/CXX/limited-ctor.cpp +++ b/clang/test/DebugInfo/CXX/limited-ctor.cpp @@ -27,6 +27,81 @@ struct E { constexpr E(){}; } TestE; +// Defined delegating constructor where delegated constructor is not defined +// should not emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "Delegating"{{.*}}flags: DIFlagFwdDecl +struct Delegating { + Delegating() : Delegating(42) {} + Delegating(int); +} TestDelegating; + +// Defined out-of-line delegating constructor where delegated constructor is not +// defined should not emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "OutOfLineDelegating"{{.*}}flags: DIFlagFwdDecl +struct OutOfLineDelegating { + OutOfLineDelegating(); + OutOfLineDelegating(int); +} TestOutOfLineDelegating; +OutOfLineDelegating::OutOfLineDelegating() : OutOfLineDelegating(42) {} + +// Defined delegating constructor where delegated constructor is defined should +// emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingToDefined"{{.*}}DIFlagTypePassByValue +struct DelegatingToDefined { + DelegatingToDefined() : DelegatingToDefined(42) {} + DelegatingToDefined(int) {} +} TestDelegatingToDefined; + +// Defined delegating constructor where delegated constructor is defined out of +// line should emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingToOutOfLine"{{.*}}DIFlagTypePassByValue +struct DelegatingToOutOfLine { + DelegatingToOutOfLine() : DelegatingToOutOfLine(42) {} + DelegatingToOutOfLine(int); +} TestDelegatingToOutOfLine; +DelegatingToOutOfLine::DelegatingToOutOfLine(int) {} + +// Defined out-of-line delegating constructor where delegated constructor is +// defined should emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingOutOfLine"{{.*}}DIFlagTypePassByValue +struct DelegatingOutOfLine { + DelegatingOutOfLine(); + DelegatingOutOfLine(int) {} +} TestDelegatingOutOfLine; +DelegatingOutOfLine::DelegatingOutOfLine() : DelegatingOutOfLine(42) {} + +// Defined out-of-line delegating constructor where delegated constructor is +// defined out-of-line should emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingOutOfLineToOutOfLine"{{.*}}DIFlagTypePassByValue +struct DelegatingOutOfLineToOutOfLine { + DelegatingOutOfLineToOutOfLine(); + DelegatingOutOfLineToOutOfLine(int); +} TestDelegatingOutOfLineToOutOfLine; +DelegatingOutOfLineToOutOfLine::DelegatingOutOfLineToOutOfLine() + : DelegatingOutOfLineToOutOfLine(42) {} +DelegatingOutOfLineToOutOfLine::DelegatingOutOfLineToOutOfLine(int) {} + +// Delegating constructor to a copy constructor should not enable constructor +// homing, so it should emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingToCopyCtor"{{.*}}DIFlagTypePassByValue +struct DelegatingToCopyCtor { + DelegatingToCopyCtor(const DelegatingToCopyCtor&) = default; + DelegatingToCopyCtor(const DelegatingToCopyCtor& val, int) + : DelegatingToCopyCtor(val) {} +}; +void TestDelegatingToCopyCtor(DelegatingToCopyCtor) {} + +// Delegating constructor to a move constructor should not enable constructor +// homing, so it should emit full debug info. +// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "DelegatingToMoveCtor"{{.*}}DIFlagTypePassByValue +struct DelegatingToMoveCtor { + DelegatingToMoveCtor(const DelegatingToMoveCtor&) = default; + DelegatingToMoveCtor(DelegatingToMoveCtor&&) = default; + DelegatingToMoveCtor(DelegatingToMoveCtor&& val, int) + : DelegatingToMoveCtor(static_cast<DelegatingToMoveCtor&&>(val)) {} +}; +void TestDelegatingToMoveCtor(DelegatingToMoveCtor) {} + // Test for trivial constructor. // CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: "F"{{.*}}DIFlagTypePassByValue struct F { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
