[flang-commits] [flang] Reland [flang][debug] Emit debug info for named constants- #213974 (PR #215369)

Eugene Epshteyn via flang-commits flang-commits at lists.llvm.org
Tue Aug 11 05:48:06 PDT 2026


================
@@ -510,8 +521,27 @@ void AddDebugInfoPass::handleGlobalOp(fir::GlobalOp globalOp,
   mlir::OpBuilder builder(context);
 
   std::pair result = fir::NameUniquer::deconstruct(globalOp.getSymName());
-  if (result.first != fir::NameUniquer::NameKind::VARIABLE)
+  switch (result.first) {
+  case fir::NameUniquer::NameKind::VARIABLE:
+    break;
+  case fir::NameUniquer::NameKind::CONSTANT:
+    // A constant local to a procedure is described while walking that
+    // procedure, where `scope` is its DISubprogramAttr. Reaching here with any
+    // other scope means the procedure is not in the IR, typically because it
+    // was never called and got removed while its constant survived. There is
+    // no procedure to attach the constant to, and describing it at compile
+    // unit scope would wrongly make it visible everywhere.
+    if (!isModuleLevelName(result.second) &&
+        !mlir::isa<mlir::LLVM::DISubprogramAttr>(scope))
+      return;
+    // Don't describe a constant for which we only have a declaration. It could
+    // leave an unresolved symbol in the debug information.
+    if (!globalOp.isInitialized())
----------------
eugeneepshteyn wrote:

AI reviewer flagged the following here. This is beyond my current knowledge of debug info, so please check if this makes sense to you:

In `getModuleAttrFromGlobalOp` (`flang/lib/Optimizer/Transforms/AddDebugInfo.cpp`),
`decl = !globalOp.isInitialized()` answers *"does this unit initialize this global?"* and
is used to answer *"is this unit where the module is defined?"*. Those coincide for a
module **variable**, which is initialized exactly where its module is defined. They do not
coincide for a named **constant**: an intrinsic module's constants are materialized
locally (as `linkonce_odr`) in every using unit. Since the early walk now uses
`isModuleDataObject` instead of `isModuleVariable`, constants reach
`getOrCreateModuleAttr`, whose map is first-writer-wins — so one locally-materialized
constant makes the whole intrinsic module look locally defined.

Same 10-line source, `-g -O0`, patched vs. unpatched:

```fortran
program p
  use iso_fortran_env
  implicit none
  print *, 'hello'
end program p
```

| build | `DW_TAG_module "iso_fortran_env"` | `.rela.debug_info` relocations naming it |
|---|---|---|
| main (before this PR) | `DW_AT_declaration (true)` | 0 |
| **this PR** | `DW_AT_decl_file ("p01.f90") DW_AT_decl_line (75)` | **1** |

So the emitted DWARF states that `iso_fortran_env` is defined at line 75 of a 10-line user
program. The relocation is `R_X86_64_64 _QMiso_fortran_envECcharacter_kinds` against a
`WEAK DEFAULT` **defined** symbol, which is why nothing fails to link — but the statement
is still false, and it is a regression in metadata quality against main.

The same mechanism is **order-sensitive in ordinary user code**. Two submodule sources
differing only in the order of items in one `print`:

par3.f90:
```fortran
module par3
  implicit none
  integer :: pv = 1
  integer, parameter :: pk = 5
  integer, parameter :: ptbl(3) = [7,8,9]
  interface
    module subroutine work()
    end subroutine
  end interface
end module par3
```

kid3.f90:
```fortran
submodule (par3) kid3
  implicit none
  integer, parameter :: sq(3) = [9,8,7]
contains
  module subroutine work()
    print *, pv, pk, ptbl, sq
  end subroutine work
end submodule kid3
```

kid2.f90 (same as kid3, except the `print` order is different):
```fortran
submodule (par3) kid3
  implicit none
  integer, parameter :: sq(3) = [9,8,7]
contains
  module subroutine work()
    print *, sq, pv, pk, ptbl
  end subroutine work
end submodule kid3
```
| object | `.rela.debug_info` relocations naming `_QMpar3` |
|---|---|
| `kid3.o` | **0** |
| `kid4.o` | **2**, including `R_X86_64_64 _QMpar3Epv` — and `_QMpar3Epv` is `UND` in that object |

`kid4` links and runs correctly (`par3.o` defines `_QMpar3Epv`), so this is not a link
failure — but debug-info content that depends on the order of items in a `print` statement
is a fragile place to be, and it is the same predicate that caused the revert.


https://github.com/llvm/llvm-project/pull/215369


More information about the flang-commits mailing list