[flang-commits] [flang] [flang][debug] Emit debug info for procedures from an INCLUDE'd file. (PR #225068)

Abid Qadeer via flang-commits flang-commits at lists.llvm.org
Tue Sep 22 03:27:28 PDT 2026


https://github.com/abidh updated https://github.com/llvm/llvm-project/pull/225068

>From 665d47f3e1c4161b3bc2223da1af779b485cc5c4 Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Mon, 21 Sep 2026 11:26:38 +0100
Subject: [PATCH 1/2] [flang][debug] Emit debug info for procedures from an
 INCLUDE'd file.

A declaration read through INCLUDE gets a location that is fused with the
inclusion information, carrying a fir::LocationKindArrayAttr.
debugInfoIsAlreadySet treated any fused location as one this pass had
already handled, apart from a fir::LocationKindAttr that is never the
attribute actually used, so handleFuncOp and handleGlobalOp returned
immediately and such a procedure or global got no debug information at all.

Examine what the fusion holds instead of only whether there is one. The
attribute to look for is now a template argument, so each caller names the
one it would attach itself, a DISubprogramAttr for a function and an array
of DIGlobalVariableExpressionAttr for a global, and no central list has to
be kept in step with them.

Doing only that describes the procedure at the line of the INCLUDE
statement rather than at its own, because the file and line are read with
a cast that a fused location does not satisfy, leaving them at the compile
unit's file and at line 1. Search the location for the FileLineColLoc in
both places instead. Searching it also gives a variable inlined from
another procedure the line it is declared on rather than that same
fallback of 1, which is what changes in debug-dummy-argument-inline.fir.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 flang/include/flang/Optimizer/Support/Utils.h |  6 ++-
 .../lib/Optimizer/Transforms/AddDebugInfo.cpp | 26 +++++++----
 flang/test/Integration/debug-include-file.f90 | 35 ++++++++++++++
 .../debug-dummy-argument-inline.fir           |  4 +-
 flang/test/Transforms/debug-include-file.fir  | 46 +++++++++++++++++++
 5 files changed, 104 insertions(+), 13 deletions(-)
 create mode 100644 flang/test/Integration/debug-include-file.f90
 create mode 100644 flang/test/Transforms/debug-include-file.fir

diff --git a/flang/include/flang/Optimizer/Support/Utils.h b/flang/include/flang/Optimizer/Support/Utils.h
index d2f0be15d7dd9..34f41b8cf9524 100644
--- a/flang/include/flang/Optimizer/Support/Utils.h
+++ b/flang/include/flang/Optimizer/Support/Utils.h
@@ -32,10 +32,12 @@
 #include "flang/Optimizer/CodeGen/TypeConverter.h"
 
 namespace fir {
-/// Return the line of a location, or 1 if it does not carry one.
+/// Return the line of a location, or 1 if it does not carry one. The location
+/// can be a fused one, e.g. for something read from an INCLUDE'd file, so
+/// search it rather than expecting a bare FileLineColLoc.
 inline uint32_t getLineFromLoc(mlir::Location loc) {
   uint32_t line = 1;
-  if (auto fileLoc = mlir::dyn_cast<mlir::FileLineColLoc>(loc))
+  if (auto fileLoc = loc->findInstanceOf<mlir::FileLineColLoc>())
     line = fileLoc.getLine();
   return line;
 }
diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 045caafa3e5f9..e710cf003bd4c 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -146,13 +146,17 @@ class AddDebugInfoPass : public fir::impl::AddDebugInfoBase<AddDebugInfoPass> {
                            fir::cg::XDeclareOp typeGenDeclOp);
 };
 
+/// Whether \p loc already carries debug information of type \c AttrT, fused
+/// onto it by this pass. A location is fused for unrelated reasons too, most
+/// notably one that came from an INCLUDE'd file, so what the fusion holds has
+/// to be examined rather than the fusion merely detected. Each caller names
+/// the attribute it would attach itself, so nothing here needs updating when
+/// another kind of debug information is generated elsewhere. Only the
+/// outermost fusion is examined, because that is the one this pass adds.
+template <typename AttrT>
 bool debugInfoIsAlreadySet(mlir::Location loc) {
-  if (mlir::isa<mlir::FusedLoc>(loc)) {
-    if (loc->findInstanceOf<mlir::FusedLocWith<fir::LocationKindAttr>>())
-      return false;
-    return true;
-  }
-  return false;
+  auto fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc);
+  return fusedLoc && mlir::isa_and_present<AttrT>(fusedLoc.getMetadata());
 }
 
 // Generates the name for the artificial DISubprogram that we are going to
