[clang] 06d202b - [clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations (#154142)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 9 01:50:15 PDT 2025
Author: Michael Buch
Date: 2025-09-09T09:50:11+01:00
New Revision: 06d202b6cb13b38165af03dbf12a3beaac0b38ea
URL: https://github.com/llvm/llvm-project/commit/06d202b6cb13b38165af03dbf12a3beaac0b38ea
DIFF: https://github.com/llvm/llvm-project/commit/06d202b6cb13b38165af03dbf12a3beaac0b38ea.diff
LOG: [clang][DebugInfo] Emit unified (Itanium) mangled name to structor declarations (#154142)
Depends on https://github.com/llvm/llvm-project/pull/154137
This patch is motivated by
https://github.com/llvm/llvm-project/pull/149827, where we plan on using
mangled names on structor declarations to find the exact structor
definition that LLDB's expression evaluator should call.
Given a `DW_TAG_subprogram` for a function declaration, the most
convenient way for a debugger to find the corresponding definition is to
use the `DW_AT_linkage_name` (i.e., the mangled name). However, we
currently can't do that for constructors/destructors because Clang
doesn't attach linkage names to them. This is because, depending on ABI,
there can be multiple definitions for a single constructor/destructor
declaration. The way GCC works around this is by producing a `C4`/`D4`
"unified" mangling for structor declarations (see
[godbolt](https://godbolt.org/z/Wds6cja9K)). GDB uses this to locate the
relevant definitions.
This patch aligns Clang with GCC's DWARF output and allows us to
implement the same lookup scheme in LLDB.
Added:
clang/test/DebugInfo/CXX/local-structor-linkage-names.cpp
clang/test/DebugInfo/CXX/structor-linkage-names.cpp
Modified:
clang/include/clang/Basic/ABI.h
clang/include/clang/Basic/DebugOptions.def
clang/include/clang/Driver/Options.td
clang/lib/AST/ItaniumMangle.cpp
clang/lib/AST/MicrosoftMangle.cpp
clang/lib/CodeGen/CGClass.cpp
clang/lib/CodeGen/CGDebugInfo.cpp
clang/lib/CodeGen/CGDebugInfo.h
clang/lib/CodeGen/ItaniumCXXABI.cpp
clang/lib/CodeGen/MicrosoftCXXABI.cpp
clang/lib/Driver/ToolChains/Clang.cpp
clang/test/DebugInfo/CXX/artificial-arg.cpp
clang/test/DebugInfo/ObjCXX/cyclic.mm
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/ABI.h b/clang/include/clang/Basic/ABI.h
index 231bad799a42c..8279529c316cf 100644
--- a/clang/include/clang/Basic/ABI.h
+++ b/clang/include/clang/Basic/ABI.h
@@ -27,14 +27,16 @@ enum CXXCtorType {
Ctor_Comdat, ///< The COMDAT used for ctors
Ctor_CopyingClosure, ///< Copying closure variant of a ctor
Ctor_DefaultClosure, ///< Default closure variant of a ctor
+ Ctor_Unified, ///< GCC-style unified dtor
};
/// C++ destructor types.
enum CXXDtorType {
- Dtor_Deleting, ///< Deleting dtor
- Dtor_Complete, ///< Complete object dtor
- Dtor_Base, ///< Base object dtor
- Dtor_Comdat ///< The COMDAT used for dtors
+ Dtor_Deleting, ///< Deleting dtor
+ Dtor_Complete, ///< Complete object dtor
+ Dtor_Base, ///< Base object dtor
+ Dtor_Comdat, ///< The COMDAT used for dtors
+ Dtor_Unified, ///< GCC-style unified dtor
};
} // end namespace clang
diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def
index c6e736e92744c..a768b12fa4e0d 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -125,6 +125,12 @@ DEBUGOPT(DebugNameTable, 2, 0, Compatible)
/// Whether to use DWARF base address specifiers in .debug_ranges.
DEBUGOPT(DebugRangesBaseAddress, 1, 0, Compatible)
+/// Whether to add linkage names to constructor/destructor declarations.
+/// This is an escape hatch for cases where attaching the additional linkage
+/// names would increase debug-info size (particularly the .debug_str section)
+/// too much.
+DEBUGOPT(DebugStructorDeclLinkageNames, 1, 0, Benign)
+
/// Whether to embed source in DWARF debug line section.
DEBUGOPT(EmbedSource, 1, 0, Compatible)
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 718808d583e8c..ea5a94f840470 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4789,6 +4789,18 @@ def gembed_source : Flag<["-"], "gembed-source">, Group<g_flags_Group>,
def gno_embed_source : Flag<["-"], "gno-embed-source">, Group<g_flags_Group>,
Flags<[NoXarchOption]>,
HelpText<"Restore the default behavior of not embedding source text in DWARF debug sections">;
+defm structor_decl_linkage_names
+ : BoolGOption<"structor-decl-linkage-names",
+ CodeGenOpts<"DebugStructorDeclLinkageNames">, DefaultTrue,
+ NegFlag<SetFalse>,
+ PosFlag<SetTrue, [], [],
+ "Attach linkage names to C++ constructor/destructor "
+ "declarations in DWARF."
+ "Implies -g.">,
+ BothFlags<[], [ClangOption, CLOption, CC1Option]>>,
+ DocBrief<[{On some ABIs (e.g., Itanium), constructors and destructors may have multiple variants. Historically, when generating DWARF, Clang did not attach ``DW_AT_linkage_name``s to structor DIEs because there were multiple possible manglings (depending on the structor variant) that could be used. With ``-gstructor-decl-linkage-names``, for ABIs with structor variants, we attach a "unified" mangled name to structor declarations DIEs which debuggers can use to look up all the definitions for a structor declaration. E.g., a "unified" mangled name ``_ZN3FooC4Ev`` may have multiple definitions associated with it such as ``_ZN3FooC1Ev`` and ``_ZN3FooC2Ev``.
+
+Enabling this flag results in a better interactive debugging experience (both GDB and LLDB have support for understanding these "unified" linkage names). However, it comes with a significant increase in debug-info size (particularly the `.debug_str` section). As an escape hatch, users can disable this feature using ``-gno-structor-decl-linkage-names``.}]>;
defm key_instructions : BoolGOption<"key-instructions",
CodeGenOpts<"DebugKeyInstructions">, DefaultFalse,
NegFlag<SetFalse>, PosFlag<SetTrue, [], [],
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index ffadfce67d631..163cd43abd45a 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -6026,6 +6026,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
// ::= CI2 <type> # base inheriting constructor
//
// In addition, C5 is a comdat name with C1 and C2 in it.
+ // C4 represents a ctor declaration and is used by debuggers to look up
+ // the various ctor variants.
Out << 'C';
if (InheritedFrom)
Out << 'I';
@@ -6036,6 +6038,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T,
case Ctor_Base:
Out << '2';
break;
+ case Ctor_Unified:
+ Out << '4';
+ break;
case Ctor_Comdat:
Out << '5';
break;
@@ -6053,6 +6058,8 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// ::= D2 # base object destructor
//
// In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it.
+ // D4 represents a dtor declaration and is used by debuggers to look up
+ // the various dtor variants.
switch (T) {
case Dtor_Deleting:
Out << "D0";
@@ -6063,6 +6070,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
case Dtor_Base:
Out << "D2";
break;
+ case Dtor_Unified:
+ Out << "D4";
+ break;
case Dtor_Comdat:
Out << "D5";
break;
diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp
index 2ac38a24456c7..d96472e393f68 100644
--- a/clang/lib/AST/MicrosoftMangle.cpp
+++ b/clang/lib/AST/MicrosoftMangle.cpp
@@ -1496,6 +1496,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) {
// it.
case Dtor_Comdat:
llvm_unreachable("not expecting a COMDAT");
+ case Dtor_Unified:
+ llvm_unreachable("not expecting a unified dtor type");
}
llvm_unreachable("Unsupported dtor type?");
}
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index bae55aa1e1928..6742c196053a2 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1481,6 +1481,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) {
// we'd introduce *two* handler blocks. In the Microsoft ABI, we
// always delegate because we might not have a definition in this TU.
switch (DtorType) {
+ case Dtor_Unified:
+ llvm_unreachable("not expecting a unified dtor");
case Dtor_Comdat: llvm_unreachable("not expecting a COMDAT");
case Dtor_Deleting: llvm_unreachable("already handled deleting case");
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 0385dbdac869b..578d09f7971d6 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -2177,24 +2177,47 @@ static bool isFunctionLocalClass(const CXXRecordDecl *RD) {
return false;
}
+llvm::StringRef
+CGDebugInfo::GetMethodLinkageName(const CXXMethodDecl *Method) const {
+ assert(Method);
+
+ const bool IsCtorOrDtor =
+ isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+
+ if (IsCtorOrDtor && !CGM.getCodeGenOpts().DebugStructorDeclLinkageNames)
+ return {};
+
+ // In some ABIs (particularly Itanium) a single ctor/dtor
+ // corresponds to multiple functions. Attach a "unified"
+ // linkage name for those (which is the convention GCC uses).
+ // Otherwise, attach no linkage name.
+ if (IsCtorOrDtor && !CGM.getTarget().getCXXABI().hasConstructorVariants())
+ return {};
+
+ if (const auto *Ctor = llvm::dyn_cast<CXXConstructorDecl>(Method))
+ return CGM.getMangledName(GlobalDecl(Ctor, CXXCtorType::Ctor_Unified));
+
+ if (const auto *Dtor = llvm::dyn_cast<CXXDestructorDecl>(Method))
+ return CGM.getMangledName(GlobalDecl(Dtor, CXXDtorType::Dtor_Unified));
+
+ return CGM.getMangledName(Method);
+}
+
llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction(
const CXXMethodDecl *Method, llvm::DIFile *Unit, llvm::DIType *RecordTy) {
- bool IsCtorOrDtor =
- isa<CXXConstructorDecl>(Method) || isa<CXXDestructorDecl>(Method);
+ assert(Method);
StringRef MethodName = getFunctionName(Method);
llvm::DISubroutineType *MethodTy = getOrCreateMethodType(Method, Unit);
- // Since a single ctor/dtor corresponds to multiple functions, it doesn't
- // make sense to give a single ctor/dtor a linkage name.
StringRef MethodLinkageName;
// FIXME: 'isFunctionLocalClass' seems like an arbitrary/unintentional
// property to use here. It may've been intended to model "is non-external
// type" but misses cases of non-function-local but non-external classes such
// as those in anonymous namespaces as well as the reverse - external types
// that are function local, such as those in (non-local) inline functions.
- if (!IsCtorOrDtor && !isFunctionLocalClass(Method->getParent()))
- MethodLinkageName = CGM.getMangledName(Method);
+ if (!isFunctionLocalClass(Method->getParent()))
+ MethodLinkageName = GetMethodLinkageName(Method);
// Get the location for the method.
llvm::DIFile *MethodDefUnit = nullptr;
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index ff9c3cd2d1136..f86077369a42a 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -899,6 +899,10 @@ class CGDebugInfo {
std::memcpy(Data + A.size(), B.data(), B.size());
return StringRef(Data, A.size() + B.size());
}
+
+ /// If one exists, returns the linkage name of the specified \
+ /// (non-null) \c Method. Returns empty string otherwise.
+ llvm::StringRef GetMethodLinkageName(const CXXMethodDecl *Method) const;
};
/// A scoped helper to set the current debug location to the specified
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index d5b5fd7200855..7dc2eaf1e9f75 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -91,6 +91,8 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
case Dtor_Comdat:
llvm_unreachable("emitting dtor comdat as function?");
+ case Dtor_Unified:
+ llvm_unreachable("emitting unified dtor as function?");
}
llvm_unreachable("bad dtor kind");
}
@@ -108,6 +110,9 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
case Ctor_Comdat:
llvm_unreachable("emitting ctor comdat as function?");
+
+ case Ctor_Unified:
+ llvm_unreachable("emitting unified ctor as function?");
}
llvm_unreachable("bad dtor kind");
}
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 88f0648660965..94190a149e859 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -77,6 +77,8 @@ class MicrosoftCXXABI : public CGCXXABI {
return false;
case Dtor_Comdat: llvm_unreachable("emitting dtor comdat as function?");
+ case Dtor_Unified:
+ llvm_unreachable("unexpected unified dtor type");
}
llvm_unreachable("bad dtor kind");
}
@@ -1417,6 +1419,8 @@ llvm::GlobalValue::LinkageTypes MicrosoftCXXABI::getCXXDestructorLinkage(
// and are emitted everywhere they are used. They are internal if the class
// is internal.
return llvm::GlobalValue::LinkOnceODRLinkage;
+ case Dtor_Unified:
+ llvm_unreachable("MS C++ ABI does not support unified dtors");
case Dtor_Comdat:
llvm_unreachable("MS C++ ABI does not support comdat dtors");
}
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 21e45c6b56bbb..a357a8828b13d 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -4608,6 +4608,10 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
KeyInstructionsOnByDefault))
CmdArgs.push_back("-gkey-instructions");
+ if (!Args.hasFlag(options::OPT_gstructor_decl_linkage_names,
+ options::OPT_gno_structor_decl_linkage_names, true))
+ CmdArgs.push_back("-gno-structor-decl-linkage-names");
+
if (EmitCodeView) {
CmdArgs.push_back("-gcodeview");
diff --git a/clang/test/DebugInfo/CXX/artificial-arg.cpp b/clang/test/DebugInfo/CXX/artificial-arg.cpp
index a0cf131f83e15..21b8d047b3456 100644
--- a/clang/test/DebugInfo/CXX/artificial-arg.cpp
+++ b/clang/test/DebugInfo/CXX/artificial-arg.cpp
@@ -25,7 +25,8 @@ int main(int argc, char **argv) {
// CHECK: ![[CLASSTYPE:.*]] = distinct !DICompositeType(tag: DW_TAG_class_type, name: "A",
// CHECK-SAME: identifier: "_ZTS1A"
// CHECK: ![[ARTARG:.*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[CLASSTYPE]],{{.*}} DIFlagArtificial
-// CHECK: !DISubprogram(name: "A", scope: ![[CLASSTYPE]]
+// CHECK: !DISubprogram(name: "A"
+// CHECK-SAME: scope: ![[CLASSTYPE]]
// CHECK-SAME: line: 12
// CHECK-SAME: DIFlagPublic
// CHECK: !DISubroutineType(types: [[FUNCTYPE:![0-9]*]])
diff --git a/clang/test/DebugInfo/CXX/local-structor-linkage-names.cpp b/clang/test/DebugInfo/CXX/local-structor-linkage-names.cpp
new file mode 100644
index 0000000000000..4b4261ee3fbd8
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/local-structor-linkage-names.cpp
@@ -0,0 +1,29 @@
+// Tests that we emit don't emit unified constructor/destructor linkage names
+// for function-local constructors.
+
+// Check with -gstructor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
+// RUN: -gstructor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK
+//
+// Check with -gno-structor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
+// RUN: -gno-structor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK
+
+struct HasNestedCtor {
+ HasNestedCtor();
+};
+
+HasNestedCtor::HasNestedCtor() {
+ struct Local {
+ Local() {}
+ ~Local() {}
+ } l;
+}
+
+// CHECK: !DISubprogram(name: "Local"
+// CHECK-NOT: linkageName
+// CHECK-SAME: )
+
+// CHECK: !DISubprogram(name: "~Local"
+// CHECK-NOT: linkageName
+// CHECK-SAME: )
diff --git a/clang/test/DebugInfo/CXX/structor-linkage-names.cpp b/clang/test/DebugInfo/CXX/structor-linkage-names.cpp
new file mode 100644
index 0000000000000..b7aac198c5180
--- /dev/null
+++ b/clang/test/DebugInfo/CXX/structor-linkage-names.cpp
@@ -0,0 +1,89 @@
+// Tests that we emit unified constructor/destructor linkage names
+// for ABIs that support it.
+
+// Check that -gstructor-decl-linkage-names is the default.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
+// RUN: %s -o - | FileCheck %s --check-prefixes=CHECK,ITANIUM
+//
+// Check with -gstructor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
+// RUN: -gstructor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK,ITANIUM
+//
+// Check with -gno-structor-decl-linkage-names.
+// RUN: %clang_cc1 -triple aarch64-apple-macosx -emit-llvm -debug-info-kind=standalone \
+// RUN: -gno-structor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK,DISABLE
+//
+// Check ABI without structor variants.
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -debug-info-kind=standalone \
+// RUN: -gstructor-decl-linkage-names %s -o - | FileCheck %s --check-prefixes=CHECK,MSABI
+
+struct Base {
+ Base(int x);
+ ~Base();
+};
+
+Base::Base(int x) {}
+Base::~Base() {}
+
+// Check that we emit unified ctor/dtor (C4/D4) on Itanium but not for MS-ABI.
+
+// CHECK: ![[BASE_CTOR_DECL:[0-9]+]] = !DISubprogram(name: "Base"
+// MSABI-NOT: linkageName:
+// DISABLE-NOT: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN4BaseC4Ei"
+// CHECK-SAME: spFlags: 0
+
+// CHECK: ![[BASE_DTOR_DECL:[0-9]+]] = !DISubprogram(name: "~Base"
+// MSABI-NOT: linkageName:
+// DISABLE-NOT: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN4BaseD4Ev"
+// CHECK-SAME: spFlags: 0
+
+// Check that the ctor/dtor definitions have linkage names that aren't
+// the ones on the declaration.
+
+// CHECK: !DISubprogram(name: "Base"
+// MSABI-SAME: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN4BaseC2Ei"
+// CHECK-SAME: spFlags: DISPFlagDefinition
+// CHECK-SAME: declaration: ![[BASE_CTOR_DECL]]
+
+// ITANIUM: !DISubprogram(name: "Base"
+// ITANIUM-SAME: linkageName: "_ZN4BaseC1Ei"
+// ITANIUM-SAME: spFlags: DISPFlagDefinition
+// ITANIUM-SAME: declaration: ![[BASE_CTOR_DECL]]
+
+// CHECK: !DISubprogram(name: "~Base"
+// MSABI-SAME: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN4BaseD2Ev"
+// CHECK-SAME: spFlags: DISPFlagDefinition
+// CHECK-SAME: declaration: ![[BASE_DTOR_DECL]]
+
+// ITANIUM: !DISubprogram(name: "~Base"
+// ITANIUM-SAME: linkageName: "_ZN4BaseD1Ev"
+// ITANIUM-SAME: spFlags: DISPFlagDefinition
+// ITANIUM-SAME: declaration: ![[BASE_DTOR_DECL]]
+
+struct Derived : public Base {
+ using Base::Base;
+} d(5);
+
+// CHECK: !DISubprogram(name: "Base"
+// MSABI-SAME: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN7DerivedCI14BaseEi"
+// CHECK-SAME: spFlags: {{.*}}DISPFlagDefinition
+// CHECK-SAME: declaration: ![[BASE_INHERIT_CTOR_DECL:[0-9]+]]
+
+// CHECK: [[BASE_INHERIT_CTOR_DECL]] = !DISubprogram(name: "Base"
+// MSABI-NOT: linkageName:
+// DISABLE-NOT: linkageName:
+// ITANIUM-SAME: linkageName: "_ZN7DerivedCI44BaseEi"
+// CHECK-SAME spFlags: 0
+
+// ITANIUM: !DISubprogram(name: "Base"
+// ITANIUM-SAME: linkageName: "_ZN7DerivedCI24BaseEi"
+// ITANIUM-SAME: spFlags: DISPFlagDefinition
+// ITANIUM-SAME: declaration: ![[BASE_INHERIT_CTOR_DECL:[0-9]+]]
+
+// MSABI: !DISubprogram(name: "~Derived"
+// DISABLE: !DISubprogram(name: "~Derived"
diff --git a/clang/test/DebugInfo/ObjCXX/cyclic.mm b/clang/test/DebugInfo/ObjCXX/cyclic.mm
index 2fb1611c904d0..a062b6ad50612 100644
--- a/clang/test/DebugInfo/ObjCXX/cyclic.mm
+++ b/clang/test/DebugInfo/ObjCXX/cyclic.mm
@@ -10,8 +10,9 @@
// CHECK-SAME: identifier:
// CHECK: ![[BMEMBERS]] = !{![[BB:[0-9]+]]}
B(struct A *);
-// CHECK: ![[BB]] = !DISubprogram(name: "B", scope: ![[B]]
-// CHECK-SAME: line: [[@LINE-2]],
+// CHECK: ![[BB]] = !DISubprogram(name: "B",
+// CHECK-SAME: scope: ![[B]]
+// CHECK-SAME: line: [[@LINE-3]],
// CHECK-SAME: type: ![[TY:[0-9]+]],
// CHECK: ![[TY]] = !DISubroutineType(types: ![[ARGS:[0-9]+]])
// CHECK: ![[ARGS]] = !{null, ![[THIS:[0-9]+]], !{{[^,]+}}}
More information about the cfe-commits
mailing list