[flang-commits] [flang] [flang] Exclude procedure scope variables in isModuleScopeDataUniquedName (PR #192999)
via flang-commits
flang-commits at lists.llvm.org
Mon Apr 20 08:28:03 PDT 2026
https://github.com/nvptm created https://github.com/llvm/llvm-project/pull/192999
In particular, for saved local such as `x` in the sample below, isModuleScopeDataUniquedName should return false.
```
module m
contains
subroutine foo()
integer, save :: x ! <-- SAVE
end subroutine
end
```
>From 06eb750e9d6216169c4720abdf67f0fac3cce33b Mon Sep 17 00:00:00 2001
From: nvpm <pmathew at nvidia.com>
Date: Mon, 20 Apr 2026 08:22:09 -0700
Subject: [PATCH] Update isModuleScopeDataUniquedName to exclude module
procedure scope variables
---
.../flang/Optimizer/Support/InternalNames.h | 4 +++-
flang/lib/Optimizer/Support/InternalNames.cpp | 5 ++++-
.../unittests/Optimizer/InternalNamesTest.cpp | 21 ++++++++++++++++---
3 files changed, 25 insertions(+), 5 deletions(-)
diff --git a/flang/include/flang/Optimizer/Support/InternalNames.h b/flang/include/flang/Optimizer/Support/InternalNames.h
index 238d491ac99c1..004fb8633f4df 100644
--- a/flang/include/flang/Optimizer/Support/InternalNames.h
+++ b/flang/include/flang/Optimizer/Support/InternalNames.h
@@ -158,7 +158,9 @@ struct NameUniquer {
/// True if \p uniquedName denotes module-scope data (variable, named
/// constant, or common block), as opposed to procedures, types, or other
- /// symbols that may still carry a module prefix in the mangling.
+ /// symbols that may still carry a module prefix in the mangling. This
+ /// excludes symbols nested in a procedure according to the mangled prefix
+ /// (including \c SAVE locals in module procedures).
static bool isModuleScopeDataUniquedName(llvm::StringRef uniquedName);
/// Given a mangled derived type name, get the name of the related derived
diff --git a/flang/lib/Optimizer/Support/InternalNames.cpp b/flang/lib/Optimizer/Support/InternalNames.cpp
index b02ee054387f4..ba46249d1bba7 100644
--- a/flang/lib/Optimizer/Support/InternalNames.cpp
+++ b/flang/lib/Optimizer/Support/InternalNames.cpp
@@ -351,13 +351,16 @@ bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName,
/// uniqued root produced by \c fir::NameUniquer; \c deconstruct exposes that
/// as \c parts.modules. A non-empty module path means the symbol was declared
/// under a module or submodule, not only at program or internal unit scope.
+/// Procedure nesting is encoded as \c F<proc> ancestors in \c parts.procs;
+/// those must be empty so we do not classify locals inside module procedures
+/// (including \c SAVE locals) as module-scope data.
/// We then require \c VARIABLE, \c CONSTANT, or \c COMMON so we match
/// module-level data (including common), not procedures or other name kinds
/// that can also carry a module prefix.
bool fir::NameUniquer::isModuleScopeDataUniquedName(
llvm::StringRef uniquedName) {
auto [kind, parts] = fir::NameUniquer::deconstruct(uniquedName);
- if (parts.modules.empty())
+ if (parts.modules.empty() || !parts.procs.empty())
return false;
switch (kind) {
diff --git a/flang/unittests/Optimizer/InternalNamesTest.cpp b/flang/unittests/Optimizer/InternalNamesTest.cpp
index ab0b91622980a..611fd8d571e27 100644
--- a/flang/unittests/Optimizer/InternalNamesTest.cpp
+++ b/flang/unittests/Optimizer/InternalNamesTest.cpp
@@ -154,9 +154,7 @@ TEST(InternalNamesTest, doNamelistGroup) {
TEST(InternalNamesTest, deconstructTest) {
std::pair actual = NameUniquer::deconstruct("_QChello");
auto expectedNameKind = NameUniquer::NameKind::COMMON;
- struct DeconstructedName expectedComponents {
- {}, {}, 0, "hello", {}
- };
+ struct DeconstructedName expectedComponents{{}, {}, 0, "hello", {}};
validateDeconstructedName(actual, expectedNameKind, expectedComponents);
}
@@ -218,6 +216,23 @@ TEST(InternalNamesTest, needExternalNameMangling) {
ASSERT_TRUE(NameUniquer::needExternalNameMangling("_QCa"));
}
+TEST(InternalNamesTest, isModuleScopeDataUniquedName) {
+ // True cases: module-scope variable, constant, common block
+ ASSERT_TRUE(NameUniquer::isModuleScopeDataUniquedName("_QMmodEintvar"));
+ ASSERT_TRUE(NameUniquer::isModuleScopeDataUniquedName("_QMmodECpi"));
+ ASSERT_TRUE(NameUniquer::isModuleScopeDataUniquedName("_QMmodSsubEvar"));
+ // False cases (in order): module procedure, derived type, unqualified common
+ // block (no module), saved variable local to a procedure (nested blocks),
+ // external name, empty name, non-module-scope name.
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("_QMmodPsub"));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("_QMmodTmytype"));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("_QCblk"));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("_QFsubB2Ex"));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("someExternalName"));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName(""));
+ ASSERT_FALSE(NameUniquer::isModuleScopeDataUniquedName("_QMmFfooEx"));
+}
+
TEST(InternalNamesTest, isExternalFacingUniquedName) {
std::pair result = NameUniquer::deconstruct("_QMmodSs1modSs2modFsubPfun");
More information about the flang-commits
mailing list