https://github.com/JustinStitt updated 
https://github.com/llvm/llvm-project/pull/174892

>From 401a61f5fbc9a65560a6419621a7abb46e126a8e Mon Sep 17 00:00:00 2001
From: Justin Stitt <[email protected]>
Date: Tue, 6 Jan 2026 15:36:33 -0800
Subject: [PATCH 1/3] [Clang] Implement inlining hints for
 __attribute__((warnning/error))

When functions marked with __attribute__((warning/error)) are called
through inlined functions, Clang now shows the inlining chain that led
to the call.

The two modes are:

- ``heuristic`` tries to guess which functions will be inlined to
  minimize the amount of source locations kept in memory and visible in
  LLVM IR.

- ``debug`` leverages minimal debug directive tracking infrastructure to
  get more reliable source locations over the heuristic mode while
  having more compile-time overhead.

``debug`` mode is enabled when debug information
``-gline-directives-only`` (implied by ``-g1`` or higher) is available.
If this debug information is not available, the ``heuristic`` mode is
used which represents a best-effort approach towards accurate inline
hints. When the heuristic fails and we cannot show an accurate source
location for one or more hints, the source location of the initial
warning is used -- completely wrong locations are never used.

Fixes: https://github.com/ClangBuiltLinux/linux/issues/1571
Based-on: https://github.com/llvm/llvm-project/pull/73552
Signed-off-by: Justin Stitt <[email protected]>
---
 clang/docs/ReleaseNotes.rst                   |   9 ++
 clang/include/clang/Basic/AttrDocs.td         |   9 ++
 .../clang/Basic/DiagnosticFrontendKinds.td    |   6 +
 clang/include/clang/Options/Options.td        |  10 +-
 clang/lib/CodeGen/CGCall.cpp                  |  24 ++--
 clang/lib/CodeGen/CodeGenAction.cpp           |  38 ++++++
 clang/test/CodeGen/attr-nomerge.cpp           |   6 +-
 clang/test/CodeGenCXX/builtin-invoke.cpp      |   4 +-
 .../inheriting-constructor-cleanup.cpp        |   2 +-
 .../test/CodeGenCXX/type-aware-allocators.cpp |   2 +-
 .../coro-await-resume-eh.cpp                  |   2 +-
 clang/test/DebugInfo/CXX/member-call.cpp      |   4 +-
 .../backend-attribute-inlining-cross-tu.c     |  67 +++++++++++
 ...-attribute-inlining-debug-vs-heuristic.cpp |  92 ++++++++++++++
 .../backend-attribute-inlining-modes.c        |  32 +++++
 .../Frontend/backend-attribute-inlining.c     | 112 ++++++++++++++++++
 ...ibute_parallel_for_num_threads_codegen.cpp |   8 +-
 ..._parallel_for_simd_num_threads_codegen.cpp |  12 +-
 clang/test/OpenMP/scope_codegen.cpp           |   8 +-
 clang/test/OpenMP/single_codegen.cpp          |  12 +-
 ...ibute_parallel_for_num_threads_codegen.cpp |   4 +-
 ..._parallel_for_simd_num_threads_codegen.cpp |   6 +-
 clang/test/OpenMP/threadprivate_codegen.cpp   |  42 +++----
 .../Inputs/basic-cplusplus.cpp.expected       |  41 +++++--
 ...plicit-template-instantiation.cpp.expected |  20 ++--
 llvm/include/llvm/IR/DiagnosticInfo.h         |  26 +++-
 llvm/lib/IR/DiagnosticInfo.cpp                |  38 +++++-
 llvm/lib/Transforms/Utils/InlineFunction.cpp  |  44 +++++++
 28 files changed, 588 insertions(+), 92 deletions(-)
 create mode 100644 clang/test/Frontend/backend-attribute-inlining-cross-tu.c
 create mode 100644 
clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
 create mode 100644 clang/test/Frontend/backend-attribute-inlining-modes.c
 create mode 100644 clang/test/Frontend/backend-attribute-inlining.c

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 489a91d439133..17aa673296d13 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -187,6 +187,15 @@ Improvements to Clang's diagnostics
     int* p(int *in [[clang::noescape]]) { return in; }
                                                  ^~
 
+- ``[[gnu::warning]]`` and ``[[gnu::error]]`` diagnostics now have notes
+  describing inlining locations. When a function with these attributes is
+  called from an inlined context, Clang can now show which functions were
+  inlined to reach the call. When debug info is available
+  (``-gline-directives-only`` (implicitly enabled at ``-g1``) or higher),
+  accurate source locations are used; otherwise, a heuristic fallback is used
+  with a note suggesting how to enable debug info for better accuracy.
+
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Basic/AttrDocs.td 
b/clang/include/clang/Basic/AttrDocs.td
index 6e2c73f924352..0d72688d80c50 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -8411,6 +8411,15 @@ pointing to precise locations of the call site in the 
source.
       dontcall(); // No Warning
     sizeof(dontcall()); // No Warning
   }
+
+When the call occurs through inlined functions, the inlining chain that led to
+the call is shown. This helps identify which call site triggered the diagnostic
+when the attributed function is called from multiple locations through inline
+functions.
+
+The most accurate source location information for inline notes can be obtained
+when ``-gline-directives-only`` (implied by ``-g1`` or higher) is enabled.
+Otherwise, a heuristic approach is used to track source locations.
   }];
 }
 
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index e2b257ceae80d..8180766d63464 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -94,6 +94,12 @@ def err_fe_backend_error_attr :
 def warn_fe_backend_warning_attr :
   Warning<"call to '%0' declared with 'warning' attribute: %1">, BackendInfo,
   InGroup<BackendWarningAttributes>;
+def note_fe_backend_in : Note<"called by function '%0'">, BackendInfo;
+def note_fe_backend_inlined : Note<"inlined by function '%0'">, BackendInfo;
+def note_fe_backend_inlining_debug_info
+    : Note<"use '-gline-directives-only' (implied by '-g1') or higher for "
+           "more accurate inlining chain locations">,
+      BackendInfo;
 def warn_toc_unsupported_type : Warning<"-mtocdata option is ignored "
   "for %0 because %1">, InGroup<BackendWarningAttributes>;
 
diff --git a/clang/include/clang/Options/Options.td 
b/clang/include/clang/Options/Options.td
index a08100ef9d0cd..796cba4fb2fb5 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -2168,10 +2168,12 @@ defm diagnostics_show_option : 
BoolFOption<"diagnostics-show-option",
     DiagnosticOpts<"ShowOptionNames">, DefaultTrue,
     NegFlag<SetFalse, [], [ClangOption, CC1Option]>,
     PosFlag<SetTrue, [], [ClangOption], "Print option name with mappable 
diagnostics">>;
-defm diagnostics_show_note_include_stack : 
BoolFOption<"diagnostics-show-note-include-stack",
-    DiagnosticOpts<"ShowNoteIncludeStack">, DefaultFalse,
-    PosFlag<SetTrue, [], [ClangOption], "Display include stacks for diagnostic 
notes">,
-    NegFlag<SetFalse>, BothFlags<[], [ClangOption, CC1Option]>>;
+defm diagnostics_show_note_include_stack
+    : BoolFOption<"diagnostics-show-note-include-stack",
+                  DiagnosticOpts<"ShowNoteIncludeStack">, DefaultFalse,
+                  PosFlag<SetTrue, [], [ClangOption],
+                          "Display include stacks for diagnostic notes">,
+                  NegFlag<SetFalse>, BothFlags<[], [ClangOption, CC1Option]>>;
 def fdiagnostics_format_EQ : Joined<["-"], "fdiagnostics-format=">, 
Group<f_clang_Group>;
 def fdiagnostics_show_category_EQ : Joined<["-"], 
"fdiagnostics-show-category=">, Group<f_clang_Group>;
 def fdiagnostics_show_template_tree : Flag<["-"], 
"fdiagnostics-show-template-tree">,
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 04f44146e1269..9afb942a0df13 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6064,13 +6064,23 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   if (getDebugInfo() && TargetDecl && TargetDecl->hasAttr<MSAllocatorAttr>())
     getDebugInfo()->addHeapAllocSiteMetadata(CI, RetTy->getPointeeType(), Loc);
 
