[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