[1/1] gdb/dwarf, fortran: Use the function scope for DW_TAG_imported_declaration
Commit Message
All Fortran imported variable aliases (`use module, alias => var`) were
being added to "global scope", regardless of whether they appeared in:
- Program/module scope (should be global)
- Function scope (should be local)
This caused conflicts when different functions had the same alias name
pointing to different variables.
DW_TAG_imported_declaration and DW_TAG_namespace cases are now handled
separately. The issue is Fortran-specific and does not affect
DW_TAG_namespace. This patch modifies the case for DW_TAG_imported_
declaration in the function new_symbol () to use cu->list_in_scope instead
of global symbols for Fortran. This ensures that function-scoped aliases
use the current scope rather than being forced into the global scope.
Bug Scenario:
subroutine sub1
use mod1, var_i_alias=>var_i ! alias points to mod1::var_i
var_i_alias = 3
var_i = 4
end subroutine
subroutine sub2
use mod2, var_i_alias=>var_i ! alias points to mod2::var_i
var_i_alias = 23
var_i = 25
end subroutine
Before: var_i_alias in sub2 incorrectly resolved to mod1::var_i (value 25)
After: Each function's alias correctly resolves to its own imported
variable (value 23)
New test files verify the fix and include regression tests for global
program-scope imports:
- gdb/testsuite/gdb.fortran/module_declarations.exp
- gdb/testsuite/gdb.fortran/module_declarations.f90
Before the change:
(gdb) print var_i_alias
$4 = 25
FAIL: gdb.fortran/module_declarations.exp: sub2_test: print var_i_alias
After the change:
(gdb) print var_i_alias
$4 = 23
PASS: gdb.fortran/module_declarations.exp: sub2_test: print var_i_alias
---
gdb/dwarf2/read.c | 12 ++++
.../gdb.fortran/module_declarations.exp | 62 +++++++++++++++++++
.../gdb.fortran/module_declarations.f90 | 59 ++++++++++++++++++
3 files changed, 133 insertions(+)
create mode 100644 gdb/testsuite/gdb.fortran/module_declarations.exp
create mode 100644 gdb/testsuite/gdb.fortran/module_declarations.f90
Comments
>>>>> Abdul Basit Ijaz <abdul.b.ijaz@intel.com> writes:
> All Fortran imported variable aliases (`use module, alias => var`) were
> being added to "global scope", regardless of whether they appeared in:
> - Program/module scope (should be global)
> - Function scope (should be local)
Thanks for the patch.
> case DW_TAG_imported_declaration:
> + sym->set_domain (TYPE_DOMAIN);
> + sym->set_loc_class_index (LOC_TYPEDEF);
> + /* For Fortran imported declarations, use current scope context
> + rather than forcing global scope. This ensures variable aliases
> + are scoped correctly (function-level, module-level, or
> + program-level). */
> + if (cu->lang () == language_fortran)
> + list_to_add = cu->list_in_scope;
> + else
> + list_to_add = &cu->get_builder ()->get_global_symbols ();
I wonder if this could simply omit the 'if' and do the "usual"
file->global transform like:
list_to_add
= ((cu->list_in_scope
== &cu->get_builder ()->get_file_symbols ())
? &cu->get_builder ()->get_global_symbols ()
: cu->list_in_scope);
That is, do we know for sure that there's some language requiring that a
local import be stuffed into the global scope?
I tend to think such DWARF wouldn't exist and the code would be easier
to maintain in the long run without a fortran-specific check.
Would you mind giving this a try?
thanks,
Tom
Thanks Tom for the feedback.
>> + if (cu->lang () == language_fortran)
>> + list_to_add = cu->list_in_scope;
>> + else
>> + list_to_add = &cu->get_builder ()->get_global_symbols ();
Tom>That is, do we know for sure that there's some language requiring that a local import be stuffed into the global scope?
Abdul> Also not sure about the others languages.
Tom>I tend to think such DWARF wouldn't exist and the code would be easier to maintain in the long run without a fortran-specific check.
Tom>Would you mind giving this a try?
Tom> list_to_add
Tom> = ((cu->list_in_scope
Tom> == &cu->get_builder ()->get_file_symbols ())
Tom> ? &cu->get_builder ()->get_global_symbols ()
Tom> : cu->list_in_scope);
Abdul>Should be working fine. I will try this change and if it works fine then I will push the patch 2 with this change.
Best Regards,
Abdul Basit
-----Original Message-----
From: Tom Tromey <tom@tromey.com>
Sent: Friday, May 1, 2026 6:49 PM
To: Ijaz, Abdul B <abdul.b.ijaz@intel.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH 1/1] gdb/dwarf, fortran: Use the function scope for DW_TAG_imported_declaration
>>>>> Abdul Basit Ijaz <abdul.b.ijaz@intel.com> writes:
> All Fortran imported variable aliases (`use module, alias => var`)
> were being added to "global scope", regardless of whether they appeared in:
> - Program/module scope (should be global)
> - Function scope (should be local)
Thanks for the patch.
> case DW_TAG_imported_declaration:
> + sym->set_domain (TYPE_DOMAIN);
> + sym->set_loc_class_index (LOC_TYPEDEF);
> + /* For Fortran imported declarations, use current scope context
> + rather than forcing global scope. This ensures variable aliases
> + are scoped correctly (function-level, module-level, or
> + program-level). */
> + if (cu->lang () == language_fortran)
> + list_to_add = cu->list_in_scope;
> + else
> + list_to_add = &cu->get_builder ()->get_global_symbols ();
I wonder if this could simply omit the 'if' and do the "usual"
file->global transform like:
list_to_add
= ((cu->list_in_scope
== &cu->get_builder ()->get_file_symbols ())
? &cu->get_builder ()->get_global_symbols ()
: cu->list_in_scope);
That is, do we know for sure that there's some language requiring that a local import be stuffed into the global scope?
I tend to think such DWARF wouldn't exist and the code would be easier to maintain in the long run without a fortran-specific check.
Would you mind giving this a try?
thanks,
Tom
Intel Deutschland GmbH
Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany
Tel: +49 89 991 430, www.intel.de
Managing Directors: Harry Demas, Jeffrey Schneiderman, Yin Chong Sorrell
Chairperson of the Supervisory Board: Nicole Lau
Registered Seat: Munich
Commercial Register: Amtsgericht Muenchen HRB 186928
@@ -15858,6 +15858,18 @@ new_symbol (struct die_info *die, struct dwarf2_cu *cu, struct symbol *sym,
: cu->list_in_scope);
break;
case DW_TAG_imported_declaration:
+ sym->set_domain (TYPE_DOMAIN);
+ sym->set_loc_class_index (LOC_TYPEDEF);
+ /* For Fortran imported declarations, use current scope context
+ rather than forcing global scope. This ensures variable aliases
+ are scoped correctly (function-level, module-level, or
+ program-level). */
+ if (cu->lang () == language_fortran)
+ list_to_add = cu->list_in_scope;
+ else
+ list_to_add = &cu->get_builder ()->get_global_symbols ();
+
+ break;
case DW_TAG_namespace:
sym->set_domain (TYPE_DOMAIN);
sym->set_loc_class_index (LOC_TYPEDEF);
new file mode 100644
@@ -0,0 +1,62 @@
+# Copyright 2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "fortran.exp"
+
+require allow_fortran_tests
+
+standard_testfile .f90
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug f90}] } {
+ return
+}
+
+if {![fortran_runto_main]} {
+ return
+}
+
+# Test global alias at program scope
+gdb_breakpoint [gdb_get_line_number "bp-main"]
+gdb_continue_to_breakpoint "bp-main" ".*bp-main.*"
+
+with_test_prefix "global_test" {
+ gdb_test "print global_alias" " = 200"
+ gdb_test "print global_var_i_from_mod1" " = 300"
+}
+
+gdb_breakpoint [gdb_get_line_number "bp-sub1"]
+gdb_continue_to_breakpoint "bp-sub1" ".*bp-sub1.*"
+
+with_test_prefix "sub1_test" {
+ gdb_test "print var_i_alias" " = 3"
+ gdb_test "print var_i" " = 4"
+}
+
+gdb_breakpoint [gdb_get_line_number "bp-sub2"]
+gdb_continue_to_breakpoint "bp-sub2" ".*bp-sub2.*"
+
+with_test_prefix "sub2_test" {
+ gdb_test "print var_i_alias" " = 23"
+ gdb_test "print var_i" " = 25"
+}
+
+# Test same-name variables shadowed within same function
+gdb_breakpoint [gdb_get_line_number "bp-sub3"]
+gdb_continue_to_breakpoint "bp-sub3" ".*bp-sub3.*"
+
+with_test_prefix "sub3_shadow_test" {
+ gdb_test "print var_i_from_mod1" " = 31"
+ gdb_test "print var_i_from_mod2" " = 32"
+}
new file mode 100644
@@ -0,0 +1,59 @@
+! Copyright 2026 Free Software Foundation, Inc.
+!
+! This program is free software; you can redistribute it and/or modify
+! it under the terms of the GNU General Public License as published by
+! the Free Software Foundation; either version 3 of the License, or
+! (at your option) any later version.
+!
+! This program is distributed in the hope that it will be useful,
+! but WITHOUT ANY WARRANTY; without even the implied warranty of
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+! GNU General Public License for more details.
+!
+! You should have received a copy of the GNU General Public License
+! along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+module mod1
+ implicit none
+ integer :: var_i = 1
+ integer :: global_var = 100
+end module mod1
+
+module mod2
+ implicit none
+ integer :: var_i = 2
+end module mod2
+
+subroutine sub1
+ use mod1, var_i_alias=>var_i
+ use mod2
+ implicit none
+ var_i_alias = 3
+ var_i = 4
+end subroutine ! bp-sub1
+
+subroutine sub2
+ use mod1
+ use mod2, var_i_alias=>var_i
+ implicit none
+ var_i_alias = 23
+ var_i = 25
+end subroutine ! bp-sub2
+
+subroutine sub3
+ use mod1, var_i_from_mod1=>var_i
+ use mod2, var_i_from_mod2=>var_i
+ implicit none
+ var_i_from_mod1 = 31
+ var_i_from_mod2 = 32
+end subroutine ! bp-sub3
+
+program main
+ use mod1, global_alias=>global_var, global_var_i_from_mod1=>var_i
+ implicit none
+ global_alias = 200
+ global_var_i_from_mod1 = 300
+ call sub1 ! bp-main
+ call sub2
+ call sub3
+end