-  // Add metadata if calling an __attribute__((error(""))) or warning fn.
-  if (TargetDecl && TargetDecl->hasAttr<ErrorAttr>()) {
-    llvm::ConstantInt *Line =
-        llvm::ConstantInt::get(Int64Ty, Loc.getRawEncoding());
-    llvm::ConstantAsMetadata *MD = llvm::ConstantAsMetadata::get(Line);
-    llvm::MDTuple *MDT = llvm::MDNode::get(getLLVMContext(), {MD});
-    CI->setMetadata("srcloc", MDT);
+  // Add srcloc metadata for [[gnu::error/warning]] diagnostics. Track
+  // inline/static calls for the heuristic fallback when debug info is not
+  // available. This heuristic is conservative and best-effort since static or
+  // inline-annotated functions are still not guaranteed to be inlined.
+  if (TargetDecl) {
+    bool NeedSrcLoc = TargetDecl->hasAttr<ErrorAttr>();
+    if (!NeedSrcLoc) {
+      if (const auto *FD = dyn_cast<FunctionDecl>(TargetDecl))
+        NeedSrcLoc = FD->isInlined() || FD->hasAttr<AlwaysInlineAttr>() ||
+                     FD->getStorageClass() == SC_Static ||
+                     FD->isInAnonymousNamespace();
+    }
+    if (NeedSrcLoc) {
+      auto *Line = llvm::ConstantInt::get(Int64Ty, Loc.getRawEncoding());
+      auto *MD = llvm::ConstantAsMetadata::get(Line);
+      CI->setMetadata("srcloc", llvm::MDNode::get(getLLVMContext(), {MD}));
+    }
   }
 
   // 4. Finish the call.
diff --git a/clang/lib/CodeGen/CodeGenAction.cpp 
b/clang/lib/CodeGen/CodeGenAction.cpp
index a5ef4ac9d361d..3e492b9517fe2 100644
--- a/clang/lib/CodeGen/CodeGenAction.cpp
+++ b/clang/lib/CodeGen/CodeGenAction.cpp
@@ -732,6 +732,44 @@ void BackendConsumer::DontCallDiagHandler(const 
DiagnosticInfoDontCall &D) {
                               ? diag::err_fe_backend_error_attr
                               : diag::warn_fe_backend_warning_attr)
       << llvm::demangle(D.getFunctionName()) << D.getNote();
+
+  auto EmitNote = [&](SourceLocation Loc, StringRef FuncName, bool IsFirst) {
+    if (!Loc.isValid())
+      Loc = LocCookie;
+    unsigned DiagID =
+        IsFirst ? diag::note_fe_backend_in : diag::note_fe_backend_inlined;
+    Diags.Report(Loc, DiagID) << llvm::demangle(FuncName.str());
+  };
+
+  // Try debug info first for accurate source locations.
+  if (!D.getDebugInlineChain().empty()) {
+    SourceManager &SM = Context->getSourceManager();
+    FileManager &FM = SM.getFileManager();
+    for (const auto &[I, Info] : llvm::enumerate(D.getDebugInlineChain())) {
+      SourceLocation Loc;
+      if (Info.Line > 0)
+        if (auto FE = FM.getOptionalFileRef(Info.Filename))
+          Loc = SM.translateFileLineCol(*FE, Info.Line,
+                                        Info.Column ? Info.Column : 1);
+      EmitNote(Loc, Info.FuncName, I == 0);
+    }
+    return;
+  }
+
+  // Fall back to heuristic (srcloc metadata) when debug info is unavailable.
+  auto InliningDecisions = D.getInliningDecisions();
+  if (InliningDecisions.empty())
+    return;
+
+  for (const auto &[I, Entry] : llvm::enumerate(InliningDecisions)) {
+    SourceLocation Loc =
+        I == 0 ? LocCookie : SourceLocation::getFromRawEncoding(Entry.second);
+    EmitNote(Loc, Entry.first, I == 0);
+  }
+
+  // Suggest enabling debug info (at least -gline-directives-only) for more
+  // accurate locations.
+  Diags.Report(LocCookie, diag::note_fe_backend_inlining_debug_info);
 }
 
 void BackendConsumer::MisExpectDiagHandler(
diff --git a/clang/test/CodeGen/attr-nomerge.cpp 
b/clang/test/CodeGen/attr-nomerge.cpp
index 1cf5bb1619b31..f9c0235de89f9 100644
--- a/clang/test/CodeGen/attr-nomerge.cpp
+++ b/clang/test/CodeGen/attr-nomerge.cpp
@@ -92,10 +92,10 @@ void something_else_again() {
 // CHECK: call void @_ZN1AC1Ev({{.*}}) #[[ATTR0]]
 // CHECK: call void @_ZN1A1fEv({{.*}}) #[[ATTR0]]
 // CHECK: call void @_ZN1A1gEv({{.*}}) #[[ATTR0]]
-// CHECK: call void @_ZN1A2f1Ev() #[[ATTR0]]
-// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}}
+// CHECK: call void @_ZN1A2f1Ev(){{.*}}#[[ATTR0]]
+// CHECK: call void @_ZN1BC1Ev({{.*}}){{.*}}{{$}}
 // CHECK: call void @_ZN1B1gEv({{.*}}){{$}}
-// CHECK: call void @_ZN1BC1Ev({{.*}}){{$}}
+// CHECK: call void @_ZN1BC1Ev({{.*}}){{.*}}{{$}}
 // CHECK: load ptr, ptr
 // CHECK: load ptr, ptr
 // CHECK: %[[AG:.*]] = load ptr, ptr
diff --git a/clang/test/CodeGenCXX/builtin-invoke.cpp 
b/clang/test/CodeGenCXX/builtin-invoke.cpp
index 0f84f83e18add..a4f65f1a5df1e 100644
--- a/clang/test/CodeGenCXX/builtin-invoke.cpp
+++ b/clang/test/CodeGenCXX/builtin-invoke.cpp
@@ -47,8 +47,8 @@ extern "C" void call_memptr(std::reference_wrapper<Callable> 
wrapper) {
   // CHECK-EMPTY:
   // CHECK-NEXT: memptr.virtual:
   // CHECK-NEXT:   %vtable = load ptr, ptr %0, align 8
-  // CHECK-NEXT:   %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint 
(ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize !2
-  // CHECK-NEXT:   %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize 
!2
+  // CHECK-NEXT:   %1 = getelementptr i8, ptr %vtable, i64 sub (i64 ptrtoint 
(ptr @_ZN8Callable4funcEv to i64), i64 1), !nosanitize !
+  // CHECK-NEXT:   %memptr.virtualfn = load ptr, ptr %1, align 8, !nosanitize !
   // CHECK-NEXT:   br label %memptr.end
   // CHECK-EMPTY:
   // CHECK-NEXT: memptr.nonvirtual:
diff --git a/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp 
b/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp
index 722166fd86488..fc350bca36b98 100644
--- a/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp
+++ b/clang/test/CodeGenCXX/inheriting-constructor-cleanup.cpp
@@ -37,7 +37,7 @@ void f() {
   // EXCEPTIONS: %[[TMP1:.*]] = alloca %struct.S1
   // EXCEPTIONS: %[[TMP2:.*]] = alloca %struct.S2
   // EXCEPTIONS: invoke void (ptr, ptr, ptr, ptr, ...) 
@_ZN4BaseC2ERK2S1RK2S2PKcz(ptr {{.*}}, ptr noundef nonnull align 1 
dereferenceable(1) %[[TMP1]], ptr noundef nonnull align 1 dereferenceable(1) 
%[[TMP2]], ptr {{.*}})
-  // EXCEPTIONS-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]]
+  // EXCEPTIONS-NEXT: to label %[[CONT:.*]] unwind label %[[LPAD:.*]], !srcloc
 
   // EXCEPTIONS: [[CONT]]:
   // EXCEPTIONS-NEXT: call void @_ZN9InheritorD1Ev(ptr {{.*}})
diff --git a/clang/test/CodeGenCXX/type-aware-allocators.cpp 
b/clang/test/CodeGenCXX/type-aware-allocators.cpp
index cce9197ed0d12..a91087aa4b659 100644
--- a/clang/test/CodeGenCXX/type-aware-allocators.cpp
+++ b/clang/test/CodeGenCXX/type-aware-allocators.cpp
@@ -163,7 +163,7 @@ extern "C" void test_ensure_type_aware_overrides() {
 // CHECK: call void [[S6_DFN]](
 // CHECK: [[S7_ALLOC:%.*]] = call {{.*}} 
@_ZN2S6nwI2S7EEPvSt13type_identityIT_EmSt11align_val_t(
 // CHECK: @_ZN2S7C1Ev({{.*}}[[S7_ALLOC]])
-// CHECK-NEXT: unwind label %[[S7LPAD:.*]]
+// CHECK-NEXT: unwind label %[[S7LPAD:.*]], !srcloc
 // CHECK: [[S7_VTABLE:%vtable.*]] = load
 // CHECK: [[S7_DFN_ADDR:%.*]] = getelementptr inbounds ptr, ptr [[S7_VTABLE]], 
i64 1
 // CHECK: [[S7_DFN:%.*]] = load ptr, ptr [[S7_DFN_ADDR]]
diff --git a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp 
b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
index 8253337ba7390..1ad8fe0cc43ba 100644
--- a/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
+++ b/clang/test/CodeGenCoroutines/coro-await-resume-eh.cpp
@@ -34,7 +34,7 @@ throwing_task f() {
   // CHECK: init.ready:
   // CHECK-NEXT: store i1 true, ptr %[[RESUMETHREW:.+]], align 1
   // CHECK-NEXT: invoke void @_ZN18throwing_awaitable12await_resumeEv
-  // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]]
+  // CHECK-NEXT: to label %[[RESUMECONT:.+]] unwind label %[[RESUMELPAD:.+]], 
!srcloc
 
   // If 'await_resume' does not throw an exception, 'false' is stored in
   // variable RESUMETHREW.
diff --git a/clang/test/DebugInfo/CXX/member-call.cpp 
b/clang/test/DebugInfo/CXX/member-call.cpp
index 2b60de8aee491..d73147ba8efb6 100644
--- a/clang/test/DebugInfo/CXX/member-call.cpp
+++ b/clang/test/DebugInfo/CXX/member-call.cpp
@@ -16,8 +16,8 @@ void test(Foo *f) {
 }
 
 // CHECK-LABEL: @_Z4testP3Foo
-// CHECK: call {{.*}} @_ZN3Foo3fooEv{{.*}}, !dbg ![[CALL1LOC:.*]]
-// CHECK: call void @_ZN3Bar3barEv{{.*}}, !dbg ![[CALL2LOC:.*]]
+// CHECK: call {{.*}} @_ZN3Foo3fooEv{{.*}}, !dbg ![[CALL1LOC:.*]], !srcloc
+// CHECK: call void @_ZN3Bar3barEv{{.*}}, !dbg ![[CALL2LOC:.*]], !srcloc
 
 // CHECK: ![[CALL1LOC]] = !DILocation(line: [[LINE:[0-9]+]], column: 6,
 // CHECK: ![[CALL2LOC]] = !DILocation(line: [[LINE]], column: 13,
diff --git a/clang/test/Frontend/backend-attribute-inlining-cross-tu.c 
b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c
new file mode 100644
index 0000000000000..18cc0606e1bb5
--- /dev/null
+++ b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c
@@ -0,0 +1,67 @@
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+// RUN: not %clang -O2 -S %t/main.c -I%t -o /dev/null 2>&1 | FileCheck %s
+
+// Cross-TU inlining: header functions inlined into source file.
+
+//--- overflow.h
+[[gnu::warning("write overflow")]]
+void __write_overflow(void);
+
+[[gnu::error("read overflow")]]
+void __read_overflow(void);
+
+static inline void check_write(int size) {
+  if (size > 100)
+    __write_overflow();
+}
+
+static inline void check_read(int size) {
+  if (size > 50)
+    __read_overflow();
+}
+
+static inline void check_both(int size) {
+  check_write(size);
+  check_read(size);
+}
+
+//--- main.c
+#include "overflow.h"
+
+void test_simple_cross_tu(void) {
+  check_write(200);
+}
+// CHECK: warning: call to '__write_overflow' declared with 'warning' 
attribute: write overflow
+// CHECK: note: called by function 'check_write'
+// CHECK: main.c:{{.*}}: note: inlined by function 'test_simple_cross_tu'
+
+// Nested cross-TU inlining (header -> header -> source).
+static inline void local_wrapper(int x) {
+  check_both(x);
+}
+
+void test_nested_cross_tu(void) {
+  local_wrapper(200);
+}
+// CHECK: warning: call to '__write_overflow' declared with 'warning' 
attribute: write overflow
+// CHECK: note: called by function 'check_write'
+// CHECK: overflow.h:{{.*}}: note: inlined by function 'check_both'
+// CHECK: main.c:{{.*}}: note: inlined by function 'local_wrapper'
+// CHECK: main.c:{{.*}}: note: inlined by function 'test_nested_cross_tu'
+
+// CHECK: error: call to '__read_overflow' declared with 'error' attribute: 
read overflow
+// CHECK: note: called by function 'check_read'
+// CHECK: overflow.h:{{.*}}: note: inlined by function 'check_both'
+// CHECK: main.c:{{.*}}: note: inlined by function 'local_wrapper'
+// CHECK: main.c:{{.*}}: note: inlined by function 'test_nested_cross_tu'
+
+void test_error_cross_tu(void) {
+  check_read(100);
+}
+// CHECK: error: call to '__read_overflow' declared with 'error' attribute: 
read overflow
+// CHECK: note: called by function 'check_read'
+// CHECK: main.c:{{.*}}: note: inlined by function 'test_error_cross_tu'
+
+// Fallback note should appear (no debug info).
+// CHECK: note: use '-gline-directives-only' (implied by '-g1') or higher for 
more accurate inlining chain locations
diff --git 
a/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp 
b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
new file mode 100644
index 0000000000000..65e4eea8f2a44
--- /dev/null
+++ b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -O2 -emit-obj %s -o /dev/null 2>&1 | FileCheck %s 
--check-prefix=HEURISTIC
+// RUN: %clang_cc1 -O2 -emit-obj -debug-info-kind=line-directives-only %s -o 
/dev/null 2>&1 | FileCheck %s --check-prefix=DEBUG
+
+// Verify auto-selection works between debug info and heuristic fallback. When
+// we have at least -gline-directives-only we can use DILocation for accurate
+// inline locations.
+
+// Without that debug info we fall back to a heuristic approach using srcloc
+// metadata.
+
+[[gnu::warning("dangerous function")]]
+void dangerous();
+
+// Non-static, non-inline functions that get inlined at -O2.
+void wrapper() {
+    dangerous();
+}
+
+void middle() {
+    wrapper();
+}
+
+void caller() {
+    middle();
+}
+
+
+// HEURISTIC: :16:{{.*}}: warning: call to '{{.*}}dangerous{{.*}}'
+// HEURISTIC: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}'
+// HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}middle{{.*}}'
+// HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}caller{{.*}}'
+// HEURISTIC: note: use '-gline-directives-only' (implied by '-g1') or higher 
for more accurate inlining chain locations
+
+// DEBUG: :16:{{.*}}: warning: call to '{{.*}}dangerous{{.*}}'
+// DEBUG: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}'
+// DEBUG: :20:{{.*}}: note: inlined by function '{{.*}}middle{{.*}}'
+// DEBUG: :24:{{.*}}: note: inlined by function '{{.*}}caller{{.*}}'
+// DEBUG-NOT: note: use '-gline-directives-only'
+
+// Test that functions in anonymous namespaces are properly tracked for
+// inlining chain diagnostics. Anonymous namespace functions have internal
+// linkage and are prime candidates for inlining.
+
+[[gnu::warning("do not call")]]
+void bad_func();
+
+namespace {
+void anon_helper() {
+    bad_func();
+}
+
+void anon_middle() {
+    anon_helper();
+}
+} // namespace
+
+void public_caller() {
+    anon_middle();
+}
+
+// HEURISTIC: :49:{{.*}}: warning: call to '{{.*}}bad_func{{.*}}'
+// HEURISTIC: :49:{{.*}}: note: called by function '{{.*}}anon_helper{{.*}}'
+// HEURISTIC: :53:{{.*}}: note: inlined by function '{{.*}}anon_middle{{.*}}'
+// HEURISTIC: :58:{{.*}}: note: inlined by function '{{.*}}public_caller{{.*}}'
+
+// DEBUG: :49:{{.*}}: warning: call to '{{.*}}bad_func{{.*}}'
+// DEBUG: :49:{{.*}}: note: called by function '{{.*}}anon_helper{{.*}}'
+// DEBUG: :53:{{.*}}: note: inlined by function '{{.*}}anon_middle{{.*}}'
+// DEBUG: :58:{{.*}}: note: inlined by function '{{.*}}public_caller{{.*}}'
+
+// always_inline forces inlining but doesn't imply
+// isInlined() in the language sense.
+
+[[gnu::warning("always inline warning")]]
+void always_inline_target();
+
+__attribute__((always_inline))
+void always_inline_wrapper() {
+    always_inline_target();
+}
+
+void always_inline_caller() {
+    always_inline_wrapper();
+}
+
+// HEURISTIC: :79:{{.*}}: warning: call to '{{.*}}always_inline_target{{.*}}'
+// HEURISTIC: :79:{{.*}}: note: called by function 
'{{.*}}always_inline_wrapper{{.*}}'
+// HEURISTIC: :83:{{.*}}: note: inlined by function 
'{{.*}}always_inline_caller{{.*}}'
+
+// DEBUG: :79:{{.*}}: warning: call to '{{.*}}always_inline_target{{.*}}'
+// DEBUG: :79:{{.*}}: note: called by function 
'{{.*}}always_inline_wrapper{{.*}}'
+// DEBUG: :83:{{.*}}: note: inlined by function 
'{{.*}}always_inline_caller{{.*}}'
diff --git a/clang/test/Frontend/backend-attribute-inlining-modes.c 
b/clang/test/Frontend/backend-attribute-inlining-modes.c
new file mode 100644
index 0000000000000..653e5bb0390bd
--- /dev/null
+++ b/clang/test/Frontend/backend-attribute-inlining-modes.c
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -O2 -emit-obj %s -o /dev/null 2>&1 | FileCheck %s 
--check-prefix=ENABLED-HEURISTIC
+// RUN: %clang_cc1 -O2 -emit-obj -debug-info-kind=line-directives-only %s -o 
/dev/null 2>&1 | FileCheck %s --check-prefix=ENABLED-DEBUG
+
+[[gnu::warning("do not call")]]
+void bad_func(void);
+
+static inline void level1(void) {
+    bad_func();
+}
+
+static inline void level2(void) {
+    level1();
+}
+
+void entry(void) {
+    level2();
+}
+
+// Enabled without debug info: heuristic fallback.
+// All notes point to original call site (:14).
+// ENABLED-HEURISTIC: :8:{{.*}}: warning: call to 'bad_func'
+// ENABLED-HEURISTIC: :8:{{.*}}: note: called by function 'level1'
+// ENABLED-HEURISTIC: :12:{{.*}}: note: inlined by function 'level2'
+// ENABLED-HEURISTIC: :16:{{.*}}: note: inlined by function 'entry'
+// ENABLED-HEURISTIC: note: use '-gline-directives-only' (implied by '-g1') or 
higher for more accurate inlining chain locations
+
+// Enabled with debug info: accurate locations.
+// ENABLED-DEBUG: :8:{{.*}}: warning: call to 'bad_func'
+// ENABLED-DEBUG: :8:{{.*}}: note: called by function 'level1'
+// ENABLED-DEBUG: :12:{{.*}}: note: inlined by function 'level2'
+// ENABLED-DEBUG: :16:{{.*}}: note: inlined by function 'entry'
+// ENABLED-DEBUG-NOT: note: use '-gline-directives-only'
diff --git a/clang/test/Frontend/backend-attribute-inlining.c 
b/clang/test/Frontend/backend-attribute-inlining.c
new file mode 100644
index 0000000000000..0c49c395b3f83
--- /dev/null
+++ b/clang/test/Frontend/backend-attribute-inlining.c
@@ -0,0 +1,112 @@
+// RUN: not %clang -O2 -S %s -o /dev/null 2>&1 | FileCheck %s
+
+// Single-level inlining with warning attribute.
+[[gnu::warning("do not call directly")]]
+void __warn_single(void);
+
+static inline void warn_wrapper(void) {
+  __warn_single();
+}
+
+void test_single_level(void) {
+  warn_wrapper();
+}
+// CHECK: warning: call to '__warn_single' declared with 'warning' attribute: 
do not call directly
+// CHECK: note: called by function 'warn_wrapper'
+// CHECK: :12:{{.*}}: note: inlined by function 'test_single_level'
+
+// Error attribute with inlining.
+[[gnu::error("never call this")]]
+void __error_func(void);
+
+static inline void error_wrapper(void) {
+  __error_func();
+}
+
+void test_error_inlined(void) {
+  error_wrapper();
+}
+// CHECK: error: call to '__error_func' declared with 'error' attribute: never 
call this
+// CHECK: note: called by function 'error_wrapper'
+// CHECK: :27:{{.*}}: note: inlined by function 'test_error_inlined'
+
+// Deep nesting (5 levels).
+[[gnu::warning("deep call")]]
+void __warn_deep(void);
+
+static inline void deep1(void) { __warn_deep(); }
+static inline void deep2(void) { deep1(); }
+static inline void deep3(void) { deep2(); }
+static inline void deep4(void) { deep3(); }
+static inline void deep5(void) { deep4(); }
+
+void test_deep_nesting(void) {
+  deep5();
+}
+// CHECK: warning: call to '__warn_deep' declared with 'warning' attribute: 
deep call
+// CHECK: note: called by function 'deep1'
+// CHECK: :38:{{.*}}: note: inlined by function 'deep2'
+// CHECK: :39:{{.*}}: note: inlined by function 'deep3'
+// CHECK: :40:{{.*}}: note: inlined by function 'deep4'
+// CHECK: :41:{{.*}}: note: inlined by function 'deep5'
+// CHECK: :44:{{.*}}: note: inlined by function 'test_deep_nesting'
+
+// Multiple call sites produce distinct diagnostics.
+[[gnu::warning("deprecated")]]
+void __warn_multi(void);
+
+static inline void multi_wrapper(void) {
+  __warn_multi();
+}
+
+void call_site_a(void) { multi_wrapper(); }
+void call_site_b(void) { multi_wrapper(); }
+void call_site_c(void) { multi_wrapper(); }
+
+// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: 
deprecated
+// CHECK: note: called by function 'multi_wrapper'
+// CHECK: :62:{{.*}}: note: inlined by function 'call_site_a'
+
+// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: 
deprecated
+// CHECK: note: called by function 'multi_wrapper'
+// CHECK: :63:{{.*}}: note: inlined by function 'call_site_b'
+
+// CHECK: warning: call to '__warn_multi' declared with 'warning' attribute: 
deprecated
+// CHECK: note: called by function 'multi_wrapper'
+// CHECK: :64:{{.*}}: note: inlined by function 'call_site_c'
+
+// Different nesting depths from same inner function.
+[[gnu::warning("mixed depth")]]
+void __warn_mixed(void);
+
+static inline void mixed_inner(void) { __warn_mixed(); }
+static inline void mixed_middle(void) { mixed_inner(); }
+
+void shallow(void) { mixed_inner(); }
+void deep(void) { mixed_middle(); }
+
+// CHECK: warning: call to '__warn_mixed' declared with 'warning' attribute: 
mixed depth
+// CHECK: note: called by function 'mixed_inner'
+// CHECK: :85:{{.*}}: note: inlined by function 'shallow'
+
+// CHECK: warning: call to '__warn_mixed' declared with 'warning' attribute: 
mixed depth
+// CHECK: note: called by function 'mixed_inner'
+// CHECK: :83:{{.*}}: note: inlined by function 'mixed_middle'
+// CHECK: :86:{{.*}}: note: inlined by function 'deep'
+
+// Incidental inlining (function not marked inline/static).
+// The "inlined by" note has no location since heuristic mode doesn't track it.
+[[gnu::warning("incidental")]]
+void __warn_incidental(void);
+
+void not_marked_inline(void) { __warn_incidental(); }
+
+void test_incidental(void) { not_marked_inline(); }
+
+// CHECK: warning: call to '__warn_incidental' declared with 'warning' 
attribute: incidental
+// CHECK: note: called by function 'not_marked_inline'
+// CHECK: note: inlined by function 'test_incidental'
+// CHECK-NOT: :{{.*}}: note: inlined by function 'test_incidental'
+
+// Fallback note should appear (no debug info).
+// CHECK: note: use '-gline-directives-only' (implied by '-g1') or higher for 
more accurate inlining chain locations
diff --git a/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp 
b/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp
index bf979d79fc61b..60ed7a227731e 100644
--- a/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp
+++ b/clang/test/OpenMP/distribute_parallel_for_num_threads_codegen.cpp
@@ -2508,7 +2508,7 @@ int main() {
 // CHECK1-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK1-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK1-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK1-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -3760,7 +3760,7 @@ int main() {
 // CHECK5-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK5-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK5-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK5:       invoke.cont:
 // CHECK5-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK5-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -5012,7 +5012,7 @@ int main() {
 // CHECK9-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK9-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK9-NEXT:    [[CALL:%.*]] = invoke noundef i8 @_ZN1ScvcEv(ptr noundef 
nonnull align 8 dereferenceable(24) [[S]])
-// CHECK9-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK9-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK9:       invoke.cont:
 // CHECK9-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK9-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -6264,7 +6264,7 @@ int main() {
 // CHECK13-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK13-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK13-NEXT:    [[CALL:%.*]] = invoke noundef i8 @_ZN1ScvcEv(ptr noundef 
nonnull align 8 dereferenceable(24) [[S]])
-// CHECK13-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK13-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK13:       invoke.cont:
 // CHECK13-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK13-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
diff --git 
a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp 
b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp
index 0d4b9b245743d..62a1f68070dbc 100644
--- a/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp
+++ b/clang/test/OpenMP/distribute_parallel_for_simd_num_threads_codegen.cpp
@@ -112,7 +112,7 @@ int main() {
 // CHECK1-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK1-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK1-NEXT:    [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull 
align 8 dereferenceable(24) [[S]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK1-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -1450,7 +1450,7 @@ int main() {
 // CHECK3-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK3-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK3-NEXT:    [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull 
align 8 dereferenceable(24) [[S]])
-// CHECK3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK3:       invoke.cont:
 // CHECK3-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK3-NEXT:    store i32 0, ptr [[DOTOMP_LB]], align 4
@@ -1787,7 +1787,7 @@ int main() {
 // CHECK5-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK5-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK5-NEXT:    [[CALL:%.*]] = invoke signext i8 @_ZN1ScvcEv(ptr nonnull 
align 8 dereferenceable(24) [[S]])
-// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK5:       invoke.cont:
 // CHECK5-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK5-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -3123,7 +3123,7 @@ int main() {
 // CHECK9-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK9-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK9-NEXT:    [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 
dereferenceable(24) [[S]])
-// CHECK9-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK9-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK9:       invoke.cont:
 // CHECK9-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK9-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -4461,7 +4461,7 @@ int main() {
 // CHECK11-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK11-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK11-NEXT:    [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 
dereferenceable(24) [[S]])
-// CHECK11-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK11-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK11:       invoke.cont:
 // CHECK11-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK11-NEXT:    store i32 0, ptr [[DOTOMP_LB]], align 4
@@ -4798,7 +4798,7 @@ int main() {
 // CHECK13-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK13-NEXT:    call void @_ZN1SC1El(ptr nonnull align 8 
dereferenceable(24) [[S]], i64 0)
 // CHECK13-NEXT:    [[CALL:%.*]] = invoke i8 @_ZN1ScvcEv(ptr nonnull align 8 
dereferenceable(24) [[S]])
-// CHECK13-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK13-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK13:       invoke.cont:
 // CHECK13-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK13-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
diff --git a/clang/test/OpenMP/scope_codegen.cpp 
b/clang/test/OpenMP/scope_codegen.cpp
index ef69b8302fa2d..35a0aef5c027b 100644
--- a/clang/test/OpenMP/scope_codegen.cpp
+++ b/clang/test/OpenMP/scope_codegen.cpp
@@ -185,7 +185,7 @@ int main() {
 // CHECK1:       arrayctor.loop:
 // CHECK1-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ 
[[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK1-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK1-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2)
@@ -267,7 +267,7 @@ int main() {
 // CHECK1-NEXT:    [[TMP1:%.*]] = load i8, ptr [[A]], align 1
 // CHECK1-NEXT:    store i8 [[TMP1]], ptr [[A1]], align 1
 // CHECK1-NEXT:    invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 
4 dereferenceable(4) [[C2]], ptr noundef nonnull align 4 dereferenceable(4) @tc)
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[TERMINATE_LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[TERMINATE_LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store ptr [[C2]], ptr [[TMP]], align 8
 // CHECK1-NEXT:    invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 
4 dereferenceable(4) [[TC]], ptr noundef nonnull align 4 dereferenceable(4) @tc)
@@ -683,7 +683,7 @@ int main() {
 // CHECK4:       arrayctor.loop:
 // CHECK4-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ 
[[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK4-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK4:       invoke.cont:
 // CHECK4-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK4-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2)
@@ -765,7 +765,7 @@ int main() {
 // CHECK4-NEXT:    [[TMP1:%.*]] = load i8, ptr [[A]], align 1
 // CHECK4-NEXT:    store i8 [[TMP1]], ptr [[A1]], align 1
 // CHECK4-NEXT:    invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 
4 dereferenceable(4) [[C2]], ptr noundef nonnull align 4 dereferenceable(4) @tc)
-// CHECK4-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[TERMINATE_LPAD:%.*]]
+// CHECK4-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[TERMINATE_LPAD:%.*]], !srcloc
 // CHECK4:       invoke.cont:
 // CHECK4-NEXT:    store ptr [[C2]], ptr [[TMP]], align 8
 // CHECK4-NEXT:    invoke void @_ZN9TestClassC1ERKS_(ptr noundef nonnull align 
4 dereferenceable(4) [[TC]], ptr noundef nonnull align 4 dereferenceable(4) @tc)
diff --git a/clang/test/OpenMP/single_codegen.cpp 
b/clang/test/OpenMP/single_codegen.cpp
index a4c9b015b615f..00f606a2350f9 100644
--- a/clang/test/OpenMP/single_codegen.cpp
+++ b/clang/test/OpenMP/single_codegen.cpp
@@ -170,7 +170,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK1:       arrayctor.loop:
 // CHECK1-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], 
[[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK1-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK1-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
[[ARRAYCTOR_END]]
@@ -246,7 +246,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK1:       arrayctor.loop:
 // CHECK1-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ 
[[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK1-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK1-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2)
@@ -1048,7 +1048,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK2:       arrayctor.loop:
 // CHECK2-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ 
[[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK2-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK2-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK2:       invoke.cont:
 // CHECK2-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK2-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2)
@@ -1140,7 +1140,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK2:       arrayctor.loop:
 // CHECK2-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], 
[[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK2-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK2-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK2:       invoke.cont:
 // CHECK2-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK2-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
[[ARRAYCTOR_END]]
@@ -1977,7 +1977,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK4:       arrayctor.loop:
 // CHECK4-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ @tc2, [[ENTRY:%.*]] ], [ 
[[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK4-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK4:       invoke.cont:
 // CHECK4-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS:%.*]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK4-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
getelementptr inbounds ([[CLASS_TESTCLASS]], ptr @tc2, i64 2)
@@ -2024,7 +2024,7 @@ void array_func(int n, int a[n], St s[2]) {
 // CHECK4:       arrayctor.loop:
 // CHECK4-NEXT:    [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], 
[[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[INVOKE_CONT:%.*]] ]
 // CHECK4-NEXT:    invoke void @_ZN9TestClassC1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]]
+// CHECK4-NEXT:            to label [[INVOKE_CONT]] unwind label [[LPAD:%.*]], 
!srcloc
 // CHECK4:       invoke.cont:
 // CHECK4-NEXT:    [[ARRAYCTOR_NEXT]] = getelementptr inbounds 
[[CLASS_TESTCLASS]], ptr [[ARRAYCTOR_CUR]], i64 1
 // CHECK4-NEXT:    [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], 
[[ARRAYCTOR_END]]
diff --git 
a/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp 
b/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp
index d097631f7d0e5..2ea44a5a07bef 100644
--- a/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp
+++ b/clang/test/OpenMP/teams_distribute_parallel_for_num_threads_codegen.cpp
@@ -93,7 +93,7 @@ int main() {
 // CHECK1-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK1-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK1-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK1-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -1380,7 +1380,7 @@ int main() {
 // CHECK5-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK5-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK5-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK5:       invoke.cont:
 // CHECK5-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK5-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
diff --git 
a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp 
b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp
index d5f3af343fced..3884a48b36ee8 100644
--- 
a/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp
+++ 
b/clang/test/OpenMP/teams_distribute_parallel_for_simd_num_threads_codegen.cpp
@@ -95,7 +95,7 @@ int main() {
 // CHECK1-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK1-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK1-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK1-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
@@ -1468,7 +1468,7 @@ int main() {
 // CHECK3-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK3-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK3-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK3:       invoke.cont:
 // CHECK3-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK3-NEXT:    store i32 0, ptr [[DOTOMP_LB]], align 4
@@ -1815,7 +1815,7 @@ int main() {
 // CHECK5-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK5-NEXT:    call void @_ZN1SC1El(ptr noundef nonnull align 8 
dereferenceable(24) [[S]], i64 noundef 0)
 // CHECK5-NEXT:    [[CALL:%.*]] = invoke noundef signext i8 @_ZN1ScvcEv(ptr 
noundef nonnull align 8 dereferenceable(24) [[S]])
-// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK5-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK5:       invoke.cont:
 // CHECK5-NEXT:    store i8 [[CALL]], ptr [[A]], align 1
 // CHECK5-NEXT:    [[TMP0:%.*]] = getelementptr inbounds nuw 
[[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
diff --git a/clang/test/OpenMP/threadprivate_codegen.cpp 
b/clang/test/OpenMP/threadprivate_codegen.cpp
index 154c5f45642a4..f7f97483bf803 100644
--- a/clang/test/OpenMP/threadprivate_codegen.cpp
+++ b/clang/test/OpenMP/threadprivate_codegen.cpp
@@ -1037,7 +1037,7 @@ int foobar() {
 // CHECK1-NEXT:    store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK1-NEXT:    store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[TMP1]], i32 noundef 1)
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds 
[[STRUCT_S1:%.*]], ptr [[TMP1]], i64 1
 // CHECK1-NEXT:    store ptr [[ARRAYINIT_ELEMENT]], ptr 
[[ARRAYINIT_ENDOFINIT1]], align 8
@@ -1053,7 +1053,7 @@ int foobar() {
 // CHECK1-NEXT:    store ptr [[ARRAYINIT_ELEMENT6]], ptr 
[[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK1-NEXT:    store ptr [[ARRAYINIT_ELEMENT6]], ptr 
[[ARRAYINIT_ENDOFINIT7]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYINIT_ELEMENT6]], i32 noundef 4)
-// CHECK1-NEXT:            to label [[INVOKE_CONT9:%.*]] unwind label 
[[LPAD8:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT9:%.*]] unwind label 
[[LPAD8:%.*]], !srcloc
 // CHECK1:       invoke.cont9:
 // CHECK1-NEXT:    [[ARRAYINIT_ELEMENT10:%.*]] = getelementptr inbounds 
[[STRUCT_S1]], ptr [[ARRAYINIT_ELEMENT6]], i64 1
 // CHECK1-NEXT:    store ptr [[ARRAYINIT_ELEMENT10]], ptr 
[[ARRAYINIT_ENDOFINIT7]], align 8
@@ -1251,7 +1251,7 @@ int foobar() {
 // CHECK1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -1264,7 +1264,7 @@ int foobar() {
 // CHECK1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// CHECK1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // CHECK1:       invoke.cont7:
 // CHECK1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -1372,7 +1372,7 @@ int foobar() {
 // CHECK1-NEXT:    [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S1:%.*]], 
ptr [[TMP4]], i32 0, i32 0
 // CHECK1-NEXT:    [[TMP5:%.*]] = load i32, ptr [[A]], align 4
 // CHECK1-NEXT:    invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 
8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP5]])
-// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK1:       invoke.cont:
 // CHECK1-NEXT:    [[TMP6:%.*]] = call i32 @__cxa_atexit(ptr 
@_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]]
 // CHECK1-NEXT:    call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) 
#[[ATTR3]]
@@ -1774,7 +1774,7 @@ int foobar() {
 // CHECK2-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK2-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK2:       invoke.cont:
 // CHECK2-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -1787,7 +1787,7 @@ int foobar() {
 // CHECK2-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK2-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// CHECK2-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // CHECK2:       invoke.cont7:
 // CHECK2-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -1886,7 +1886,7 @@ int foobar() {
 // CHECK2-NEXT:    store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK2-NEXT:    store ptr [[TMP1]], ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[TMP1]], i32 noundef 1)
-// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK2:       invoke.cont:
 // CHECK2-NEXT:    [[ARRAYINIT_ELEMENT:%.*]] = getelementptr inbounds 
[[STRUCT_S1:%.*]], ptr [[TMP1]], i64 1
 // CHECK2-NEXT:    store ptr [[ARRAYINIT_ELEMENT]], ptr 
[[ARRAYINIT_ENDOFINIT1]], align 8
@@ -1902,7 +1902,7 @@ int foobar() {
 // CHECK2-NEXT:    store ptr [[ARRAYINIT_ELEMENT6]], ptr 
[[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK2-NEXT:    store ptr [[ARRAYINIT_ELEMENT6]], ptr 
[[ARRAYINIT_ENDOFINIT7]], align 8
 // CHECK2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[ARRAYINIT_ELEMENT6]], i32 noundef 4)
-// CHECK2-NEXT:            to label [[INVOKE_CONT9:%.*]] unwind label 
[[LPAD8:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT9:%.*]] unwind label 
[[LPAD8:%.*]], !srcloc
 // CHECK2:       invoke.cont9:
 // CHECK2-NEXT:    [[ARRAYINIT_ELEMENT10:%.*]] = getelementptr inbounds 
[[STRUCT_S1]], ptr [[ARRAYINIT_ELEMENT6]], i64 1
 // CHECK2-NEXT:    store ptr [[ARRAYINIT_ELEMENT10]], ptr 
[[ARRAYINIT_ENDOFINIT7]], align 8
@@ -2023,7 +2023,7 @@ int foobar() {
 // CHECK2-NEXT:    [[A:%.*]] = getelementptr inbounds nuw [[STRUCT_S1:%.*]], 
ptr [[TMP4]], i32 0, i32 0
 // CHECK2-NEXT:    [[TMP5:%.*]] = load i32, ptr [[A]], align 4
 // CHECK2-NEXT:    invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 
8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP5]])
-// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK2:       invoke.cont:
 // CHECK2-NEXT:    [[TMP6:%.*]] = call i32 @__cxa_atexit(ptr 
@_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]]
 // CHECK2-NEXT:    call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) 
#[[ATTR3]]
@@ -2446,7 +2446,7 @@ int foobar() {
 // SIMD1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // SIMD1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // SIMD1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// SIMD1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// SIMD1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // SIMD1:       invoke.cont:
 // SIMD1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // SIMD1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -2459,7 +2459,7 @@ int foobar() {
 // SIMD1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // SIMD1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // SIMD1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// SIMD1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// SIMD1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // SIMD1:       invoke.cont7:
 // SIMD1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // SIMD1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -2562,7 +2562,7 @@ int foobar() {
 // SIMD1:       init:
 // SIMD1-NEXT:    [[TMP2:%.*]] = load i32, ptr @_ZL3gs1, align 4
 // SIMD1-NEXT:    invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 
8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP2]])
-// SIMD1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// SIMD1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // SIMD1:       invoke.cont:
 // SIMD1-NEXT:    [[TMP3:%.*]] = call i32 @__cxa_atexit(ptr 
@_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]]
 // SIMD1-NEXT:    call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) 
#[[ATTR3]]
@@ -3439,7 +3439,7 @@ int foobar() {
 // CHECK-TLS1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK-TLS1-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK-TLS1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK-TLS1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK-TLS1-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK-TLS1:       invoke.cont:
 // CHECK-TLS1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], 
ptr @arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK-TLS1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -3452,7 +3452,7 @@ int foobar() {
 // CHECK-TLS1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK-TLS1-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK-TLS1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// CHECK-TLS1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// CHECK-TLS1-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // CHECK-TLS1:       invoke.cont7:
 // CHECK-TLS1-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK-TLS1-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -4170,7 +4170,7 @@ int foobar() {
 // CHECK-TLS2-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK-TLS2-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK-TLS2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK-TLS2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// CHECK-TLS2-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // CHECK-TLS2:       invoke.cont:
 // CHECK-TLS2-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], 
ptr @arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // CHECK-TLS2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -4183,7 +4183,7 @@ int foobar() {
 // CHECK-TLS2-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // CHECK-TLS2-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK-TLS2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// CHECK-TLS2-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// CHECK-TLS2-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // CHECK-TLS2:       invoke.cont7:
 // CHECK-TLS2-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // CHECK-TLS2-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -4513,7 +4513,7 @@ int foobar() {
 // CHECK-TLS3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8, 
!dbg [[DBG185:![0-9]+]]
 // CHECK-TLS3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 
8, !dbg [[DBG187:![0-9]+]]
 // CHECK-TLS3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK-TLS3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !dbg [[DBG188:![0-9]+]]
+// CHECK-TLS3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !dbg [[DBG188:![0-9]+]],
 // CHECK-TLS3:       invoke.cont:
 // CHECK-TLS3-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], 
ptr @arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8, !dbg [[DBG187]]
 // CHECK-TLS3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -5567,7 +5567,7 @@ int foobar() {
 // SIMD3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // SIMD3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // SIMD3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// SIMD3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// SIMD3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // SIMD3:       invoke.cont:
 // SIMD3-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8
 // SIMD3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)
@@ -5580,7 +5580,7 @@ int foobar() {
 // SIMD3-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT]], align 8
 // SIMD3-NEXT:    store ptr getelementptr inbounds ([3 x %struct.S1], ptr 
@arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT5]], align 8
 // SIMD3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 
1), i32 noundef 4)
-// SIMD3-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]]
+// SIMD3-NEXT:            to label [[INVOKE_CONT7:%.*]] unwind label 
[[LPAD6:%.*]], !srcloc
 // SIMD3:       invoke.cont7:
 // SIMD3-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1]], ptr 
getelementptr inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), ptr 
[[ARRAYINIT_ENDOFINIT5]], align 8
 // SIMD3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr getelementptr 
inbounds ([3 x %struct.S1], ptr @arr_x, i64 1), i64 1), i32 noundef 5)
@@ -5683,7 +5683,7 @@ int foobar() {
 // SIMD3:       init:
 // SIMD3-NEXT:    [[TMP2:%.*]] = load i32, ptr @_ZL3gs1, align 4
 // SIMD3-NEXT:    invoke void @_ZZ4mainEN5SmainC1Ei(ptr noundef nonnull align 
8 dereferenceable(24) @_ZZ4mainE2sm, i32 noundef [[TMP2]])
-// SIMD3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]]
+// SIMD3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !srcloc
 // SIMD3:       invoke.cont:
 // SIMD3-NEXT:    [[TMP3:%.*]] = call i32 @__cxa_atexit(ptr 
@_ZZ4mainEN5SmainD1Ev, ptr @_ZZ4mainE2sm, ptr @__dso_handle) #[[ATTR3]]
 // SIMD3-NEXT:    call void @__cxa_guard_release(ptr @_ZGVZ4mainE2sm) 
#[[ATTR3]]
diff --git 
a/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected 
b/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected
index 96370b4bec2d9..76e5361690ddf 100644
--- a/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected
+++ b/clang/test/utils/update_cc_test_checks/Inputs/basic-cplusplus.cpp.expected
@@ -83,9 +83,9 @@ int main() {
 // CHECK-NEXT:    [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4
 // CHECK-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // CHECK-NEXT:    call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 1)
-// CHECK-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2)
-// CHECK-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3)
-// CHECK-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0)
+// CHECK-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META2:![0-9]+]]
+// CHECK-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META3:![0-9]+]]
+// CHECK-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META4:![0-9]+]]
 // CHECK-NEXT:    store i32 [[CALL2]], ptr [[RETVAL]], align 4
 // CHECK-NEXT:    call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[F]]) #[[ATTR2]]
 // CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
@@ -184,9 +184,9 @@ int main() {
 // MACHO-NEXT:    [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4
 // MACHO-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // MACHO-NEXT:    call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 1)
-// MACHO-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2)
-// MACHO-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3)
-// MACHO-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0)
+// MACHO-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META2:![0-9]+]]
+// MACHO-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META3:![0-9]+]]
+// MACHO-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META4:![0-9]+]]
 // MACHO-NEXT:    store i32 [[CALL2]], ptr [[RETVAL]], align 4
 // MACHO-NEXT:    call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[F]]) #[[ATTR2]]
 // MACHO-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
@@ -239,9 +239,9 @@ int main() {
 // MSVC-NEXT:    [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4
 // MSVC-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // MSVC-NEXT:    [[CALL:%.*]] = call noundef ptr @"??0Foo@@QEAA@H@Z"(ptr 
noundef nonnull align 4 dereferenceable(4) [[F]], i32 noundef 1)
-// MSVC-NEXT:    [[CALL1:%.*]] = call noundef i32 
@"?function_defined_inline@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2)
-// MSVC-NEXT:    [[CALL2:%.*]] = call noundef i32 
@"?function_defined_out_of_line@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3)
-// MSVC-NEXT:    [[CALL3:%.*]] = call noundef i32 
@"?static_noinline_fn@@YAHH@Z"(i32 noundef 0)
+// MSVC-NEXT:    [[CALL1:%.*]] = call noundef i32 
@"?function_defined_inline@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META6:![0-9]+]]
+// MSVC-NEXT:    [[CALL2:%.*]] = call noundef i32 
@"?function_defined_out_of_line@Foo@@QEBAHH@Z"(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META7:![0-9]+]]
+// MSVC-NEXT:    [[CALL3:%.*]] = call noundef i32 
@"?static_noinline_fn@@YAHH@Z"(i32 noundef 0), !srcloc [[META8:![0-9]+]]
 // MSVC-NEXT:    store i32 [[CALL3]], ptr [[RETVAL]], align 4
 // MSVC-NEXT:    call void @"??1Foo@@QEAA@XZ"(ptr noundef nonnull align 4 
dereferenceable(4) [[F]]) #[[ATTR2:[0-9]+]]
 // MSVC-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
@@ -301,9 +301,9 @@ int main() {
 // MINGW-NEXT:    [[F:%.*]] = alloca [[CLASS_FOO:%.*]], align 4
 // MINGW-NEXT:    store i32 0, ptr [[RETVAL]], align 4
 // MINGW-NEXT:    call void @_ZN3FooC1Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 1)
-// MINGW-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2)
-// MINGW-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3)
-// MINGW-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0)
+// MINGW-NEXT:    [[CALL:%.*]] = call noundef i32 
@_ZNK3Foo23function_defined_inlineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 2), !srcloc [[META6:![0-9]+]]
+// MINGW-NEXT:    [[CALL1:%.*]] = call noundef i32 
@_ZNK3Foo28function_defined_out_of_lineEi(ptr noundef nonnull align 4 
dereferenceable(4) [[F]], i32 noundef 3), !srcloc [[META7:![0-9]+]]
+// MINGW-NEXT:    [[CALL2:%.*]] = call noundef i32 
@_ZL18static_noinline_fni(i32 noundef 0), !srcloc [[META8:![0-9]+]]
 // MINGW-NEXT:    store i32 [[CALL2]], ptr [[RETVAL]], align 4
 // MINGW-NEXT:    call void @_ZN3FooD1Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[F]]) #[[ATTR2]]
 // MINGW-NEXT:    [[TMP0:%.*]] = load i32, ptr [[RETVAL]], align 4
@@ -348,3 +348,20 @@ int main() {
 // MINGW-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARG_ADDR]], align 4
 // MINGW-NEXT:    ret i32 [[TMP0]]
 //
+//.
+// CHECK: [[META2]] = !{i64 1048}
+// CHECK: [[META3]] = !{i64 1080}
+// CHECK: [[META4]] = !{i64 1122}
+//.
+// MACHO: [[META2]] = !{i64 1048}
+// MACHO: [[META3]] = !{i64 1080}
+// MACHO: [[META4]] = !{i64 1122}
+//.
+// MSVC: [[META6]] = !{i64 1048}
+// MSVC: [[META7]] = !{i64 1080}
+// MSVC: [[META8]] = !{i64 1122}
+//.
+// MINGW: [[META6]] = !{i64 1048}
+// MINGW: [[META7]] = !{i64 1080}
+// MINGW: [[META8]] = !{i64 1122}
+//.
diff --git 
a/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected
 
b/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected
index 2ed8693d181d7..8c0aaa0fa672a 100644
--- 
a/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected
+++ 
b/clang/test/utils/update_cc_test_checks/Inputs/explicit-template-instantiation.cpp.expected
@@ -44,7 +44,7 @@ public:
 // CHECK-NEXT:    store i8 [[X:%.*]], ptr [[X_ADDR]], align 1
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load i8, ptr [[X_ADDR]], align 1
-// CHECK-NEXT:    call void @_ZN3FooIcEC2Ec(ptr noundef nonnull align 1 
dereferenceable(1) [[THIS1]], i8 noundef signext [[TMP0]])
+// CHECK-NEXT:    call void @_ZN3FooIcEC2Ec(ptr noundef nonnull align 1 
dereferenceable(1) [[THIS1]], i8 noundef signext [[TMP0]]), !srcloc 
[[META2:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3FooIcED1Ev(
@@ -52,7 +52,7 @@ public:
 // CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK-NEXT:    call void @_ZN3FooIcED2Ev(ptr noundef nonnull align 1 
dereferenceable(1) [[THIS1]]) #[[ATTR1:[0-9]+]]
+// CHECK-NEXT:    call void @_ZN3FooIcED2Ev(ptr noundef nonnull align 1 
dereferenceable(1) [[THIS1]]) #[[ATTR1:[0-9]+]], !srcloc [[META3:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3FooIcE3getEv(
@@ -86,7 +86,7 @@ template struct Foo<char>;
 // CHECK-NEXT:    store i16 [[X:%.*]], ptr [[X_ADDR]], align 2
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load i16, ptr [[X_ADDR]], align 2
-// CHECK-NEXT:    call void @_ZN3FooIsEC2Es(ptr noundef nonnull align 2 
dereferenceable(2) [[THIS1]], i16 noundef signext [[TMP0]])
+// CHECK-NEXT:    call void @_ZN3FooIsEC2Es(ptr noundef nonnull align 2 
dereferenceable(2) [[THIS1]], i16 noundef signext [[TMP0]]), !srcloc [[META2]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3FooIsED1Ev(
@@ -94,7 +94,7 @@ template struct Foo<char>;
 // CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK-NEXT:    call void @_ZN3FooIsED2Ev(ptr noundef nonnull align 2 
dereferenceable(2) [[THIS1]]) #[[ATTR1]]
+// CHECK-NEXT:    call void @_ZN3FooIsED2Ev(ptr noundef nonnull align 2 
dereferenceable(2) [[THIS1]]) #[[ATTR1]], !srcloc [[META3]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3FooIsE3getEv(
@@ -131,7 +131,7 @@ template struct Foo<short>;
 // CHECK-NEXT:    store i32 [[X:%.*]], ptr [[X_ADDR]], align 4
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[X_ADDR]], align 4
-// CHECK-NEXT:    call void @_ZN3BarIiEC2Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]])
+// CHECK-NEXT:    call void @_ZN3BarIiEC2Ei(ptr noundef nonnull align 4 
dereferenceable(4) [[THIS1]], i32 noundef [[TMP0]]), !srcloc [[META5:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3BarIiED1Ev(
@@ -139,7 +139,7 @@ template struct Foo<short>;
 // CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK-NEXT:    call void @_ZN3BarIiED2Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[THIS1]]) #[[ATTR1]]
+// CHECK-NEXT:    call void @_ZN3BarIiED2Ev(ptr noundef nonnull align 4 
dereferenceable(4) [[THIS1]]) #[[ATTR1]], !srcloc [[META3]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3BarIiE3getEv(
@@ -148,7 +148,7 @@ template struct Foo<short>;
 // CHECK-NEXT:    store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], 
ptr [[THIS1]], i32 0, i32 0
-// CHECK-NEXT:    [[CALL:%.*]] = call noundef i32 @_ZN3FooIiE3getEv(ptr 
noundef nonnull align 4 dereferenceable(4) [[FOO]])
+// CHECK-NEXT:    [[CALL:%.*]] = call noundef i32 @_ZN3FooIiE3getEv(ptr 
noundef nonnull align 4 dereferenceable(4) [[FOO]]), !srcloc [[META6:![0-9]+]]
 // CHECK-NEXT:    ret i32 [[CALL]]
 //
 // CHECK-LABEL: @_ZN3BarIiE3setEi(
@@ -160,7 +160,7 @@ template struct Foo<short>;
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[FOO:%.*]] = getelementptr inbounds nuw [[STRUCT_BAR:%.*]], 
ptr [[THIS1]], i32 0, i32 0
 // CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[_X_ADDR]], align 4
-// CHECK-NEXT:    call void @_ZN3FooIiE3setEi(ptr noundef nonnull align 4 
dereferenceable(4) [[FOO]], i32 noundef [[TMP0]])
+// CHECK-NEXT:    call void @_ZN3FooIiE3setEi(ptr noundef nonnull align 4 
dereferenceable(4) [[FOO]], i32 noundef [[TMP0]]), !srcloc [[META7:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 template struct Bar<int>;
@@ -176,7 +176,7 @@ template struct Bar<int>;
 // CHECK-NEXT:    store i64 [[X:%.*]], ptr [[X_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[X_ADDR]], align 8
-// CHECK-NEXT:    call void @_ZN3BazIlEC2El(ptr noundef nonnull align 8 
dereferenceable(8) [[THIS1]], i64 noundef [[TMP0]])
+// CHECK-NEXT:    call void @_ZN3BazIlEC2El(ptr noundef nonnull align 8 
dereferenceable(8) [[THIS1]], i64 noundef [[TMP0]]), !srcloc [[META9:![0-9]+]]
 // CHECK-NEXT:    ret void
 //
 // CHECK-LABEL: @_ZN3BazIlED1Ev(
@@ -184,7 +184,7 @@ template struct Bar<int>;
 // CHECK-NEXT:    [[THIS_ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    store ptr [[THIS:%.*]], ptr [[THIS_ADDR]], align 8
 // CHECK-NEXT:    [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK-NEXT:    call void @_ZN3BazIlED2Ev(ptr noundef nonnull align 8 
dereferenceable(8) [[THIS1]]) #[[ATTR1]]
+// CHECK-NEXT:    call void @_ZN3BazIlED2Ev(ptr noundef nonnull align 8 
dereferenceable(8) [[THIS1]]) #[[ATTR1]], !srcloc [[META3]]
 // CHECK-NEXT:    ret void
 //
 template struct Baz<long>;
diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h 
b/llvm/include/llvm/IR/DiagnosticInfo.h
index 8f6fb4da0c839..0daaa462ba715 100644
--- a/llvm/include/llvm/IR/DiagnosticInfo.h
+++ b/llvm/include/llvm/IR/DiagnosticInfo.h
@@ -1192,19 +1192,41 @@ class LLVM_ABI DiagnosticInfoSrcMgr : public 
DiagnosticInfo {
 
 LLVM_ABI void diagnoseDontCall(const CallInst &CI);
 
+/// Inlining location extracted from debug info.
+struct DebugInlineInfo {
+  StringRef FuncName;
+  StringRef Filename;
+  unsigned Line;
+  unsigned Column;
+};
+
 class LLVM_ABI DiagnosticInfoDontCall : public DiagnosticInfo {
   StringRef CalleeName;
   StringRef Note;
   uint64_t LocCookie;
+  MDNode *InlinedFromMD = nullptr;
+  SmallVector<DebugInlineInfo, 4> DebugInlineChain;
 
 public:
   DiagnosticInfoDontCall(StringRef CalleeName, StringRef Note,
-                         DiagnosticSeverity DS, uint64_t LocCookie)
+                         DiagnosticSeverity DS, uint64_t LocCookie,
+                         MDNode *InlinedFromMD = nullptr)
       : DiagnosticInfo(DK_DontCall, DS), CalleeName(CalleeName), Note(Note),
-        LocCookie(LocCookie) {}
+        LocCookie(LocCookie), InlinedFromMD(InlinedFromMD) {}
+
   StringRef getFunctionName() const { return CalleeName; }
   StringRef getNote() const { return Note; }
   uint64_t getLocCookie() const { return LocCookie; }
+  MDNode *getInlinedFromMD() const { return InlinedFromMD; }
+  SmallVector<std::pair<StringRef, uint64_t>> getInliningDecisions() const;
+
+  void setDebugInlineChain(SmallVector<DebugInlineInfo, 4> &&Chain) {
+    DebugInlineChain = std::move(Chain);
+  }
+  ArrayRef<DebugInlineInfo> getDebugInlineChain() const {
+    return DebugInlineChain;
+  }
+
   void print(DiagnosticPrinter &DP) const override;
   static bool classof(const DiagnosticInfo *DI) {
     return DI->getKind() == DK_DontCall;
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp
index e48016fc4165f..73bf0eca0b964 100644
--- a/llvm/lib/IR/DiagnosticInfo.cpp
+++ b/llvm/lib/IR/DiagnosticInfo.cpp
@@ -484,8 +484,27 @@ void llvm::diagnoseDontCall(const CallInst &CI) {
       if (MDNode *MD = CI.getMetadata("srcloc"))
         LocCookie =
             mdconst::extract<ConstantInt>(MD->getOperand(0))->getZExtValue();
+      MDNode *InlinedFromMD = CI.getMetadata("inlined.from");
       DiagnosticInfoDontCall D(F->getName(), A.getValueAsString(), Sev,
-                               LocCookie);
+                               LocCookie, InlinedFromMD);
+
+      if (const DebugLoc &DL = CI.getDebugLoc()) {
+        SmallVector<DebugInlineInfo, 4> DebugChain;
+        auto AddLocation = [&](const DILocation *Loc) {
+          if (auto *Scope = Loc->getScope())
+            if (auto *SP = Scope->getSubprogram())
+              DebugChain.push_back({SP->getName(), Loc->getFilename(),
+                                    Loc->getLine(), Loc->getColumn()});
+        };
+        if (const DILocation *Loc = DL.get()) {
+          AddLocation(Loc);
+          for (const DILocation *InlinedAt = Loc->getInlinedAt(); InlinedAt;
+               InlinedAt = InlinedAt->getInlinedAt())
+            AddLocation(InlinedAt);
+        }
+        D.setDebugInlineChain(std::move(DebugChain));
+      }
+
       F->getContext().diagnose(D);
     }
   }
@@ -500,3 +519,20 @@ void DiagnosticInfoDontCall::print(DiagnosticPrinter &DP) 
const {
   if (!getNote().empty())
     DP << ": " << getNote();
 }
+
+SmallVector<std::pair<StringRef, uint64_t>>
+DiagnosticInfoDontCall::getInliningDecisions() const {
+  SmallVector<std::pair<StringRef, uint64_t>> Chain;
+  if (!InlinedFromMD)
+    return Chain;
+
+  for (unsigned I = 0, E = InlinedFromMD->getNumOperands(); I + 1 < E; I += 2) 
{
+    auto *NameMD = dyn_cast<MDString>(InlinedFromMD->getOperand(I));
+    auto *LocMD =
+        mdconst::dyn_extract<ConstantInt>(InlinedFromMD->getOperand(I + 1));
+    if (NameMD && !NameMD->getString().empty())
+      Chain.emplace_back(NameMD->getString(),
+                         LocMD ? LocMD->getZExtValue() : 0);
+  }
+  return Chain;
+}
diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp 
b/llvm/lib/Transforms/Utils/InlineFunction.cpp
index aa902f687d8aa..2573c0b2d63a1 100644
--- a/llvm/lib/Transforms/Utils/InlineFunction.cpp
+++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp
@@ -974,6 +974,46 @@ static void PropagateCallSiteMetadata(CallBase &CB, 
Function::iterator FStart,
   }
 }
 
+/// Track inlining chain via inlined.from metadata for dontcall diagnostics.
+static void PropagateInlinedFromMetadata(CallBase &CB, StringRef 
CalledFuncName,
+                                         StringRef CallerFuncName,
+                                         Function::iterator FStart,
+                                         Function::iterator FEnd) {
+  LLVMContext &Ctx = CB.getContext();
+  uint64_t InlineSiteLoc = 0;
+  if (auto *MD = CB.getMetadata("srcloc"))
+    if (auto *CI = mdconst::dyn_extract<ConstantInt>(MD->getOperand(0)))
+      InlineSiteLoc = CI->getZExtValue();
+
+  auto *I64Ty = Type::getInt64Ty(Ctx);
+  auto MakeMDInt = [&](uint64_t V) {
+    return ConstantAsMetadata::get(ConstantInt::get(I64Ty, V));
+  };
+
+  for (BasicBlock &BB : make_range(FStart, FEnd)) {
+    for (Instruction &I : BB) {
+      auto *CI = dyn_cast<CallInst>(&I);
+      if (!CI || !CI->getMetadata("srcloc"))
+        continue;
+      auto *Callee = CI->getCalledFunction();
+      if (!Callee || (!Callee->hasFnAttribute("dontcall-error") &&
+                      !Callee->hasFnAttribute("dontcall-warn")))
+        continue;
+
+      SmallVector<Metadata *, 8> Ops;
+      if (MDNode *Existing = CI->getMetadata("inlined.from"))
+        append_range(Ops, Existing->operands());
+      else {
+        Ops.push_back(MDString::get(Ctx, CalledFuncName));
+        Ops.push_back(MakeMDInt(0));
+      }
+      Ops.push_back(MDString::get(Ctx, CallerFuncName));
+      Ops.push_back(MakeMDInt(InlineSiteLoc));
+      CI->setMetadata("inlined.from", MDNode::get(Ctx, Ops));
+    }
+  }
+}
+
 /// Bundle operands of the inlined function must be added to inlined call 
sites.
 static void PropagateOperandBundles(Function::iterator InlinedBB,
                                     Instruction *CallSiteEHPad) {
@@ -2839,6 +2879,10 @@ void llvm::InlineFunctionImpl(CallBase &CB, 
InlineFunctionInfo &IFI,
       }
     }
 
+    // Propagate inlined.from metadata for dontcall diagnostics.
+    PropagateInlinedFromMetadata(CB, CalledFunc->getName(), Caller->getName(),
+                                 FirstNewBlock, Caller->end());
+
     // Register any cloned assumptions.
     if (IFI.GetAssumptionCache)
       for (BasicBlock &NewBlock :

>From 4a1dee8a3a548b88caab7b8e90fad5bb718ccdfd Mon Sep 17 00:00:00 2001
From: Justin Stitt <[email protected]>
Date: Thu, 29 Jan 2026 11:55:34 -0800
Subject: [PATCH 2/3] use better wording around parens

Signed-off-by: Justin Stitt <[email protected]>
---
 clang/docs/ReleaseNotes.rst                               | 8 ++++----
 clang/include/clang/Basic/DiagnosticFrontendKinds.td      | 2 +-
 clang/test/Frontend/backend-attribute-inlining-cross-tu.c | 2 +-
 .../backend-attribute-inlining-debug-vs-heuristic.cpp     | 2 +-
 clang/test/Frontend/backend-attribute-inlining-modes.c    | 2 +-
 clang/test/Frontend/backend-attribute-inlining.c          | 2 +-
 6 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 17aa673296d13..667c05c5897e5 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -190,10 +190,10 @@ Improvements to Clang's diagnostics
 - ``[[gnu::warning]]`` and ``[[gnu::error]]`` diagnostics now have notes
   describing inlining locations. When a function with these attributes is
   called from an inlined context, Clang can now show which functions were
-  inlined to reach the call. When debug info is available
-  (``-gline-directives-only`` (implicitly enabled at ``-g1``) or higher),
-  accurate source locations are used; otherwise, a heuristic fallback is used
-  with a note suggesting how to enable debug info for better accuracy.
+  inlined to reach the call. When ``-gline-directives-only`` (implied by
+  ``-g1`` or higher) is available, accurate source locations are used;
+  otherwise, a heuristic fallback is used with a note suggesting how to enable
+  debug info for better accuracy.
 
 
 Improvements to Clang's time-trace
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td 
b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index 8180766d63464..4c8982a373c6b 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -97,7 +97,7 @@ def warn_fe_backend_warning_attr :
 def note_fe_backend_in : Note<"called by function '%0'">, BackendInfo;
 def note_fe_backend_inlined : Note<"inlined by function '%0'">, BackendInfo;
 def note_fe_backend_inlining_debug_info
-    : Note<"use '-gline-directives-only' (implied by '-g1') or higher for "
+    : Note<"use '-gline-directives-only' (implied by '-g1' or higher) for "
            "more accurate inlining chain locations">,
       BackendInfo;
 def warn_toc_unsupported_type : Warning<"-mtocdata option is ignored "
diff --git a/clang/test/Frontend/backend-attribute-inlining-cross-tu.c 
b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c
index 18cc0606e1bb5..e0f43c2f465e9 100644
--- a/clang/test/Frontend/backend-attribute-inlining-cross-tu.c
+++ b/clang/test/Frontend/backend-attribute-inlining-cross-tu.c
@@ -64,4 +64,4 @@ void test_error_cross_tu(void) {
 // CHECK: main.c:{{.*}}: note: inlined by function 'test_error_cross_tu'
 
 // Fallback note should appear (no debug info).
-// CHECK: note: use '-gline-directives-only' (implied by '-g1') or higher for 
more accurate inlining chain locations
+// CHECK: note: use '-gline-directives-only' (implied by '-g1' or higher) for 
more accurate inlining chain locations
diff --git 
a/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp 
b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
index 65e4eea8f2a44..95552b61894c3 100644
--- a/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
+++ b/clang/test/Frontend/backend-attribute-inlining-debug-vs-heuristic.cpp
@@ -29,7 +29,7 @@ void caller() {
 // HEURISTIC: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}'
 // HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}middle{{.*}}'
 // HEURISTIC: :16:{{.*}}: note: inlined by function '{{.*}}caller{{.*}}'
-// HEURISTIC: note: use '-gline-directives-only' (implied by '-g1') or higher 
for more accurate inlining chain locations
+// HEURISTIC: note: use '-gline-directives-only' (implied by '-g1' or higher) 
for more accurate inlining chain locations
 
 // DEBUG: :16:{{.*}}: warning: call to '{{.*}}dangerous{{.*}}'
 // DEBUG: :16:{{.*}}: note: called by function '{{.*}}wrapper{{.*}}'
diff --git a/clang/test/Frontend/backend-attribute-inlining-modes.c 
b/clang/test/Frontend/backend-attribute-inlining-modes.c
index 653e5bb0390bd..4abc4023191f3 100644
--- a/clang/test/Frontend/backend-attribute-inlining-modes.c
+++ b/clang/test/Frontend/backend-attribute-inlining-modes.c
@@ -22,7 +22,7 @@ void entry(void) {
 // ENABLED-HEURISTIC: :8:{{.*}}: note: called by function 'level1'
 // ENABLED-HEURISTIC: :12:{{.*}}: note: inlined by function 'level2'
 // ENABLED-HEURISTIC: :16:{{.*}}: note: inlined by function 'entry'
-// ENABLED-HEURISTIC: note: use '-gline-directives-only' (implied by '-g1') or 
higher for more accurate inlining chain locations
+// ENABLED-HEURISTIC: note: use '-gline-directives-only' (implied by '-g1' or 
higher) for more accurate inlining chain locations
 
 // Enabled with debug info: accurate locations.
 // ENABLED-DEBUG: :8:{{.*}}: warning: call to 'bad_func'
diff --git a/clang/test/Frontend/backend-attribute-inlining.c 
b/clang/test/Frontend/backend-attribute-inlining.c
index 0c49c395b3f83..1aaf98b191b90 100644
--- a/clang/test/Frontend/backend-attribute-inlining.c
+++ b/clang/test/Frontend/backend-attribute-inlining.c
@@ -109,4 +109,4 @@ void test_incidental(void) { not_marked_inline(); }
 // CHECK-NOT: :{{.*}}: note: inlined by function 'test_incidental'
 
 // Fallback note should appear (no debug info).
-// CHECK: note: use '-gline-directives-only' (implied by '-g1') or higher for 
more accurate inlining chain locations
+// CHECK: note: use '-gline-directives-only' (implied by '-g1' or higher) for 
more accurate inlining chain locations

>From eee8703bfff021049700ffdb2561de32cf710780 Mon Sep 17 00:00:00 2001
From: Justin Stitt <[email protected]>
Date: Thu, 29 Jan 2026 14:25:05 -0800
Subject: [PATCH 3/3] dont use heuristic approach if debug info is available

Signed-off-by: Justin Stitt <[email protected]>
---
 clang/lib/CodeGen/CGCall.cpp                | 2 +-
 clang/test/DebugInfo/CXX/member-call.cpp    | 4 ++--
 clang/test/OpenMP/threadprivate_codegen.cpp | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 9afb942a0df13..fbf18d0eb6f82 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -6070,7 +6070,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo 
&CallInfo,
   // inline-annotated functions are still not guaranteed to be inlined.
   if (TargetDecl) {
     bool NeedSrcLoc = TargetDecl->hasAttr<ErrorAttr>();
-    if (!NeedSrcLoc) {
+    if (!NeedSrcLoc && !getDebugInfo()) {
       if (const auto *FD = dyn_cast<FunctionDecl>(TargetDecl))
         NeedSrcLoc = FD->isInlined() || FD->hasAttr<AlwaysInlineAttr>() ||
                      FD->getStorageClass() == SC_Static ||
diff --git a/clang/test/DebugInfo/CXX/member-call.cpp 
b/clang/test/DebugInfo/CXX/member-call.cpp
index d73147ba8efb6..2b60de8aee491 100644
--- a/clang/test/DebugInfo/CXX/member-call.cpp
+++ b/clang/test/DebugInfo/CXX/member-call.cpp
@@ -16,8 +16,8 @@ void test(Foo *f) {
 }
 
 // CHECK-LABEL: @_Z4testP3Foo
-// CHECK: call {{.*}} @_ZN3Foo3fooEv{{.*}}, !dbg ![[CALL1LOC:.*]], !srcloc
-// CHECK: call void @_ZN3Bar3barEv{{.*}}, !dbg ![[CALL2LOC:.*]], !srcloc
+// CHECK: call {{.*}} @_ZN3Foo3fooEv{{.*}}, !dbg ![[CALL1LOC:.*]]
+// CHECK: call void @_ZN3Bar3barEv{{.*}}, !dbg ![[CALL2LOC:.*]]
 
 // CHECK: ![[CALL1LOC]] = !DILocation(line: [[LINE:[0-9]+]], column: 6,
 // CHECK: ![[CALL2LOC]] = !DILocation(line: [[LINE]], column: 13,
diff --git a/clang/test/OpenMP/threadprivate_codegen.cpp 
b/clang/test/OpenMP/threadprivate_codegen.cpp
index f7f97483bf803..92eadb1433d38 100644
--- a/clang/test/OpenMP/threadprivate_codegen.cpp
+++ b/clang/test/OpenMP/threadprivate_codegen.cpp
@@ -4513,7 +4513,7 @@ int foobar() {
 // CHECK-TLS3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT]], align 8, 
!dbg [[DBG185:![0-9]+]]
 // CHECK-TLS3-NEXT:    store ptr @arr_x, ptr [[ARRAYINIT_ENDOFINIT1]], align 
8, !dbg [[DBG187:![0-9]+]]
 // CHECK-TLS3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) @arr_x, i32 noundef 1)
-// CHECK-TLS3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !dbg [[DBG188:![0-9]+]],
+// CHECK-TLS3-NEXT:            to label [[INVOKE_CONT:%.*]] unwind label 
[[LPAD:%.*]], !dbg [[DBG188:![0-9]+]]
 // CHECK-TLS3:       invoke.cont:
 // CHECK-TLS3-NEXT:    store ptr getelementptr inbounds ([[STRUCT_S1:%.*]], 
ptr @arr_x, i64 1), ptr [[ARRAYINIT_ENDOFINIT1]], align 8, !dbg [[DBG187]]
 // CHECK-TLS3-NEXT:    invoke void @_ZN2S1C1Ei(ptr noundef nonnull align 4 
dereferenceable(4) getelementptr inbounds ([[STRUCT_S1]], ptr @arr_x, i64 1), 
i32 noundef 2)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to