[flang-commits] [flang] [flang] Ignore -fno-realloc-lhs for polymorphic allocatable LHS with warning (PR #192697)
Eugene Epshteyn via flang-commits
flang-commits at lists.llvm.org
Sun Apr 19 19:52:44 PDT 2026
https://github.com/eugeneepshteyn updated https://github.com/llvm/llvm-project/pull/192697
>From dad003517f01faf824eff2915d2951f755e29cb8 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Fri, 17 Apr 2026 12:48:58 -0400
Subject: [PATCH 1/4] [flang] Ignore -fno-realloc-lhs for polymorphic
allocatable LHS with warning
When -fno-realloc-lhs is specified and the LHS of an assignment is a
polymorphic allocatable (class(*) or class(T)), reallocation semantics
are required by the Fortran 2003 standard for dynamic type tracking and
cannot be safely skipped. Previously, the compiler generated invalid
FIR in such cases (type mismatch between i32 and
!fir.class<!fir.heap<none>>), causing a compilation error.
With this change, when -fno-realloc-lhs is in effect and a polymorphic
allocatable LHS is detected, the compiler emits a warning that the
option is being ignored for that assignment and proceeds with
reallocation semantics.
---
flang/lib/Lower/Bridge.cpp | 24 +++++++++++++++++++-----
flang/test/Lower/reallocate-lhs.f90 | 20 ++++++++++++++++++--
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 28c82a6ca99ce..2153c07e03020 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5592,15 +5592,29 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// Gather some information about the assignment that will impact how it is
// lowered.
- const bool isWholeAllocatableAssignment =
+ const bool lhsIsWholeAllocatable =
!userDefinedAssignment && !isInsideHlfirWhere() &&
- Fortran::lower::isWholeAllocatable(assign.lhs) &&
- bridge.getLoweringOptions().getReallocateLHS();
+ Fortran::lower::isWholeAllocatable(assign.lhs);
+ std::optional<Fortran::evaluate::DynamicType> lhsType =
+ assign.lhs.GetType();
+ // Polymorphic allocatable LHS always requires reallocation semantics
+ // regardless of -fno-realloc-lhs: assignment to a polymorphic variable
+ // is a F2003+ feature that requires dynamic type tracking, which cannot
+ // be safely skipped. When -fno-realloc-lhs is specified but the LHS is
+ // polymorphic, emit a warning and proceed with reallocation semantics.
+ const bool lhsIsPolymorphic =
+ lhsType.has_value() && lhsType->IsPolymorphic();
+ if (lhsIsWholeAllocatable && lhsIsPolymorphic &&
+ !bridge.getLoweringOptions().getReallocateLHS())
+ mlir::emitWarning(loc,
+ "-fno-realloc-lhs is ignored for assignment to "
+ "polymorphic allocatable");
+ const bool isWholeAllocatableAssignment =
+ lhsIsWholeAllocatable &&
+ (bridge.getLoweringOptions().getReallocateLHS() || lhsIsPolymorphic);
const bool isUserDefAssignToPointerOrAllocatable =
userDefinedAssignment &&
firstDummyIsPointerOrAllocatable(*userDefinedAssignment);
- std::optional<Fortran::evaluate::DynamicType> lhsType =
- assign.lhs.GetType();
const bool keepLhsLengthInAllocatableAssignment =
isWholeAllocatableAssignment && lhsType.has_value() &&
lhsType->category() == Fortran::common::TypeCategory::Character &&
diff --git a/flang/test/Lower/reallocate-lhs.f90 b/flang/test/Lower/reallocate-lhs.f90
index 82a4edab787c7..7b65d6b6a9741 100644
--- a/flang/test/Lower/reallocate-lhs.f90
+++ b/flang/test/Lower/reallocate-lhs.f90
@@ -1,9 +1,13 @@
! RUN: bbc %s -o - -emit-hlfir | FileCheck %s --check-prefixes=ALL,REALLOCLHS
! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs | FileCheck %s --check-prefixes=ALL,REALLOCLHS
-! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs=false | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS
+! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs=false 2>&1 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS,POLYWARNING
! RUN: %flang_fc1 %s -o - -emit-hlfir | FileCheck %s --check-prefixes=ALL,REALLOCLHS
! RUN: %flang_fc1 %s -o - -emit-hlfir -frealloc-lhs | FileCheck %s --check-prefixes=ALL,REALLOCLHS
-! RUN: %flang_fc1 %s -o - -emit-hlfir -fno-realloc-lhs | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS
+! RUN: %flang_fc1 %s -o - -emit-hlfir -fno-realloc-lhs 2>&1 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS,POLYWARNING
+
+! -fno-realloc-lhs must be ignored for polymorphic allocatable LHS (test3 below).
+! The warning below is emitted before the MLIR output, so it must be checked first.
+! POLYWARNING: warning: {{.*}}-fno-realloc-lhs is ignored for assignment to polymorphic allocatable left-hand side
subroutine test1(a, b)
integer, allocatable :: a(:), b(:)
@@ -30,3 +34,15 @@ end subroutine test2
! NOREALLOCLHS: %[[VAL_7:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>>
! NOREALLOCLHS: hlfir.assign %{{.*}} to %[[VAL_7]] : !fir.box<!fir.array<?x!fir.char<1,?>>>, !fir.box<!fir.heap<!fir.array<?x!fir.char<1,?>>>>
+! Polymorphic allocatable LHS: reallocation semantics must be used regardless of
+! -fno-realloc-lhs, because the Fortran standard requires dynamic type tracking
+! for polymorphic assignments (a F2003+ feature that cannot be safely skipped).
+subroutine test3(x)
+ class(*), allocatable :: x
+ x = 1
+end subroutine test3
+
+! ALL-LABEL: func.func @_QPtest3(
+! ALL: %[[VAL_1:.*]]:2 = hlfir.declare{{.*}}{fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFtest3Ex"}
+! ALL: hlfir.assign %{{.*}} to %[[VAL_1]]#0 realloc : i32, !fir.ref<!fir.class<!fir.heap<none>>>
+
>From 932d0c05c4e25df83cb3d487184ea125562229e6 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Fri, 17 Apr 2026 12:59:28 -0400
Subject: [PATCH 2/4] I didn't change the message everywhere. Fixed
---
flang/test/Lower/reallocate-lhs.f90 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/test/Lower/reallocate-lhs.f90 b/flang/test/Lower/reallocate-lhs.f90
index 7b65d6b6a9741..cf01f304eda44 100644
--- a/flang/test/Lower/reallocate-lhs.f90
+++ b/flang/test/Lower/reallocate-lhs.f90
@@ -7,7 +7,7 @@
! -fno-realloc-lhs must be ignored for polymorphic allocatable LHS (test3 below).
! The warning below is emitted before the MLIR output, so it must be checked first.
-! POLYWARNING: warning: {{.*}}-fno-realloc-lhs is ignored for assignment to polymorphic allocatable left-hand side
+! POLYWARNING: warning: {{.*}}-fno-realloc-lhs is ignored for assignment to polymorphic allocatable
subroutine test1(a, b)
integer, allocatable :: a(:), b(:)
>From c03ccc46e8507877a8b2b2d7522634cdf1191639 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Fri, 17 Apr 2026 12:59:46 -0400
Subject: [PATCH 3/4] clang-format
---
flang/lib/Lower/Bridge.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 2153c07e03020..bbdd7ded1c84e 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5606,9 +5606,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
lhsType.has_value() && lhsType->IsPolymorphic();
if (lhsIsWholeAllocatable && lhsIsPolymorphic &&
!bridge.getLoweringOptions().getReallocateLHS())
- mlir::emitWarning(loc,
- "-fno-realloc-lhs is ignored for assignment to "
- "polymorphic allocatable");
+ mlir::emitWarning(loc, "-fno-realloc-lhs is ignored for assignment to "
+ "polymorphic allocatable");
const bool isWholeAllocatableAssignment =
lhsIsWholeAllocatable &&
(bridge.getLoweringOptions().getReallocateLHS() || lhsIsPolymorphic);
>From 92ce94ac506278a709b93f811481d5f0e60f4bf5 Mon Sep 17 00:00:00 2001
From: Eugene Epshteyn <eepshteyn at nvidia.com>
Date: Sun, 19 Apr 2026 22:52:17 -0400
Subject: [PATCH 4/4] Implemented language option for -fno-realloc-lhs, so that
could display better warning in semantics
---
.../include/flang/Support/Fortran-features.h | 3 ++-
flang/include/flang/Support/LangOptions.def | 4 +++
flang/lib/Frontend/CompilerInvocation.cpp | 4 ++-
flang/lib/Lower/Bridge.cpp | 7 +----
flang/lib/Semantics/expression.cpp | 3 +++
flang/lib/Support/Fortran-features.cpp | 1 +
flang/test/Lower/reallocate-lhs.f90 | 4 +--
flang/test/Semantics/no-realloc-lhs-poly.f90 | 26 +++++++++++++++++++
8 files changed, 41 insertions(+), 11 deletions(-)
create mode 100644 flang/test/Semantics/no-realloc-lhs-poly.f90
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index f2bd0d21f25b6..4f6cd02fd35ef 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -84,7 +84,8 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
HostAssociatedIntentOutInSpecExpr, NonVolatilePointerToVolatile,
RealConstantWidening, VolatileOrAsynchronousTemporary, UnusedVariable,
UsedUndefinedVariable, BadValueInDeadCode, AssumedTypeSizeDummy,
- MisplacedIgnoreTKR, NamelistParameter, ImpureFinalInPure)
+ MisplacedIgnoreTKR, NamelistParameter, ImpureFinalInPure,
+ IgnoredNoReallocateLHS)
using LanguageFeatures = EnumSet<LanguageFeature, LanguageFeature_enumSize>;
using UsageWarnings = EnumSet<UsageWarning, UsageWarning_enumSize>;
diff --git a/flang/include/flang/Support/LangOptions.def b/flang/include/flang/Support/LangOptions.def
index e310ecf37a52d..c2d6f80132cfe 100644
--- a/flang/include/flang/Support/LangOptions.def
+++ b/flang/include/flang/Support/LangOptions.def
@@ -60,6 +60,10 @@ LANGOPT(OpenMPNoThreadState, 1, 0)
LANGOPT(OpenMPNoNestedParallelism, 1, 0)
/// Use SIMD only OpenMP support.
LANGOPT(OpenMPSimd, 1, false)
+/// -fno-realloc-lhs: disable reallocation of allocatable LHS on assignment.
+/// When set, polymorphic allocatable LHS still requires reallocation (F2003+);
+/// a warning is emitted in that case.
+LANGOPT(NoReallocateLHS, 1, false)
/// Enable fast MOD operations for REAL
LANGOPT(FastRealMod, 1, false)
LANGOPT(VScaleMin, 32, 0) ///< Minimum vscale range value
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index fab1b792180c3..5a0710874dae4 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -1661,8 +1661,10 @@ bool CompilerInvocation::createFromArgs(
// -frealloc-lhs is the default.
if (!args.hasFlag(clang::options::OPT_frealloc_lhs,
- clang::options::OPT_fno_realloc_lhs, true))
+ clang::options::OPT_fno_realloc_lhs, true)) {
invoc.loweringOpts.setReallocateLHS(false);
+ invoc.getLangOpts().NoReallocateLHS = true;
+ }
invoc.loweringOpts.setRepackArrays(args.hasFlag(
clang::options::OPT_frepack_arrays, clang::options::OPT_fno_repack_arrays,
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 058b84addc87c..e39fc9d901adc 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5616,14 +5616,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// Polymorphic allocatable LHS always requires reallocation semantics
// regardless of -fno-realloc-lhs: assignment to a polymorphic variable
// is a F2003+ feature that requires dynamic type tracking, which cannot
- // be safely skipped. When -fno-realloc-lhs is specified but the LHS is
- // polymorphic, emit a warning and proceed with reallocation semantics.
+ // be safely skipped. A warning is emitted by the semantics phase.
const bool lhsIsPolymorphic =
lhsType.has_value() && lhsType->IsPolymorphic();
- if (lhsIsWholeAllocatable && lhsIsPolymorphic &&
- !bridge.getLoweringOptions().getReallocateLHS())
- mlir::emitWarning(loc, "-fno-realloc-lhs is ignored for assignment to "
- "polymorphic allocatable");
const bool isWholeAllocatableAssignment =
lhsIsWholeAllocatable &&
(bridge.getLoweringOptions().getReallocateLHS() || lhsIsPolymorphic);
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 756bfd551a90a..e95de7d063ab7 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3613,6 +3613,9 @@ const Assignment *ExpressionAnalyzer::Analyze(const parser::AssignmentStmt &x) {
Say("Left-hand side of intrinsic assignment may not be polymorphic unless assignment is to an entire allocatable"_err_en_US);
} else if (evaluate::IsCoarray(*lastWhole)) {
Say("Left-hand side of intrinsic assignment may not be polymorphic if it is a coarray"_err_en_US);
+ } else if (context_.langOptions().NoReallocateLHS) {
+ Warn(common::UsageWarning::IgnoredNoReallocateLHS,
+ "-fno-realloc-lhs is ignored for assignment to polymorphic allocatable"_warn_en_US);
}
}
if (auto *derived{GetDerivedTypeSpec(*dyType)}) {
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 4201f0b9b1e49..67cdb8d67c8af 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -162,6 +162,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnUsage_.set(UsageWarning::BadValueInDeadCode);
warnUsage_.set(UsageWarning::MisplacedIgnoreTKR);
warnUsage_.set(UsageWarning::ImpureFinalInPure);
+ warnUsage_.set(UsageWarning::IgnoredNoReallocateLHS);
warnLanguage_.set(LanguageFeature::OpenMPThreadprivateEquivalence);
}
diff --git a/flang/test/Lower/reallocate-lhs.f90 b/flang/test/Lower/reallocate-lhs.f90
index cf01f304eda44..d1b0f1cc1a43f 100644
--- a/flang/test/Lower/reallocate-lhs.f90
+++ b/flang/test/Lower/reallocate-lhs.f90
@@ -1,13 +1,11 @@
! RUN: bbc %s -o - -emit-hlfir | FileCheck %s --check-prefixes=ALL,REALLOCLHS
! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs | FileCheck %s --check-prefixes=ALL,REALLOCLHS
-! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs=false 2>&1 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS,POLYWARNING
+! RUN: bbc %s -o - -emit-hlfir -frealloc-lhs=false | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS
! RUN: %flang_fc1 %s -o - -emit-hlfir | FileCheck %s --check-prefixes=ALL,REALLOCLHS
! RUN: %flang_fc1 %s -o - -emit-hlfir -frealloc-lhs | FileCheck %s --check-prefixes=ALL,REALLOCLHS
! RUN: %flang_fc1 %s -o - -emit-hlfir -fno-realloc-lhs 2>&1 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS,POLYWARNING
! -fno-realloc-lhs must be ignored for polymorphic allocatable LHS (test3 below).
-! The warning below is emitted before the MLIR output, so it must be checked first.
-! POLYWARNING: warning: {{.*}}-fno-realloc-lhs is ignored for assignment to polymorphic allocatable
subroutine test1(a, b)
integer, allocatable :: a(:), b(:)
diff --git a/flang/test/Semantics/no-realloc-lhs-poly.f90 b/flang/test/Semantics/no-realloc-lhs-poly.f90
new file mode 100644
index 0000000000000..a9bbe4d62e30c
--- /dev/null
+++ b/flang/test/Semantics/no-realloc-lhs-poly.f90
@@ -0,0 +1,26 @@
+! RUN: %python %S/test_errors.py %s %flang_fc1 -fno-realloc-lhs -Werror
+
+! When -fno-realloc-lhs is specified, assignments to a polymorphic allocatable
+! LHS must still use reallocation semantics (F2003 requirement). A warning is
+! issued so the user knows the option is being ignored for this case.
+
+subroutine test_unlimited_poly(x)
+ class(*), allocatable :: x
+! WARNING: -fno-realloc-lhs is ignored for assignment to polymorphic allocatable [-Wignored-no-reallocate-lhs]
+ x = 1
+end subroutine
+
+subroutine test_class_poly(x)
+ type :: t
+ integer :: i
+ end type
+ class(t), allocatable :: x
+! WARNING: -fno-realloc-lhs is ignored for assignment to polymorphic allocatable [-Wignored-no-reallocate-lhs]
+ x = t(42)
+end subroutine
+
+! Non-polymorphic allocatable: no warning, option is honoured.
+subroutine test_non_poly(x)
+ integer, allocatable :: x
+ x = 1
+end subroutine
More information about the flang-commits
mailing list