[flang-commits] [flang] [flang][semantics] Diagnose numeric storage size on import (PR #220779)

Andre Kuhlenschmidt via flang-commits flang-commits at lists.llvm.org
Fri Sep 11 12:02:46 PDT 2026


https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/220779

>From 232772427b412dae86a5b43d03d2b01816a56efb Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Tue, 1 Sep 2026 11:26:14 -0700
Subject: [PATCH] [flang][semantics] Diagnose numeric storage size on import

---
 flang/lib/Evaluate/fold-integer.cpp           |  7 --
 flang/lib/Semantics/resolve-names.cpp         | 36 ++++++++
 flang/test/Semantics/numeric_storage_size.f90 |  6 +-
 .../Semantics/numeric_storage_size_only.f90   | 92 +++++++++++++++++++
 4 files changed, 132 insertions(+), 9 deletions(-)
 create mode 100644 flang/test/Semantics/numeric_storage_size_only.f90

diff --git a/flang/lib/Evaluate/fold-integer.cpp b/flang/lib/Evaluate/fold-integer.cpp
index c7db4069e3e28..48bef73cccbb8 100644
--- a/flang/lib/Evaluate/fold-integer.cpp
+++ b/flang/lib/Evaluate/fold-integer.cpp
@@ -1456,13 +1456,6 @@ Expr<Type<TypeCategory::Integer, KIND>> FoldIntrinsicFunction(
       auto realBytes{
           context.targetCharacteristics().GetByteSize(TypeCategory::Real,
               context.defaults().GetDefaultKind(TypeCategory::Real))};
-      if (intBytes != realBytes) {
-        // Using the low-level API to bypass the module file check in this case.
-        context.messages().Warn(
-            /*isInModuleFile=*/false, context.languageFeatures(),
-            common::UsageWarning::FoldingValueChecks, *context.moduleFileName(),
-            "NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined when default INTEGER and REAL are not consistent due to compiler options"_warn_en_US);
-      }
       return Expr<T>{8 * std::min(intBytes, realBytes)};
     }
   }
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 17abba65bdae5..ae7c1e2324cbd 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -1198,6 +1198,7 @@ class DeclarationVisitor : public ArraySpecVisitor,
   void CheckEquivalenceSets();
   bool CheckNotInBlock(const char *);
   bool NameIsKnownOrIntrinsic(const parser::Name &);
+  void WarnForNumericStorageSize(const parser::Name &, const Symbol &);
   void FinishNamelists();
 
   // Each of these returns a pointer to a resolved Name (i.e. with symbol)
@@ -9756,6 +9757,40 @@ const parser::Name *DeclarationVisitor::ResolveDataRef(
       x.u);
 }
 
+void DeclarationVisitor::WarnForNumericStorageSize(
+    const parser::Name &name, const Symbol &symbol) {
+  const Symbol *associated{&symbol};
+  while (const auto *host{associated->detailsIf<HostAssocDetails>()}) {
+    associated = &host->symbol();
+  }
+  const auto *use{associated->detailsIf<UseDetails>()};
+  const Symbol &ultimate{symbol.GetUltimate()};
+  const Scope &owner{ultimate.owner()};
+  if (ultimate.name() != "numeric_storage_size" || !owner.IsModule() ||
+      !owner.parent().IsIntrinsicModules() || !owner.GetName() ||
+      owner.GetName().value() != "iso_fortran_env") {
+    return;
+  }
+  const auto &defaults{context().defaultKinds()};
+  const auto &targetCharacteristics{context().targetCharacteristics()};
+  auto intKind{defaults.GetDefaultKind(TypeCategory::Integer)};
+  auto realKind{defaults.GetDefaultKind(TypeCategory::Real)};
+  auto intBytes{
+      targetCharacteristics.GetByteSize(TypeCategory::Integer, intKind)};
+  auto realBytes{
+      targetCharacteristics.GetByteSize(TypeCategory::Real, realKind)};
+  if (intBytes != realBytes) {
+    if (auto *message{context().Warn(common::UsageWarning::FoldingValueChecks,
+            name.source,
+            "NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined because compiler options make default INTEGER(KIND=%d) and REAL(KIND=%d) have different storage sizes (%d and %d bytes, respectively)"_warn_en_US,
+            intKind, realKind, intBytes, realBytes)}) {
+      if (use) {
+        message->Attach(use->location(), "USE-associated here"_en_US);
+      }
+    }
+  }
+}
+
 // If implicit types are allowed, ensure name is in the symbol table.
 // Otherwise, report an error if it hasn't been declared.
 const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
