[flang-commits] [flang] [flang][Semantics] Introduce `-Wpass-global-variable` warning (PR #160324)

via flang-commits flang-commits at lists.llvm.org
Tue Sep 23 08:17:36 PDT 2025


https://github.com/foxtran created https://github.com/llvm/llvm-project/pull/160324

In this PR, I've implemented detection of passing global variables defined in common blocks or/and modules in a bit naive way.

The main reason of implementing this that we have a lot of bugs with ifx compiler due extensively usage of passing all possible variables from common blocks to subroutines. 

Sometimes, Fortran programs actively utilises passing of global variables in a valid context, especially for stack memory allocators (like in GAMESS(US) or MRCC or Gaussian). For such cases, I've excluded those warning:
- common block has only one variable of shape [ 1 ]
- variable of shape [ 1 ] in module has attribute `allocatable`, `pointer` or `volatile`
- variable in module has attribute `parameter`

See allowed cases in test.


However, PR still have bugs.
- the checks are still working in compile time expressions (for example `flang/test/Evaluate/fold-type.f90`)
- by some reason, `!$omp declare target enter (val)` is supposed to be a function, so, the warnings are shown in this context
- the warning happens in already written tests

>From 19bb9f26ae81fa09751e4a091f7483d022a73577 Mon Sep 17 00:00:00 2001
From: "Igor S. Gerasimov" <foxtranigor at gmail.com>
Date: Tue, 23 Sep 2025 16:20:05 +0200
Subject: [PATCH 1/5] Implement -Wpass-global-variable flag for flang

---
 flang/include/flang/Support/Fortran-features.h | 2 +-
 flang/lib/Support/Fortran-features.cpp         | 1 +
 flang/unittests/Common/FortranFeaturesTest.cpp | 3 +++
 3 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 2bbc2385777da..78bec21748405 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -79,7 +79,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
     CompatibleDeclarationsFromDistinctModules,
     NullActualForDefaultIntentAllocatable, UseAssociationIntoSameNameSubprogram,
     HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile,
-    RealConstantWidening, VolatileOrAsynchronousTemporary)
+    RealConstantWidening, VolatileOrAsynchronousTemporary, PassGlobalVariable)
 
 using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
 using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 4a6fb8d75a135..bb5c7b56634e8 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -149,6 +149,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
   warnUsage_.set(UsageWarning::HostAssociatedIntentOutInSpecExpr);
   warnUsage_.set(UsageWarning::NonVolatilePointerToVolatile);
   warnUsage_.set(UsageWarning::RealConstantWidening);
+  warnUsage_.set(UsageWarning::PassGlobalVariable);
   // New warnings, on by default
   warnLanguage_.set(LanguageFeature::SavedLocalInSpecExpr);
   warnLanguage_.set(LanguageFeature::NullActualForAllocatable);
