https://github.com/Michael137 created https://github.com/llvm/llvm-project/pull/122928
In https://github.com/llvm/llvm-project/pull/122897 we started attaching `DW_AT_object_pointer` to function definitions. This patch does the same but for function declarations (which we do for implicit object pointers already). Fixes https://github.com/llvm/llvm-project/issues/120974 >From b1a937b23f76ac47d1f0340772c17734137eb261 Mon Sep 17 00:00:00 2001 From: Michael Buch <michaelbuc...@gmail.com> Date: Tue, 14 Jan 2025 11:33:33 +0000 Subject: [PATCH] [clang][DebugInfo] Emit DW_AT_object_pointer on function definitions with explicit `this` We currently don't emit `DW_AT_object_pointer` on function declarations or definitions. The DWARFv5 spec doesn't mandate this attribute be present *only* for implicit object parameters: ``` If the member function entry describes a non-static member function, then that entry has a DW_AT_object_pointer attribute whose value is a reference to the formal parameter entry that corresponds to the object for which the function is called. That parameter also has a DW_AT_artificial attribute whose value is true. ``` The part about `DW_AT_artificial` seems overly restrictive, and not true for explicit object parameters. We probably should relax this part of the DWARF spec. This will help LLDB identify static vs. non-static member functions (see https://github.com/llvm/llvm-project/issues/120856). GCC suffers from the same issue: https://godbolt.org/z/h4jeT54G5 Partially fixes https://github.com/llvm/llvm-project/issues/120974 --- clang/lib/CodeGen/CGDebugInfo.cpp | 24 ++++++++++++---- .../CodeGenCXX/debug-info-object-pointer.cpp | 28 +++++++++++++++++++ llvm/include/llvm-c/DebugInfo.h | 11 +++++--- llvm/include/llvm/IR/DIBuilder.h | 6 ++-- llvm/lib/IR/DIBuilder.cpp | 8 ++++-- llvm/lib/IR/DebugInfo.cpp | 9 +++--- 6 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 clang/test/CodeGenCXX/debug-info-object-pointer.cpp diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index d7e5e95b7873a0..3905633468335e 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2016,13 +2016,15 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( // First element is always return type. For 'void' functions it is NULL. Elts.push_back(Args[0]); - // "this" pointer is always first argument. - // ThisPtr may be null if the member function has an explicit 'this' - // parameter. - if (!ThisPtr.isNull()) { + const bool HasExplicitObjectParameter = ThisPtr.isNull(); + + // "this" pointer is always first argument. For explicit "this" + // parameters, it will already be in Args[1]. + if (!HasExplicitObjectParameter) { llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + ThisPtrType = + DBuilder.createObjectPointerType(ThisPtrType, /*Implicit=*/true); Elts.push_back(ThisPtrType); } @@ -2030,6 +2032,13 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( for (unsigned i = 1, e = Args.size(); i != e; ++i) Elts.push_back(Args[i]); + // Attach FlagObjectPointer to the explicit "this" parameter. + if (HasExplicitObjectParameter) { + assert(Elts.size() >= 2 && + "Expected at least return type and object parameter."); + Elts[1] = DBuilder.createObjectPointerType(Args[1], /*Implicit=*/false); + } + llvm::DITypeRefArray EltTypeArray = DBuilder.getOrCreateTypeArray(Elts); return DBuilder.createSubroutineType(EltTypeArray, OriginalFunc->getFlags(), @@ -4829,6 +4838,9 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, if (IPD->getParameterKind() == ImplicitParamKind::CXXThis || IPD->getParameterKind() == ImplicitParamKind::ObjCSelf) Flags |= llvm::DINode::FlagObjectPointer; + } else if (const auto *PVD = dyn_cast<ParmVarDecl>(VD)) { + if (PVD->isExplicitObjectParameter()) + Flags |= llvm::DINode::FlagObjectPointer; } // Note: Older versions of clang used to emit byval references with an extra @@ -5115,7 +5127,7 @@ llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, llvm::DIType *CachedTy = getTypeOrNull(QualTy); if (CachedTy) Ty = CachedTy; - return DBuilder.createObjectPointerType(Ty); + return DBuilder.createObjectPointerType(Ty, /*Implicit=*/true); } void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( diff --git a/clang/test/CodeGenCXX/debug-info-object-pointer.cpp b/clang/test/CodeGenCXX/debug-info-object-pointer.cpp new file mode 100644 index 00000000000000..49079f59909968 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-object-pointer.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -x c++ -std=c++23 -debug-info-kind=limited -emit-llvm < %s | FileCheck %s + +// CHECK: !DISubprogram(name: "bar", +// CHECK-SAME: flags: DIFlagPrototyped +// CHECK: !DIDerivedType(tag: DW_TAG_pointer_type +// CHECK-SAME: flags: DIFlagArtificial | DIFlagObjectPointer +// +// CHECK: !DISubprogram(name: "explicit_this", +// flags: DIFlagPrototyped +// +// CHECK: !DIDerivedType(tag: DW_TAG_rvalue_reference_type +// CHECK-SAME: flags: DIFlagObjectPointer) +// +// CHECK: !DILocalVariable(name: "this", arg: 1 +// CHECK-SAME: flags: DIFlagArtificial | DIFlagObjectPointer +// +// CHECK-NOT: DIFlagArtificial +// CHECK: !DILocalVariable(arg: 1, {{.*}}, flags: DIFlagObjectPointer) + +struct Foo { + void bar() {} + void explicit_this(this Foo &&) {} +}; + +void f() { + Foo{}.bar(); + Foo{}.explicit_this(); +} diff --git a/llvm/include/llvm-c/DebugInfo.h b/llvm/include/llvm-c/DebugInfo.h index 07f87d44088e7e..ac7ee5a7cc9a19 100644 --- a/llvm/include/llvm-c/DebugInfo.h +++ b/llvm/include/llvm-c/DebugInfo.h @@ -870,13 +870,16 @@ LLVMDIBuilderCreateObjCProperty(LLVMDIBuilderRef Builder, LLVMMetadataRef Ty); /** - * Create a uniqued DIType* clone with FlagObjectPointer and FlagArtificial set. + * Create a uniqued DIType* clone with FlagObjectPointer. If \c Implicit + * is true, then also set FlagArtificial. * \param Builder The DIBuilder. * \param Type The underlying type to which this pointer points. + * \param Implicit Indicates whether this pointer was implicitly generated + * (i.e., not spelled out in source). */ -LLVMMetadataRef -LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, - LLVMMetadataRef Type); +LLVMMetadataRef LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type, + LLVMBool Implicit); /** * Create debugging information entry for a qualified diff --git a/llvm/include/llvm/IR/DIBuilder.h b/llvm/include/llvm/IR/DIBuilder.h index cb1150c269a1da..6c479415b9ed27 100644 --- a/llvm/include/llvm/IR/DIBuilder.h +++ b/llvm/include/llvm/IR/DIBuilder.h @@ -662,9 +662,9 @@ namespace llvm { /// Create a uniqued clone of \p Ty with FlagArtificial set. static DIType *createArtificialType(DIType *Ty); - /// Create a uniqued clone of \p Ty with FlagObjectPointer and - /// FlagArtificial set. - static DIType *createObjectPointerType(DIType *Ty); + /// Create a uniqued clone of \p Ty with FlagObjectPointer set. + /// If \p Implicit is true, also set FlagArtificial. + static DIType *createObjectPointerType(DIType *Ty, bool Implicit); /// Create a permanent forward-declared type. DICompositeType *createForwardDecl(unsigned Tag, StringRef Name, diff --git a/llvm/lib/IR/DIBuilder.cpp b/llvm/lib/IR/DIBuilder.cpp index b240a2a39de362..d9bd4f11e89a39 100644 --- a/llvm/lib/IR/DIBuilder.cpp +++ b/llvm/lib/IR/DIBuilder.cpp @@ -644,11 +644,15 @@ DIType *DIBuilder::createArtificialType(DIType *Ty) { return createTypeWithFlags(Ty, DINode::FlagArtificial); } -DIType *DIBuilder::createObjectPointerType(DIType *Ty) { +DIType *DIBuilder::createObjectPointerType(DIType *Ty, bool Implicit) { // FIXME: Restrict this to the nodes where it's valid. if (Ty->isObjectPointer()) return Ty; - DINode::DIFlags Flags = DINode::FlagObjectPointer | DINode::FlagArtificial; + DINode::DIFlags Flags = DINode::FlagObjectPointer; + + if (Implicit) + Flags |= DINode::FlagArtificial; + return createTypeWithFlags(Ty, Flags); } diff --git a/llvm/lib/IR/DebugInfo.cpp b/llvm/lib/IR/DebugInfo.cpp index e5b45e0082a823..4ce518009bd3ea 100644 --- a/llvm/lib/IR/DebugInfo.cpp +++ b/llvm/lib/IR/DebugInfo.cpp @@ -1432,10 +1432,11 @@ LLVMDIBuilderCreateObjCProperty(LLVMDIBuilderRef Builder, PropertyAttributes, unwrapDI<DIType>(Ty))); } -LLVMMetadataRef -LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, - LLVMMetadataRef Type) { - return wrap(unwrap(Builder)->createObjectPointerType(unwrapDI<DIType>(Type))); +LLVMMetadataRef LLVMDIBuilderCreateObjectPointerType(LLVMDIBuilderRef Builder, + LLVMMetadataRef Type, + LLVMBool Implicit) { + return wrap(unwrap(Builder)->createObjectPointerType(unwrapDI<DIType>(Type), + Implicit)); } LLVMMetadataRef _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits