[flang-commits] [flang] 49dad16 - [flang] Ignore -fno-realloc-lhs for polymorphic allocatable LHS with warning (#192697)
via flang-commits
flang-commits at lists.llvm.org
Thu Apr 23 06:34:16 PDT 2026
Author: Eugene Epshteyn
Date: 2026-04-23T09:34:11-04:00
New Revision: 49dad1672430134e44e7831012cbeb06bebf32b7
URL: https://github.com/llvm/llvm-project/commit/49dad1672430134e44e7831012cbeb06bebf32b7
DIFF: https://github.com/llvm/llvm-project/commit/49dad1672430134e44e7831012cbeb06bebf32b7.diff
LOG: [flang] Ignore -fno-realloc-lhs for polymorphic allocatable LHS with warning (#192697)
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.
Added:
flang/test/Semantics/no-realloc-lhs-poly.f90
Modified:
flang/include/flang/Support/Fortran-features.h
flang/include/flang/Support/LangOptions.def
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Lower/Bridge.cpp
flang/lib/Semantics/expression.cpp
flang/lib/Support/Fortran-features.cpp
flang/test/Lower/reallocate-lhs.f90
Removed:
################################################################################
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 23bcc077f865b..9a995021c9351 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -5650,15 +5650,23 @@ 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. A warning is emitted by the semantics phase.
+ const bool lhsIsPolymorphic =
+ lhsType.has_value() && lhsType->IsPolymorphic();
+ 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/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 8b64fca2666e6..80d0c595ce284 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -3634,6 +3634,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 82a4edab787c7..64e2d311e0ebe 100644
--- a/flang/test/Lower/reallocate-lhs.f90
+++ b/flang/test/Lower/reallocate-lhs.f90
@@ -3,7 +3,9 @@
! 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 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS
+! RUN: %flang_fc1 %s -o - -emit-hlfir -fno-realloc-lhs 2>&1 | FileCheck %s --check-prefixes=ALL,NOREALLOCLHS
+
+! -fno-realloc-lhs must be ignored for polymorphic allocatable LHS (test3 below).
subroutine test1(a, b)
integer, allocatable :: a(:), b(:)
@@ -30,3 +32,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>>>
+
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