@@ -9768,6 +9803,7 @@ const parser::Name *DeclarationVisitor::ResolveName(const parser::Name &name) {
     if (CheckUseError(name)) {
       return nullptr; // reported an error
     }
+    WarnForNumericStorageSize(name, *symbol);
     NotePossibleBadForwardRef(name);
     symbol->set(Symbol::Flag::ImplicitOrError, false);
     if (IsUplevelReference(*symbol)) {
diff --git a/flang/test/Semantics/numeric_storage_size.f90 b/flang/test/Semantics/numeric_storage_size.f90
index ee11f3b15d5bf..ec6bdc70b116f 100644
--- a/flang/test/Semantics/numeric_storage_size.f90
+++ b/flang/test/Semantics/numeric_storage_size.f90
@@ -13,9 +13,11 @@
 !CHECK-I4: nss = 32_4
 !CHECK-R4: nss = 32_4
 !CHECK-I4-R4: nss = 32_4
-!CHECK-I8: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined when default INTEGER and REAL are not consistent due to compiler options
+!CHECK-I8: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined because compiler options make default INTEGER(KIND=8) and REAL(KIND=4) have different storage sizes (8 and 4 bytes, respectively)
+!CHECK-I8: USE-associated here
 !CHECK-I8: nss = 32_4
-!CHECK-R8: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined when default INTEGER and REAL are not consistent due to compiler options
+!CHECK-R8: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined because compiler options make default INTEGER(KIND=4) and REAL(KIND=8) have different storage sizes (4 and 8 bytes, respectively)
+!CHECK-R8: USE-associated here
 !CHECK-R8: nss = 32_4
 !CHECK-I8-R8: nss = 64_4
 integer, parameter :: nss = numeric_storage_size
diff --git a/flang/test/Semantics/numeric_storage_size_only.f90 b/flang/test/Semantics/numeric_storage_size_only.f90
new file mode 100644
index 0000000000000..e602995b66c89
--- /dev/null
+++ b/flang/test/Semantics/numeric_storage_size_only.f90
@@ -0,0 +1,92 @@
+! RUN: split-file %s %t
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/only-input %t/only-input/test.f90 2>&1 | FileCheck --allow-empty --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-real-8 -module-dir %t/only-input %t/only-input/test.f90 2>&1 | FileCheck --allow-empty --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/unused %t/unused/test.f90 2>&1 | FileCheck --allow-empty --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/direct %t/direct/test.f90 2>&1 | FileCheck --check-prefix=TWO --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/repeated %t/repeated/test.f90 2>&1 | FileCheck --check-prefix=TWO --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/renamed-twice %t/renamed-twice/test.f90 2>&1 | FileCheck --check-prefix=TWO --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/homonym %t/homonym/test.f90 2>&1 | FileCheck --allow-empty --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: not %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/rejected %t/rejected/test.f90 2>&1 | FileCheck --check-prefix=REJECTED --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+! RUN: %flang_fc1 -fsyntax-only -fdefault-integer-8 -module-dir %t/reexport %t/reexport/test.f90 2>&1 | FileCheck --check-prefix=ONE --implicit-check-not=NUMERIC_STORAGE_SIZE %s
+
+! ONE: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined because compiler options make default INTEGER(KIND=8) and REAL(KIND=4) have different storage sizes (8 and 4 bytes, respectively) [-Wfolding-value-checks]
+! ONE: USE-associated here
+! TWO-COUNT-2: warning: NUMERIC_STORAGE_SIZE from ISO_FORTRAN_ENV is not well-defined because compiler options make default INTEGER(KIND=8) and REAL(KIND=4) have different storage sizes (8 and 4 bytes, respectively) [-Wfolding-value-checks]
+! REJECTED: error: Reference to 'numeric_storage_size' is ambiguous
+
+!--- only-input/test.f90
+subroutine only_input_unit
+  use, intrinsic :: iso_fortran_env, only: renamed_input_unit => input_unit
+  implicit none
+  integer :: i
+  i = renamed_input_unit
+end subroutine only_input_unit
+
+!--- unused/test.f90
+subroutine unused_numeric_storage_size
+  use, intrinsic :: iso_fortran_env
+  implicit none
+  integer :: i
+  i = input_unit
+end subroutine unused_numeric_storage_size
+
+!--- direct/test.f90
+subroutine only_numeric_storage_size
+  use, intrinsic :: iso_fortran_env, only: numeric_storage_size
+  implicit none
+  integer, parameter :: nss = numeric_storage_size
+end subroutine only_numeric_storage_size
+
+subroutine renamed_numeric_storage_size
+  use, intrinsic :: iso_fortran_env, only: local_nss => numeric_storage_size
+  implicit none
+  integer, parameter :: nss = local_nss
+end subroutine renamed_numeric_storage_size
+
+!--- repeated/test.f90
+subroutine repeated_same_import
+  use, intrinsic :: iso_fortran_env, only: numeric_storage_size
+  use, intrinsic :: iso_fortran_env, only: numeric_storage_size
+  integer, parameter :: nss = numeric_storage_size + numeric_storage_size
+end subroutine repeated_same_import
+
+!--- renamed-twice/test.f90
+subroutine repeated_renamed_import
+  use, intrinsic :: iso_fortran_env, only: first_nss => numeric_storage_size
+  use, intrinsic :: iso_fortran_env, only: second_nss => numeric_storage_size
+  integer, parameter :: nss = first_nss + second_nss
+end subroutine repeated_renamed_import
+
+!--- homonym/test.f90
+module iso_fortran_env
+  integer, parameter :: numeric_storage_size = 123
+end module iso_fortran_env
+
+subroutine non_intrinsic_homonym
+  use, non_intrinsic :: iso_fortran_env, only: numeric_storage_size
+  implicit none
+  integer, parameter :: nss = numeric_storage_size
+end subroutine non_intrinsic_homonym
+
+!--- rejected/test.f90
+module conflicting_nss
+  integer, parameter :: numeric_storage_size = 456
+end module conflicting_nss
+
+subroutine rejected_intrinsic_import
+  use conflicting_nss, only: numeric_storage_size
+  use, intrinsic :: iso_fortran_env, only: numeric_storage_size
+  ! The ambiguous name is not successfully associated with the intrinsic
+  ! constant, so referencing it diagnoses only the import error.
+  integer, parameter :: nss = numeric_storage_size
+end subroutine rejected_intrinsic_import
+
+!--- reexport/test.f90
+module reexported_nss
+  use, intrinsic :: iso_fortran_env, only: numeric_storage_size
+end module reexported_nss
+
+subroutine import_from_reexport
+  use reexported_nss, only: numeric_storage_size
+  integer, parameter :: nss = numeric_storage_size
+end subroutine import_from_reexport



More information about the flang-commits mailing list