https://github.com/ClaytonKnittel created 
https://github.com/llvm/llvm-project/pull/218165

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_ constexpr constructors, or _any_ 
user-defined constructors are excluded from the optimization. This is being 
changed to only exclude _defined_ constexpr constructors, as declared constexpr 
constructors are not callable in a TU that doesn't see their definition. 
Additionally, we ignore delegating constructors, as we can rely on the 
delegated constructor to instantiate debug info.

>From e2bd9040c622d4180668075e42cd67934110916c Mon Sep 17 00:00:00 2001
From: Clayton Knittel <[email protected]>
Date: Sat, 22 Aug 2026 21:25:17 +0000
Subject: [PATCH] Apply constructor homing more aggressively.

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_ constexpr constructors, or _any_
user-defined constructors are excluded from the optimization. This is
being changed to only exclude _defined_ constexpr constructors, as
declared constexpr constructors are not callable in a TU that doesn't
see their definition. Additionally, we ignore 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         | 34 ++++++++++++++++----
 clang/test/DebugInfo/CXX/limited-ctor.cpp | 39 +++++++++++++++++++++++
 2 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 37ee3765fd7c4..4175e2943e924 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2539,10 +2539,12 @@ 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.
+  // 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 CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method))
-      completeUnusedClass(*CD->getParent());
+      if (!CD->isDelegatingConstructor())
+        completeUnusedClass(*CD->getParent());
 
   llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit);
   llvm::DISubprogram *SP = DBuilder.createMethod(
@@ -3236,18 +3238,36 @@ static bool canUseCtorHoming(const CXXRecordDecl *RD) {
   if (isClassOrMethodDLLImport(RD))
     return false;
 
-  if (RD->isLambda() || RD->isAggregate() ||
-      RD->hasTrivialDefaultConstructor() ||
-      RD->hasConstexprNonCopyMoveConstructor())
+  if (RD->isLambda() || RD->isAggregate() || 
RD->hasTrivialDefaultConstructor())
     return false;
 
+  // Skip this optimization if the class has a constexpr default constructor,
+  // since those constructors can be invoked without emitting type information
+  // for the constructor.
+  if (RD->needsImplicitDefaultConstructor() &&
+      RD->defaultedDefaultConstructorIsConstexpr())
+    return false;
+
+  bool HasNonDeletedCtor = false;
   for (const CXXConstructorDecl *Ctor : RD->ctors()) {
     if (Ctor->isCopyOrMoveConstructor())
       continue;
+    const FunctionDecl *Def = nullptr;
+    if (Ctor->isDefined(Def)) {
+      const auto *CtorDef = cast<CXXConstructorDecl>(Def);
+      // Ignore delegating constructors, the target constructor's definition
+      // will emit the type info.
+      if (CtorDef->isDelegatingConstructor())
+        continue;
+      // Skip this optimization if we see a defined constexpr constructor, 
which
+      // can be invoked without emitting type info.
+      if (Ctor->isConstexpr() && !Ctor->isDeleted())
+        return false;
+    }
     if (!Ctor->isDeleted())
-      return true;
+      HasNonDeletedCtor = true;
   }
-  return false;
+  return HasNonDeletedCtor;
 }
 
 static bool shouldOmitDefinition(llvm::codegenoptions::DebugInfoKind DebugKind,
diff --git a/clang/test/DebugInfo/CXX/limited-ctor.cpp 
b/clang/test/DebugInfo/CXX/limited-ctor.cpp
index 18adfdeed0480..df41bb7104c34 100644
--- a/clang/test/DebugInfo/CXX/limited-ctor.cpp
+++ b/clang/test/DebugInfo/CXX/limited-ctor.cpp
@@ -27,6 +27,45 @@ struct E {
   constexpr E(){};
 } TestE;
 
+// Declared but not defined constexpr constructor should not trigger homing.
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: 
"DeclaredConstexpr"{{.*}}flags: DIFlagFwdDecl
+struct DeclaredConstexpr {
+  constexpr DeclaredConstexpr();
+};
+void f(DeclaredConstexpr d) {}
+
+// Defined out-of-line constexpr constructor should trigger homing.
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: 
"OutOfLineConstexpr"{{.*}}DIFlagTypePassByValue
+struct OutOfLineConstexpr {
+  constexpr OutOfLineConstexpr();
+};
+constexpr OutOfLineConstexpr::OutOfLineConstexpr() {}
+OutOfLineConstexpr TestOutOfLineConstexpr;
+
+// Defined delegating constructor where delegated constructor is not defined
+// should not trigger homing.
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: 
"Delegating"{{.*}}flags: DIFlagFwdDecl
+struct Delegating {
+  Delegating() : Delegating(42) {}
+  Delegating(int);
+} TestDelegating;
+
+// Defined delegating constructor where delegated constructor is from a base
+// class should trigger homing.
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: 
"DelegatingToBaseClass"{{.*}}DIFlagTypePassByValue
+struct DelegatingToBaseClass : public Delegating {
+  DelegatingToBaseClass() : Delegating(42) {}
+} TestDelegatingToBaseClass;
+
+// Defined delegating constexpr constructor where delegated constructor is also
+// defined should trigger homing.
+// CHECK-DAG: !DICompositeType(tag: DW_TAG_structure_type, name: 
"DelegatingConstexprBothDefined"{{.*}}DIFlagTypePassByValue
+struct DelegatingConstexprBothDefined {
+  constexpr DelegatingConstexprBothDefined()
+      : DelegatingConstexprBothDefined(42) {}
+  constexpr DelegatingConstexprBothDefined(int) {}
+} TestDelegatingConstexprBothDefined;
+
 // 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

Reply via email to