diff --git a/flang/unittests/Common/FortranFeaturesTest.cpp b/flang/unittests/Common/FortranFeaturesTest.cpp
index 9408da0361e1d..80417cfae035d 100644
--- a/flang/unittests/Common/FortranFeaturesTest.cpp
+++ b/flang/unittests/Common/FortranFeaturesTest.cpp
@@ -556,6 +556,9 @@ TEST(FortranFeaturesTest, CamelCaseToLowerCaseHyphenated) {
   EXPECT_EQ(CamelCaseToLowerCaseHyphenated(
                 EnumToString(UsageWarning::NonVolatilePointerToVolatile)),
       "non-volatile-pointer-to-volatile");
+  EXPECT_EQ(
+      CamelCaseToLowerCaseHyphenated(EnumToString(UsageWarning::PassGlobalVariable)),
+      "pass-global-variable");
 }
 
 TEST(FortranFeaturesTest, HintLanguageControlFlag) {

>From 0daa60d8566dcc8dc9db69b184d40997a1c38f73 Mon Sep 17 00:00:00 2001
From: "Igor S. Gerasimov" <foxtranigor at gmail.com>
Date: Tue, 23 Sep 2025 16:28:52 +0200
Subject: [PATCH 2/5] Add test for -Wpass-global-variable

---
 .../test/Semantics/pass-global-variables.f90  | 169 ++++++++++++++++++
 1 file changed, 169 insertions(+)
 create mode 100644 flang/test/Semantics/pass-global-variables.f90

diff --git a/flang/test/Semantics/pass-global-variables.f90 b/flang/test/Semantics/pass-global-variables.f90
new file mode 100644
index 0000000000000..73d1b8e334180
--- /dev/null
+++ b/flang/test/Semantics/pass-global-variables.f90
@@ -0,0 +1,169 @@
+!RUN: %python %S/test_errors.py %s %flang_fc1 -Werror
+module explicit_test_mod
+  implicit none (type, external)
+  integer :: i1
+  integer :: i2(1)
+  integer :: i3(3)
+  integer, allocatable :: ia(:)
+
+  real :: x1, y1
+  real :: x2, y2
+  real :: z, z2
+  common /xy1/ x1, y1(1)
+  common /xy2/ x2(1), y2
+  common /fm/ z(1)
+  common /fm_bad/ z2(5)
+contains
+  subroutine pass_int(i)
+    integer, intent(inout) :: i
+  end subroutine pass_int
+  subroutine pass_int_1d(i)
+    integer, intent(inout) :: i(*)
+  end subroutine pass_int_1d
+  subroutine pass_real(r)
+    real, intent(inout) :: r
+  end subroutine pass_real
+  subroutine pass_real_1d(r)
+    real, intent(inout) :: r(*)
+  end subroutine pass_real_1d
+  subroutine explicit_test(n)
+    integer, intent(in) :: n
+
+    !WARNING: Passing global variable 'i1' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int(i1)               !< warn:    basic type
+    call pass_int(i2(1))            !< ok:      shape == [1]
+    call pass_int(i2(n))            !< ok:      shape == [1]
+    !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int(i3(1))            !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int(i3(n))            !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int_1d(i2)            !< warn:    whole array is passed
+    call pass_int_1d(i2(n:n+3))     !< ok:      subrange of array
+    !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int_1d(i3)            !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+    call pass_int_1d(i3(n:n+3))     !< warn:    shape /= [1]
+    call pass_int(ia(1))            !< ok:      allocatable
+    call pass_int(ia(n))            !< ok:      allocatable
+    call pass_int_1d(ia)            !< ok:      allocatable
+    call pass_int_1d(ia(n:n+3))     !< ok:      allocatable
+
+    !WARNING: Passing global variable 'x1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+    call pass_real(x1)              !< warn:    x1 from common
+    !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+    call pass_real_1d(y1)           !< warn:    y1 from common or offset /= 0
+    !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+    call pass_real(y1(1))           !< warn:    offset /= 0
+    !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+    call pass_real(y1(n))           !< warn:    offset /= 0
+    !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+    call pass_real_1d(y1(n:n+3))    !< warn:    offset /= 0
+
+    !WARNING: Passing global variable 'y2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+    call pass_real(y2)              !< warn:    offset /= 0
+    !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+    call pass_real_1d(x2)           !< warn:    more than one variable in common block
+    !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+    call pass_real(x2(1))           !< warn:    more than one variable in common block
+    !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+    call pass_real(x2(n))           !< warn:    more than one variable in common block
+    !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+    call pass_real_1d(x2(n:n+3))    !< warn:    more than one variable in common block
+
+    !WARNING: Passing global variable 'z' from COMMON 'fm' as function argument [-Wpass-global-variable]
+    call pass_real_1d(z)            !< warn:    z from common
+    call pass_real(z(1))            !< ok:      single element/begin of mem block
+    call pass_real(z(n))            !< ok:      single element/begin of mem block
+    call pass_real_1d(z(n:n+3))     !< ok:      mem block
+
+    !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+    call pass_real_1d(z2)           !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+    call pass_real(z2(1))           !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+    call pass_real(z2(n))           !< warn:    shape /= [1]
+    !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+    call pass_real_1d(z2(n:n+3))    !< warn:    shape /= [1]
+  end subroutine explicit_test
+end module explicit_test_mod
+
+subroutine module_test(n)
+  use explicit_test_mod, only: i1, i2, i3, ia
+  implicit none (type, external)
+  integer, intent(in) :: n
+
+  external :: imp_pass_int, imp_pass_int_1d
+
+  !WARNING: Passing global variable 'i1' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int(i1)              !< warn:    i1 from common
+  call imp_pass_int(i2(1))           !< ok:      single element/begin of mem block
+  call imp_pass_int(i2(n))           !< ok:      single element/begin of mem block
+  !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int(i3(1))           !< warn:    shape /= [1]
+  !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int(i3(n))           !< warn:    shape /= [1]
+  call imp_pass_int(ia(1))           !< ok:      allocatable
+  call imp_pass_int(ia(n))           !< ok:      allocatable
+
+  !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int_1d(i2)           !< warn:    i2 from module
+  call imp_pass_int_1d(i2(n:n+3))    !< ok:      mem block
+  !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int_1d(i3)           !< warn:    i3 from module & shape /= [1]
+  !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
+  call imp_pass_int_1d(i3(n:n+3))    !< warn:    shape /= [1]
+  call imp_pass_int_1d(ia)           !< ok:      allocatable
+  call imp_pass_int_1d(ia(n:n+3))    !< ok:      allocatable
+end subroutine module_test
+
+subroutine implicit_test(n)
+  implicit none (type, external)
+  integer, intent(in) :: n
+  real :: x1, y1
+  real :: x2, y2
+  real :: z, z2
+  common /xy1/ x1, y1(1)
+  common /xy2/ x2(1), y2
+  common /fm/ z(1)
+  common /fm_bad/ z2(5)
+
+  external :: imp_pass_real, imp_pass_real_1d
+
+  !WARNING: Passing global variable 'x1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+  call imp_pass_real(x1)             !< warn:    x1 from common
+  !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(y1)          !< warn:    y1 from common and offset /= 0
+  !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+  call imp_pass_real(y1(1))          !< warn:    offset /= 0
+  !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+  call imp_pass_real(y1(n))          !< warn:    offset /= 0
+  !WARNING: Passing global variable 'y1' from COMMON 'xy1' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(y1(n:n+3))   !< warn:    offset /= 0
+
+  !WARNING: Passing global variable 'y2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+  call imp_pass_real(y2)             !< warn:    y2 from common and offset /= 0
+  !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(x2)          !< warn:    x2 from common
+  !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+  call imp_pass_real(x2(1))          !< warn:    more than one variable in common
+  !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+  call imp_pass_real(x2(n))          !< warn:    more than one variable in common
+  !WARNING: Passing global variable 'x2' from COMMON 'xy2' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(x2(n:n+3))   !< warn:    more than one variable in common
+
+  !WARNING: Passing global variable 'z' from COMMON 'fm' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(z)           !< warn:    z from common
+  call imp_pass_real(z(1))           !< ok:      single element/begin of mem block
+  call imp_pass_real(z(n))           !< ok:      single element/begin of mem block
+  call imp_pass_real_1d(z(n:n+3))    !< ok:      mem block
+
+  !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(z2)          !< warn:    z2 from common, shape /= [1]
+  !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+  call imp_pass_real(z2(1))          !< warn:    shape /= [1]
+  !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+  call imp_pass_real(z2(n))          !< warn:    shape /= [1]
+  !WARNING: Passing global variable 'z2' from COMMON 'fm_bad' as function argument [-Wpass-global-variable]
+  call imp_pass_real_1d(z2(n:n+3))   !< warn:    shape /= [1]
+end subroutine implicit_test

>From d53f48bd4808d021e753fbc435f00aeedb66c752 Mon Sep 17 00:00:00 2001
From: "Igor S. Gerasimov" <foxtranigor at gmail.com>
Date: Tue, 23 Sep 2025 16:45:29 +0200
Subject: [PATCH 3/5] Full implementation of -Wpass-global-varialbe for
 explicit interfaces

---
 flang/lib/Semantics/check-call.cpp | 57 ++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index 797fd067b8185..e259db4f23a18 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -1137,6 +1137,63 @@ static void CheckExplicitDataArg(const characteristics::DummyDataObject &dummy,
     messages.Say(
         "%VAL argument must be a scalar numeric or logical expression"_err_en_US);
   }
+
+  // passing global variables
+  if (actualFirstSymbol) {
+    bool warn{false};
+    std::string ownerType{""};
+    std::string ownerName{""};
+    if (actualFirstSymbol->flags().test(Symbol::Flag::InCommonBlock)) {
+      const Symbol *common{FindCommonBlockContaining(*actualFirstSymbol)};
+      ownerType = "COMMON";
+      ownerName = common->name().ToString();
+      if (!(actualFirstSymbol->Rank() == 1 && actualFirstSymbol->offset() == 0)) {
+        warn |= true;
+      } else if (actualFirstSymbol->Rank() == 1) {
+        bool actualIsArrayElement{IsArrayElement(actual) != nullptr};
+        if (!actualIsArrayElement) {
+          warn |= true;
+        }
+        if (const ArraySpec *dims{actualFirstSymbol->GetShape()};
+            dims && dims->IsExplicitShape()) {
+          if (!((*dims)[0].lbound().GetExplicit() == (*dims)[0].ubound().GetExplicit())) {
+            warn |= true;
+          }
+        }
+        if (common->get<CommonBlockDetails>().objects().size() > 1) {
+          warn |= true;
+        }
+      }
+    } else if (const auto &owner{actualFirstSymbol->GetUltimate().owner()};
+               owner.IsModule() || owner.IsSubmodule()) {
+      const Scope *module{FindModuleContaining(owner)};
+      ownerType = "MODULE";
+      ownerName = module->GetName()->ToString();
+      if (actualFirstSymbol->attrs().test(Attr::PARAMETER)) {
+        warn |= false;
+      } else if (actualFirstSymbol->Rank() != 1) {
+        warn |= true;
+      } else if (!actualFirstSymbol->attrs().test(Attr::ALLOCATABLE) &&
+                 !actualFirstSymbol->attrs().test(Attr::POINTER) &&
+                 !actualFirstSymbol->attrs().test(Attr::VOLATILE)) {
+        bool actualIsArrayElement{IsArrayElement(actual) != nullptr};
+        if (!actualIsArrayElement) {
+          warn |= true;
+        }
+        if (const ArraySpec *dims{actualFirstSymbol->GetShape()};
+            dims && dims->IsExplicitShape()) {
+          if (!((*dims)[0].lbound().GetExplicit() == (*dims)[0].ubound().GetExplicit())) {
+            warn |= true;
+          }
+        }
+      }
+    }
+    if (warn) {
+      context.Warn(common::UsageWarning::PassGlobalVariable, messages.at(),
+        "Passing global variable '%s' from %s '%s' as function argument"_warn_en_US,
+        actualFirstSymbol->name(), ownerType, ownerName);
+    }
+  }
 }
 
 static void CheckProcedureArg(evaluate::ActualArgument &arg,

>From 947180e64283f43ae24d6593b6fb3cc281f2c9d5 Mon Sep 17 00:00:00 2001
From: "Igor S. Gerasimov" <foxtranigor at gmail.com>
Date: Tue, 23 Sep 2025 16:45:56 +0200
Subject: [PATCH 4/5] Implementation of -Wpass-global-variable for implicit
 interfaces

---
 flang/lib/Semantics/check-call.cpp | 91 +++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 3 deletions(-)

diff --git a/flang/lib/Semantics/check-call.cpp b/flang/lib/Semantics/check-call.cpp
index e259db4f23a18..1b8f914fc1e85 100644
--- a/flang/lib/Semantics/check-call.cpp
+++ b/flang/lib/Semantics/check-call.cpp
@@ -56,9 +56,64 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
         "%VAL argument must be a scalar numeric or logical expression"_err_en_US);
   }
   if (const auto *expr{arg.UnwrapExpr()}) {
-    if (const Symbol * base{GetFirstSymbol(*expr)};
-        base && IsFunctionResult(*base)) {
-      context.NoteDefinedSymbol(*base);
+    if (const Symbol * base{GetFirstSymbol(*expr)}) {
+      if (IsFunctionResult(*base)) {
+        context.NoteDefinedSymbol(*base);
+      } else {
+        // passing global variables
+        // here, arrays with subscripts are processing
+        bool warn{false};
+        std::string ownerName{""};
+        std::string ownerType{""};
+        if (base->flags().test(Symbol::Flag::InCommonBlock)) {
+          const Symbol *common{FindCommonBlockContaining(*base)};
+          ownerType = "COMMON";
+          ownerName = common->name().ToString();
+          if (!(base->Rank() == 1 && base->offset() == 0)) {
+            warn |= true;
+          } else if (base->Rank() == 1) {
+            if (const ArraySpec *dims{base->GetShape()};
+                dims && dims->IsExplicitShape()) {
+              if (!((*dims)[0].lbound().GetExplicit() == (*dims)[0].ubound().GetExplicit())) {
+                warn |= true;
+              }
+            }
+            if (common->get<CommonBlockDetails>().objects().size() > 1) {
+              warn |= true;
+            }
+          }
+        } else if (const auto &owner{base->GetUltimate().owner()};
+                   owner.IsModule() || owner.IsSubmodule()) {
+          const Scope *module{FindModuleContaining(owner)};
+          ownerType = "MODULE";
+          ownerName = module->GetName()->ToString();
+          if (base->attrs().test(Attr::PARAMETER)) {
+            warn |= false;
+          } else if (base->Rank() != 1) {
+            warn |= true;
+          } else if (!base->attrs().test(Attr::ALLOCATABLE) &&
+                     !base->attrs().test(Attr::POINTER) &&
+                     !base->attrs().test(Attr::VOLATILE)) {
+            // by some reason, dims is not constructed here. For common blocks' variables, it works
+            // it leads to three skipped tests
+            /*
+            if (const ArraySpec *dims{base->GetShape()};
+                dims && dims->IsExplicitShape()) {
+              if (!((*dims)[0].lbound().GetExplicit() == (*dims)[0].ubound().GetExplicit())) {
+                  warn |= true;
+              }
+            }
+            */
+            // just give some warnings in code where modules and implicit interfaces are mixed
+            warn |= true;
+          }
+        }
+        if (warn) {
+          context.Warn(common::UsageWarning::PassGlobalVariable, messages.at(),
+            "Passing global variable '%s' from %s '%s' as function argument"_warn_en_US,
+            base->name(), ownerType, ownerName);
+        }
+      }
     }
     if (IsBOZLiteral(*expr)) {
       messages.Say("BOZ argument requires an explicit interface"_err_en_US);
@@ -79,6 +134,36 @@ static void CheckImplicitInterfaceArg(evaluate::ActualArgument &arg,
         messages.Say(
             "VOLATILE argument requires an explicit interface"_err_en_US);
       }
+      // passing global variables
+      // here, scalars and arrays without subscripts are processing
+      bool warn{false};
+      std::string ownerName{""};
+      std::string ownerType{""};
+      if (symbol.flags().test(Symbol::Flag::InCommonBlock)) {
+        const Symbol *common{FindCommonBlockContaining(symbol)};
+        ownerType = "COMMON";
+        ownerName = common->name().ToString();
+        warn |= true;
+      } else if (const auto& owner{symbol.GetUltimate().owner()};
+                 owner.IsModule() || owner.IsSubmodule()) {
+        const Scope *module{FindModuleContaining(owner)};
+        ownerType = "MODULE";
+        ownerName = module->GetName()->ToString();
+        if (symbol.attrs().test(Attr::PARAMETER)) {
+          warn |= false;
+        } else if (symbol.Rank() != 1) {
+          warn |= true;
+        } else if (!symbol.attrs().test(Attr::ALLOCATABLE) &&
+                   !symbol.attrs().test(Attr::POINTER) &&
+                   !symbol.attrs().test(Attr::VOLATILE)) {
+          warn |= true;
+        }
+      }
+      if (warn) {
+        context.Warn(common::UsageWarning::PassGlobalVariable, messages.at(),
+          "Passing global variable '%s' from %s '%s' as function argument"_warn_en_US,
+          symbol.name(), ownerType, ownerName);
+      }
     } else if (auto argChars{characteristics::DummyArgument::FromActual(
                    "actual argument", *expr, context.foldingContext(),
                    /*forImplicitInterface=*/true)}) {

>From d056747ca323520f6e94981c2a9e6e6258cf7e48 Mon Sep 17 00:00:00 2001
From: "Igor S. Gerasimov" <foxtranigor at gmail.com>
Date: Tue, 23 Sep 2025 16:52:55 +0200
Subject: [PATCH 5/5] Because of something unclear, give a bit more warnings

---
 flang/test/Semantics/pass-global-variables.f90 | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/flang/test/Semantics/pass-global-variables.f90 b/flang/test/Semantics/pass-global-variables.f90
index 73d1b8e334180..36d5324a14a65 100644
--- a/flang/test/Semantics/pass-global-variables.f90
+++ b/flang/test/Semantics/pass-global-variables.f90
@@ -97,7 +97,9 @@ subroutine module_test(n)
 
   !WARNING: Passing global variable 'i1' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int(i1)              !< warn:    i1 from common
+  !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int(i2(1))           !< ok:      single element/begin of mem block
+  !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int(i2(n))           !< ok:      single element/begin of mem block
   !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int(i3(1))           !< warn:    shape /= [1]
@@ -108,6 +110,7 @@ subroutine module_test(n)
 
   !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int_1d(i2)           !< warn:    i2 from module
+  !WARNING: Passing global variable 'i2' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int_1d(i2(n:n+3))    !< ok:      mem block
   !WARNING: Passing global variable 'i3' from MODULE 'explicit_test_mod' as function argument [-Wpass-global-variable]
   call imp_pass_int_1d(i3)           !< warn:    i3 from module & shape /= [1]



More information about the flang-commits mailing list