@@ -566,7 +570,8 @@ void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
                                       fir::DebugTypeGenerator &typeGen,
                                       mlir::SymbolTable *symbolTable,
                                       fir::cg::XDeclareOp declOp) {
-  if (debugInfoIsAlreadySet(globalOp.getLoc()))
+  // A global is described by an array of DIGlobalVariableExpressionAttr.
+  if (debugInfoIsAlreadySet<mlir::ArrayAttr>(globalOp.getLoc()))
     return;
   mlir::MLIRContext *context = &getContext();
   mlir::OpBuilder builder(context);
@@ -644,8 +649,9 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
                                     mlir::SymbolTable *symbolTable) {
   mlir::Location l = funcOp->getLoc();
   // If fused location has already been created then nothing to do
-  // Otherwise, create a fused location.
-  if (debugInfoIsAlreadySet(l))
+  // Otherwise, create a fused location. A function is described by a
+  // DISubprogramAttr.
+  if (debugInfoIsAlreadySet<mlir::LLVM::DISubprogramAttr>(l))
     return;
 
   mlir::MLIRContext *context = &getContext();
@@ -656,7 +662,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
                         ? llvm::dwarf::getCallingConvention("DW_CC_program")
                         : llvm::dwarf::getCallingConvention("DW_CC_normal");
 
-  if (auto funcLoc = mlir::dyn_cast<mlir::FileLineColLoc>(l)) {
+  if (auto funcLoc = l->findInstanceOf<mlir::FileLineColLoc>()) {
     fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
     filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
   }
diff --git a/flang/test/Integration/debug-include-file.f90 b/flang/test/Integration/debug-include-file.f90
new file mode 100644
index 0000000000000..ab69921c98149
--- /dev/null
+++ b/flang/test/Integration/debug-include-file.f90
@@ -0,0 +1,35 @@
+! RUN: split-file %s %t
+! RUN: %flang_fc1 -emit-llvm -debug-info-kind=standalone -I %t %t/main.f90 -o - | FileCheck %s
+
+! A procedure written in an INCLUDE'd file gets a location that is fused with
+! the inclusion information. Check that it still gets debug information, and
+! that the information points at the file and line where the procedure is
+! written rather than at the INCLUDE statement.
+
+!--- body.f90
+! Nothing here starts on line 1 on purpose. 1 is also the line that is reported
+! when a position cannot be read out of the location, so checking for it would
+! pass whether or not the location was understood.
+subroutine included_sub(i)
+  integer :: i
+  i = 1
+  call inner()
+contains
+subroutine inner()
+  i = i + 1
+end subroutine
+end subroutine
+
+!--- main.f90
+include 'body.f90'
+program p
+  integer :: i
+  call included_sub(i)
+  print *, i
+end program
+
+! CHECK-DAG: ![[BODY:[0-9]+]] = !DIFile(filename: "body.f90"
+! CHECK-DAG: ![[SUB:[0-9]+]] = distinct !DISubprogram(name: "included_sub", linkageName: "included_sub_", {{.*}}file: ![[BODY]], line: 4, {{.*}}scopeLine: 4
+! CHECK-DAG: !DISubprogram(name: "inner", linkageName: "_QFincluded_subPinner", scope: ![[SUB]], file: ![[BODY]], line: 9, {{.*}}scopeLine: 9
+! CHECK-DAG: !DISubprogram(name: "p", linkageName: "_QQmain", {{.*}}file: ![[MAIN:[0-9]+]], line: 2
+! CHECK-DAG: ![[MAIN]] = !DIFile(filename: "main.f90"
diff --git a/flang/test/Transforms/debug-dummy-argument-inline.fir b/flang/test/Transforms/debug-dummy-argument-inline.fir
index 02f0d5c6539b4..e4ec5e182c078 100644
--- a/flang/test/Transforms/debug-dummy-argument-inline.fir
+++ b/flang/test/Transforms/debug-dummy-argument-inline.fir
@@ -2,8 +2,10 @@
 // procedure where the calls were inlined.
 // RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s -o - | FileCheck %s
 
+// The inlined declaration is a callsite location, so its line is the one the
+// variable is declared on in the inlined procedure, not the line of the call.
 // CHECK: #di_local_variable = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 6, arg = 1, type = #di_basic_type>
-// CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 1, type = #di_basic_type>
+// CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 2, type = #di_basic_type>
 
 func.func @foo_(%arg0: !fir.ref<i32> {fir.bindc_name = "i"} loc("debug-dummy-argument-inline.f90":5:1)) attributes {fir.internal_name = "_QPfoo"} {
   %0 = fir.undefined !fir.dscope loc(#loc5)
diff --git a/flang/test/Transforms/debug-include-file.fir b/flang/test/Transforms/debug-include-file.fir
new file mode 100644
index 0000000000000..007c5932637a1
--- /dev/null
+++ b/flang/test/Transforms/debug-include-file.fir
@@ -0,0 +1,46 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+
+// Lowering fuses the inclusion information onto the location of anything read
+// through an INCLUDE statement, which is the shape reproduced below. Check that
+// a procedure and a global carrying such a location still get debug
+// information, and that it names the file and line where they are written
+// rather than the INCLUDE statement.
+
+module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
+  func.func @_QPincluded_sub(%arg0: !fir.ref<i32>) {
+    return loc(#ret_in_body)
+  } loc(#sub_in_body)
+
+  fir.global @_QMmEmodvar : i32 {
+    %c7_i32 = arith.constant 7 : i32 loc(#global_in_body)
+    fir.has_value %c7_i32 : i32 loc(#global_in_body)
+  } loc(#global_in_body)
+
+  func.func @_QQmain() {
+    return loc(#ret_in_main)
+  } loc(#prog_in_main)
+} loc(#module_loc)
+
+#module_loc = loc("main.f90":0:0)
+// The INCLUDE statement itself, on line 1 of the including file.
+#include_stmt = loc("main.f90":1:1)
+
+// Written in the included file, reached through the INCLUDE statement.
+#sub_pos = loc("body.f90":4:1)
+#sub_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#sub_pos, #include_stmt])
+#ret_pos = loc("body.f90":6:1)
+#ret_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#ret_pos, #include_stmt])
+#global_pos = loc("body.f90":2:14)
+#global_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#global_pos, #include_stmt])
+
+// Written in the including file, for contrast.
+#prog_in_main = loc("main.f90":2:1)
+#ret_in_main = loc("main.f90":4:1)
+
+// CHECK-DAG: #[[MAIN:.*]] = #llvm.di_file<"main.f90" in "">
+// CHECK-DAG: #[[BODY:.*]] = #llvm.di_file<"body.f90" in "">
+// CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "included_sub", linkageName = "_QPincluded_sub", file = #[[BODY]], line = 4, scopeLine = 4{{.*}}>
+// CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "_QQmain", linkageName = "_QQmain", file = #[[MAIN]], line = 2, scopeLine = 2{{.*}}>
+// A global takes its file from the compile unit rather than from its own
+// location, so only the line is checked here.
+// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "modvar", linkageName = "_QMmEmodvar", {{.*}}line = 2{{.*}}>

>From ede37da1adc6c7d230c60764ccaa8af0545ae24c Mon Sep 17 00:00:00 2001
From: Abid Qadeer <haqadeer at amd.com>
Date: Tue, 22 Sep 2026 10:11:57 +0100
Subject: [PATCH 2/2] [flang][debug] Describe variables in the file they are
 written in.

Only handleFuncOp derived a file from the operation's own location. A
local, a dummy argument and a global all took the compile unit's file,
while taking their line from their own location, so a variable written in
an INCLUDE'd file was reported at that line of the file doing the
including.

Move that lookup into a helper and use it for the local variable and the
global as well. A location that names no file still falls back to the
compile unit's.

Nothing outside an INCLUDE changes meaning. Where a variable was already in
the file being compiled the emitted DWARF is identical, because the compile
unit's file and the one its location names resolve to the same path, and a
subprogram was described in the latter already. The two are still separate
DIFileAttr in a normal compilation, where the compile unit is built from the
name the input was given together with the working directory and a location
is split into its base name and its parent, so the tests that pinned a
particular one have been updated.

Co-authored-by: Cursor <cursoragent at cursor.com>
---
 .../lib/Optimizer/Transforms/AddDebugInfo.cpp | 28 +++++++++++--------
 flang/test/Integration/debug-include-file.f90 |  1 +
 flang/test/Integration/debug-module-2.f90     |  4 +--
 .../Integration/debug-module-constant.f90     | 11 +++++---
 .../test/Transforms/debug-derived-type-1.fir  |  2 +-
 .../debug-dummy-argument-inline.fir           |  4 +--
 flang/test/Transforms/debug-include-file.fir  | 15 ++++++----
 7 files changed, 39 insertions(+), 26 deletions(-)

diff --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index e710cf003bd4c..8734e45de244b 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -159,6 +159,18 @@ bool debugInfoIsAlreadySet(mlir::Location loc) {
   return fusedLoc && mlir::isa_and_present<AttrT>(fusedLoc.getMetadata());
 }
 
+/// The file that \p loc names, or \p fallback if it names none.
+mlir::LLVM::DIFileAttr getFileAttrFromLoc(mlir::Location loc,
+                                          mlir::LLVM::DIFileAttr fallback) {
+  auto fileLoc = loc->findInstanceOf<mlir::FileLineColLoc>();
+  if (!fileLoc)
+    return fallback;
+  llvm::StringRef path = fileLoc.getFilename().getValue();
+  return mlir::LLVM::DIFileAttr::get(loc.getContext(),
+                                     llvm::sys::path::filename(path),
+                                     llvm::sys::path::parent_path(path));
+}
+
 // Generates the name for the artificial DISubprogram that we are going to
 // generate for omp::TargetOp. Its logic is borrowed from
 // getTargetEntryUniqueInfo and
@@ -432,7 +444,8 @@ void AddDebugInfoPass::handleLocalVariable(Op declOp, llvm::StringRef name,
   }
 
   auto localVarAttr = mlir::LLVM::DILocalVariableAttr::get(
-      context, scopeAttr, mlir::StringAttr::get(context, name), fileAttr,
+      context, scopeAttr, mlir::StringAttr::get(context, name),
+      getFileAttrFromLoc(declOp.getLoc(), fileAttr),
       fir::getLineFromLoc(declOp.getLoc()), argNo, /* alignInBits*/ 0, tyAttr,
       mlir::LLVM::DIFlags::Zero);
   declOp->setLoc(builder.getFusedLoc({declOp->getLoc()}, localVarAttr));
@@ -622,7 +635,8 @@ void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
       typeGen.convertType(globalOp.getType(), fileAttr, scope, declOp);
   auto gvAttr = mlir::LLVM::DIGlobalVariableAttr::get(
       context, scope, mlir::StringAttr::get(context, result.second.name),
-      linkageName, fileAttr, line, diType, isLocalToUnit,
+      linkageName, getFileAttrFromLoc(globalOp.getLoc(), fileAttr), line,
+      diType, isLocalToUnit,
       /*isDefinition*/ globalOp.isInitialized(), /* alignInBits*/ 0);
   auto dbgExpr = mlir::LLVM::DIGlobalVariableExpressionAttr::get(
       globalOp.getContext(), gvAttr, nullptr);
@@ -656,17 +670,10 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
 
   mlir::MLIRContext *context = &getContext();
   mlir::OpBuilder builder(context);
-  llvm::StringRef fileName(fileAttr.getName());
-  llvm::StringRef filePath(fileAttr.getDirectory());
   unsigned int CC = (funcOp.getName() == fir::NameUniquer::doProgramEntry())
                         ? llvm::dwarf::getCallingConvention("DW_CC_program")
                         : llvm::dwarf::getCallingConvention("DW_CC_normal");
 
-  if (auto funcLoc = l->findInstanceOf<mlir::FileLineColLoc>()) {
-    fileName = llvm::sys::path::filename(funcLoc.getFilename().getValue());
-    filePath = llvm::sys::path::parent_path(funcLoc.getFilename().getValue());
-  }
-
   mlir::StringAttr fullName = mlir::StringAttr::get(context, funcOp.getName());
   mlir::Attribute attr = funcOp->getAttr(fir::getInternalFuncNameAttrName());
   mlir::StringAttr funcName =
@@ -712,8 +719,7 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
 
   mlir::LLVM::DISubroutineTypeAttr subTypeAttr =
       mlir::LLVM::DISubroutineTypeAttr::get(context, CC, types);
-  mlir::LLVM::DIFileAttr funcFileAttr =
-      mlir::LLVM::DIFileAttr::get(context, fileName, filePath);
+  mlir::LLVM::DIFileAttr funcFileAttr = getFileAttrFromLoc(l, fileAttr);
 
   // Only definitions need a distinct identifier and a compilation unit.
   mlir::DistinctAttr id, id2;
diff --git a/flang/test/Integration/debug-include-file.f90 b/flang/test/Integration/debug-include-file.f90
index ab69921c98149..73393dc8bfacc 100644
--- a/flang/test/Integration/debug-include-file.f90
+++ b/flang/test/Integration/debug-include-file.f90
@@ -31,5 +31,6 @@ program p
 ! CHECK-DAG: ![[BODY:[0-9]+]] = !DIFile(filename: "body.f90"
 ! CHECK-DAG: ![[SUB:[0-9]+]] = distinct !DISubprogram(name: "included_sub", linkageName: "included_sub_", {{.*}}file: ![[BODY]], line: 4, {{.*}}scopeLine: 4
 ! CHECK-DAG: !DISubprogram(name: "inner", linkageName: "_QFincluded_subPinner", scope: ![[SUB]], file: ![[BODY]], line: 9, {{.*}}scopeLine: 9
+! CHECK-DAG: !DILocalVariable(name: "i", arg: 1, scope: ![[SUB]], file: ![[BODY]], line: 5
 ! CHECK-DAG: !DISubprogram(name: "p", linkageName: "_QQmain", {{.*}}file: ![[MAIN:[0-9]+]], line: 2
 ! CHECK-DAG: ![[MAIN]] = !DIFile(filename: "main.f90"
diff --git a/flang/test/Integration/debug-module-2.f90 b/flang/test/Integration/debug-module-2.f90
index 5e95702e47b75..98396023f45ab 100644
--- a/flang/test/Integration/debug-module-2.f90
+++ b/flang/test/Integration/debug-module-2.f90
@@ -9,11 +9,11 @@
 ! CHECK-DAG: ![[R4:.*]] = !DIBasicType(name: "real(kind=4)", size: 32, encoding: DW_ATE_float)
 ! CHECK-DAG: ![[I4:.*]] = !DIBasicType(name: "integer(kind=4)", size: 32, encoding: DW_ATE_signed)
 module helper
-! CHECK-DAG: ![[GLR:.*]] = distinct !DIGlobalVariable(name: "glr", linkageName: "_QMhelperEglr", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[R4]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[GLR:.*]] = distinct !DIGlobalVariable(name: "glr", linkageName: "_QMhelperEglr", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+2]], type: ![[R4]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: ![[GLRX:.*]] = !DIGlobalVariableExpression(var: ![[GLR]], expr: !DIExpression())
   real glr
 
-! CHECK-DAG: ![[GLI:.*]] = distinct !DIGlobalVariable(name: "gli", linkageName: "_QMhelperEgli", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[I4]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[GLI:.*]] = distinct !DIGlobalVariable(name: "gli", linkageName: "_QMhelperEgli", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+2]], type: ![[I4]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: ![[GLIX:.*]] = !DIGlobalVariableExpression(var: ![[GLI]], expr: !DIExpression())
   integer gli
 
diff --git a/flang/test/Integration/debug-module-constant.f90 b/flang/test/Integration/debug-module-constant.f90
index 5e48029adc6c8..b5d7c9dad2c8a 100644
--- a/flang/test/Integration/debug-module-constant.f90
+++ b/flang/test/Integration/debug-module-constant.f90
@@ -5,27 +5,30 @@
 ! the scope of the module, with a linkage name, and visible outside this compile
 ! unit.
 
+! The compile unit names the file as it was given on the command line, while
+! anything that has a source location names it as the location does.
 ! CHECK-DAG: ![[FILE:.*]] = !DIFile(filename: {{.*}}debug-module-constant.f90{{.*}})
+! CHECK-DAG: ![[FILE2:.*]] = !DIFile(filename: {{.*}}debug-module-constant.f90{{.*}})
 ! CHECK-DAG: ![[CU:.*]] = distinct !DICompileUnit({{.*}}file: ![[FILE]]{{.*}})
 ! CHECK-DAG: ![[MOD:.*]] = !DIModule(scope: ![[CU]], name: "helper"{{.*}})
 ! CHECK-DAG: ![[I4:.*]] = !DIBasicType(name: "integer(kind=4)", size: 32, encoding: DW_ATE_signed)
 ! CHECK-DAG: ![[R4:.*]] = !DIBasicType(name: "real(kind=4)", size: 32, encoding: DW_ATE_float)
 
 module helper
-! CHECK-DAG: ![[MAX:.*]] = distinct !DIGlobalVariable(name: "max_size", linkageName: "_QMhelperECmax_size", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[I4]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[MAX:.*]] = distinct !DIGlobalVariable(name: "max_size", linkageName: "_QMhelperECmax_size", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+2]], type: ![[I4]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: !DIGlobalVariableExpression(var: ![[MAX]], expr: !DIExpression())
   integer, parameter :: max_size = 100
 
-! CHECK-DAG: ![[PI:.*]] = distinct !DIGlobalVariable(name: "pi", linkageName: "_QMhelperECpi", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+2]], type: ![[R4]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[PI:.*]] = distinct !DIGlobalVariable(name: "pi", linkageName: "_QMhelperECpi", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+2]], type: ![[R4]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: !DIGlobalVariableExpression(var: ![[PI]], expr: !DIExpression())
   real, parameter :: pi = 3.14159274
 
-! CHECK-DAG: ![[PRIMES:.*]] = distinct !DIGlobalVariable(name: "primes", linkageName: "_QMhelperECprimes", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+3]], type: ![[ARR:.*]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[PRIMES:.*]] = distinct !DIGlobalVariable(name: "primes", linkageName: "_QMhelperECprimes", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+3]], type: ![[ARR:.*]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: ![[ARR]] = !DICompositeType(tag: DW_TAG_array_type, baseType: ![[I4]]{{.*}})
 ! CHECK-DAG: !DIGlobalVariableExpression(var: ![[PRIMES]], expr: !DIExpression())
   integer, parameter :: primes(3) = [2, 3, 5]
 
-! CHECK-DAG: ![[TAG:.*]] = distinct !DIGlobalVariable(name: "tag", linkageName: "_QMhelperECtag", scope: ![[MOD]], file: ![[FILE]], line: [[@LINE+3]], type: ![[STR:.*]], isLocal: false, isDefinition: true)
+! CHECK-DAG: ![[TAG:.*]] = distinct !DIGlobalVariable(name: "tag", linkageName: "_QMhelperECtag", scope: ![[MOD]], file: ![[FILE2]], line: [[@LINE+3]], type: ![[STR:.*]], isLocal: false, isDefinition: true)
 ! CHECK-DAG: ![[STR]] = !DIStringType(size: 40, encoding: DW_ATE_ASCII)
 ! CHECK-DAG: !DIGlobalVariableExpression(var: ![[TAG]], expr: !DIExpression())
   character(len=5), parameter :: tag = "hello"
diff --git a/flang/test/Transforms/debug-derived-type-1.fir b/flang/test/Transforms/debug-derived-type-1.fir
index 0440e7dd21091..d8bd0c7e4dec1 100644
--- a/flang/test/Transforms/debug-derived-type-1.fir
+++ b/flang/test/Transforms/debug-derived-type-1.fir
@@ -59,7 +59,7 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<!llvm.ptr<272>, d
 // CHECK-DAG: #[[ELMD1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "year", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32>
 // CHECK-DAG: #[[ELMD2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "month", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32, offsetInBits = 32>
 // CHECK-DAG: #[[ELMD3:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "day", baseType = #[[INT_TY]], sizeInBits = 32, alignInBits = 32, offsetInBits = 64>
-// CHECK-DAG: #[[DATE:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_date", file = #di_file, line = 17, scope = #[[MOD]], sizeInBits = 96, elements = #[[ELMD1]], #[[ELMD2]], #[[ELMD3]]>
+// CHECK-DAG: #[[DATE:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_date"{{.*}}line = 17, scope = #[[MOD]], sizeInBits = 96, elements = #[[ELMD1]], #[[ELMD2]], #[[ELMD3]]>
 // CHECK-DAG: #[[ELMP1:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "t_address", baseType = #[[ADDR]], sizeInBits = 32, alignInBits = 32>
 // CHECK-DAG: #[[ELMP2:.*]] = #llvm.di_derived_type<tag = DW_TAG_member, name = "name", baseType = #[[STR_TY]], sizeInBits = 160, alignInBits = 8, offsetInBits = 32>
 // CHECK-DAG: #[[PERS:.*]] = #llvm.di_composite_type<{{.*}}tag = DW_TAG_structure_type, name = "t_person"{{.*}}line = 35, scope = #[[MOD]], sizeInBits = 192, elements = #[[ELMP1]], #[[ELMP2]]>
diff --git a/flang/test/Transforms/debug-dummy-argument-inline.fir b/flang/test/Transforms/debug-dummy-argument-inline.fir
index e4ec5e182c078..db6214d9d9beb 100644
--- a/flang/test/Transforms/debug-dummy-argument-inline.fir
+++ b/flang/test/Transforms/debug-dummy-argument-inline.fir
@@ -4,8 +4,8 @@
 
 // The inlined declaration is a callsite location, so its line is the one the
 // variable is declared on in the inlined procedure, not the line of the call.
-// CHECK: #di_local_variable = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 6, arg = 1, type = #di_basic_type>
-// CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file, line = 2, type = #di_basic_type>
+// CHECK: #di_local_variable = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file1, line = 6, arg = 1, type = #di_basic_type>
+// CHECK: #di_local_variable1 = #llvm.di_local_variable<scope = #di_subprogram, name = "i", file = #di_file1, line = 2, type = #di_basic_type>
 
 func.func @foo_(%arg0: !fir.ref<i32> {fir.bindc_name = "i"} loc("debug-dummy-argument-inline.f90":5:1)) attributes {fir.internal_name = "_QPfoo"} {
   %0 = fir.undefined !fir.dscope loc(#loc5)
diff --git a/flang/test/Transforms/debug-include-file.fir b/flang/test/Transforms/debug-include-file.fir
index 007c5932637a1..d1277d7b35378 100644
--- a/flang/test/Transforms/debug-include-file.fir
+++ b/flang/test/Transforms/debug-include-file.fir
@@ -2,12 +2,14 @@
 
 // Lowering fuses the inclusion information onto the location of anything read
 // through an INCLUDE statement, which is the shape reproduced below. Check that
-// a procedure and a global carrying such a location still get debug
-// information, and that it names the file and line where they are written
-// rather than the INCLUDE statement.
+// a procedure, its dummy argument and a global carrying such a location still
+// get debug information, and that it names the file and line where they are
+// written rather than the INCLUDE statement.
 
 module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
   func.func @_QPincluded_sub(%arg0: !fir.ref<i32>) {
+    %0 = fir.undefined !fir.dscope loc(#sub_in_body)
+    %1 = fircg.ext_declare %arg0 dummy_scope %0 arg 1 {uniq_name = "_QFincluded_subEi"} : (!fir.ref<i32>, !fir.dscope) -> !fir.ref<i32> loc(#arg_in_body)
     return loc(#ret_in_body)
   } loc(#sub_in_body)
 
@@ -28,6 +30,8 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
 // Written in the included file, reached through the INCLUDE statement.
 #sub_pos = loc("body.f90":4:1)
 #sub_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#sub_pos, #include_stmt])
+#arg_pos = loc("body.f90":5:14)
+#arg_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#arg_pos, #include_stmt])
 #ret_pos = loc("body.f90":6:1)
 #ret_in_body = loc(fused<#fir<loc_kind_array[<base>, <inclusion>]>>[#ret_pos, #include_stmt])
 #global_pos = loc("body.f90":2:14)
@@ -41,6 +45,5 @@ module attributes {dlti.dl_spec = #dlti.dl_spec<>} {
 // CHECK-DAG: #[[BODY:.*]] = #llvm.di_file<"body.f90" in "">
 // CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "included_sub", linkageName = "_QPincluded_sub", file = #[[BODY]], line = 4, scopeLine = 4{{.*}}>
 // CHECK-DAG: #llvm.di_subprogram<{{.*}}name = "_QQmain", linkageName = "_QQmain", file = #[[MAIN]], line = 2, scopeLine = 2{{.*}}>
-// A global takes its file from the compile unit rather than from its own
-// location, so only the line is checked here.
-// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "modvar", linkageName = "_QMmEmodvar", {{.*}}line = 2{{.*}}>
+// CHECK-DAG: #llvm.di_local_variable<{{.*}}name = "i", file = #[[BODY]], line = 5{{.*}}>
+// CHECK-DAG: #llvm.di_global_variable<{{.*}}name = "modvar", linkageName = "_QMmEmodvar", file = #[[BODY]], line = 2{{.*}}>



More information about the flang-commits mailing list