[flang-commits] [clang] [flang] [flang] Warn rather than error on out-of-range constant subscripts (PR #220435)

Ron Green [NVIDIA] via flang-commits flang-commits at lists.llvm.org
Thu Sep 3 14:58:39 PDT 2026


https://github.com/ronGreenNV updated https://github.com/llvm/llvm-project/pull/220435

>From b4aebc9e832212fd5900634c0faeff0956711233 Mon Sep 17 00:00:00 2001
From: Ronald Green <rogreen at nvidia.com>
Date: Tue, 1 Sep 2026 16:42:15 -0700
Subject: [PATCH 1/4] [flang] Add -fout-of-bounds-subscripts to accept
 out-of-range subscripts

A subscript value is required to be within its bounds only when the
reference is executed (F'2023 9.5.3.1 paragraph 2), so a reference with
an out-of-range constant subscript that never runs does not render a
program nonconforming.  Semantics already recognizes the narrow case of
a reference inside a statically false IF construct and emits a warning
there instead of an error, but the general case cannot be recognized --
consider a procedure whose only call site is in dead code, or one that
is never called at all.

References like these occur in applications that select between
configurations with a named constant, where only the branch matching the
configuration is ever executed.  Keep the error as the default, but add
-fout-of-bounds-subscripts to accept such subscripts with a warning
instead; that warning can be silenced with -Wno-out-of-bounds-subscripts.

The new language feature is off by default, so no existing behavior
changes.

Addresses #82684
---
 clang/include/clang/Options/FlangOptions.td   |  2 ++
 clang/lib/Driver/ToolChains/Flang.cpp         | 20 +++++++++----
 flang/docs/Extensions.md                      |  9 ++++++
 .../include/flang/Support/Fortran-features.h  |  2 +-
 flang/lib/Frontend/CompilerInvocation.cpp     |  6 ++++
 flang/lib/Semantics/expression.cpp            | 27 +++++++++++++----
 flang/lib/Support/Fortran-features.cpp        |  4 +++
 flang/test/Semantics/bug82684.f90             | 30 +++++++++++++++++++
 8 files changed, 88 insertions(+), 12 deletions(-)
 create mode 100644 flang/test/Semantics/bug82684.f90

diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index 7a3dfd84fd4e7..a966bf152c3e0 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -189,6 +189,8 @@ defm ppc_native_vec_elem_order: BoolOptionWithoutMarshalling<"f", "ppc-native-ve
   PosFlag<SetTrue, [], [ClangOption], "Specifies PowerPC native vector element order (default)">,
   NegFlag<SetFalse, [], [ClangOption], "Specifies PowerPC non-native vector element order">>;
 defm unsigned : OptInFC1FFlag<"unsigned", "Enables UNSIGNED type">;
+defm out_of_bounds_subscripts : OptInFC1FFlag<"out-of-bounds-subscripts",
+  "Warn instead of erroring when a constant subscript is out of bounds (extension)">;
 defm enumeration_type : OptInFC1FFlag<"enumeration-type", "Enables F2023 ENUMERATION TYPE (experimental; FIR lowering is incomplete)">;
 defm openacc_default_none_scalars_strict : OptOutFC1FFlag<"openacc-default-none-scalars-strict",
   "Require explicit data clauses for all variables (including scalars) under OpenACC DEFAULT(NONE)",
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 7562206f93438..0e6858d3bb645 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -226,14 +226,22 @@ void Flang::addDebugOptions(const llvm::opt::ArgList &Args, const JobAction &JA,
   const auto &TC = getToolChain();
   const Driver &D = TC.getDriver();
   Args.addAllArgs(CmdArgs,
-                  {options::OPT_module_dir, options::OPT_fdebug_module_writer,
-                   options::OPT_fintrinsic_modules_path, options::OPT_pedantic,
-                   options::OPT_std_EQ, options::OPT_W_Joined,
-                   options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ,
-                   options::OPT_funderscoring, options::OPT_fno_underscoring,
-                   options::OPT_funsigned, options::OPT_fno_unsigned,
+                  {options::OPT_module_dir,
+                   options::OPT_fdebug_module_writer,
+                   options::OPT_fintrinsic_modules_path,
+                   options::OPT_pedantic,
+                   options::OPT_std_EQ,
+                   options::OPT_W_Joined,
+                   options::OPT_fconvert_EQ,
+                   options::OPT_fpass_plugin_EQ,
+                   options::OPT_funderscoring,
+                   options::OPT_fno_underscoring,
+                   options::OPT_funsigned,
+                   options::OPT_fno_unsigned,
                    options::OPT_fenumeration_type,
                    options::OPT_fno_enumeration_type,
+                   options::OPT_fout_of_bounds_subscripts,
+                   options::OPT_fno_out_of_bounds_subscripts,
                    options::OPT_fopenacc_default_none_scalars_strict,
                    options::OPT_fno_openacc_default_none_scalars_strict,
                    options::OPT_fopenacc_multiple_names_in_routine,
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index 2a0afbb0cd3c0..c57d0863eeef8 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -1081,6 +1081,15 @@ print *, [(j,j=1,10)]
   are noted only as warnings when they appear in code known to be
   dead anyway at compilation time.
 
+* A subscript value is required to be within its bounds only when the
+  reference is actually executed, so a reference with an out-of-range
+  constant subscript that never runs does not make a program
+  nonconforming.  That case cannot be recognized in general -- consider a
+  procedure whose only call is in dead code, or one that is never called
+  at all -- so these subscripts are errors by default.  Use
+  `-fout-of-bounds-subscripts` to accept them with a warning instead;
+  the warning can then be silenced with `-Wno-out-of-bounds-subscripts`.
+
 ## Behavior in cases where the standard is clear but disputed
 
 * Unless one uses `-ffast-math`, directly or by implication,
diff --git a/flang/include/flang/Support/Fortran-features.h b/flang/include/flang/Support/Fortran-features.h
index 943c3e0ac6bed..4b2ff0a227f61 100644
--- a/flang/include/flang/Support/Fortran-features.h
+++ b/flang/include/flang/Support/Fortran-features.h
@@ -62,7 +62,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     OpenMPThreadprivateEquivalence, RelaxedCLocChecks, CudaPinned,
     OpenAccDefaultNoneScalarsStrict, OpenACCMultipleNamesInRoutine,
     EnumerationType, CUDAInit, PreferIntrinsicModuleUseAssociation,
-    MultipleCommonBlockInit)
+    MultipleCommonBlockInit, OutOfBoundsSubscripts)
 
 // Portability and suspicious usage warnings
 ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index ff4c7f6a18624..1ba3c2b312d3c 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -919,6 +919,12 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
                        args.hasFlag(clang::options::OPT_funsigned,
                                     clang::options::OPT_fno_unsigned, false));
 
+  // -f{no-}out-of-bounds-subscripts
+  opts.features.Enable(
+      Fortran::common::LanguageFeature::OutOfBoundsSubscripts,
+      args.hasFlag(clang::options::OPT_fout_of_bounds_subscripts,
+                   clang::options::OPT_fno_out_of_bounds_subscripts, false));
+
   // -f{no-}enumeration-type (experimental; FIR lowering is incomplete)
   opts.features.Enable(Fortran::common::LanguageFeature::EnumerationType,
                        args.hasFlag(clang::options::OPT_fenumeration_type,
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 48196c6686aee..03832d84d70d1 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -343,7 +343,7 @@ static bool FoldSubscripts(semantics::SemanticsContext &context,
   return !anyPossiblyEmptyDim;
 }
 
-static void ValidateSubscriptValue(parser::ContextualMessages &messages,
+static void ValidateSubscriptValue(semantics::SemanticsContext &context,
     const Symbol &symbol, ConstantSubscript val,
     std::optional<ConstantSubscript> lb, std::optional<ConstantSubscript> ub,
     int dim, const char *co = "") {
@@ -363,7 +363,24 @@ static void ValidateSubscriptValue(parser::ContextualMessages &messages,
       msg->set_severity(parser::Severity::Warning);
     }
   }
-  if (msg) {
+  if (!msg) {
+    return;
+  }
+  parser::ContextualMessages &messages{context.foldingContext().messages()};
+  if (msg->severity() == parser::Severity::ErrorUnlessDeadCode &&
+      context.IsEnabled(common::LanguageFeature::OutOfBoundsSubscripts)) {
+    // A subscript value is required to be within its bounds only when the
+    // reference is executed (F'2023 9.5.3.1 p2), so a reference that appears
+    // in code that never runs does not render the program nonconforming.
+    // That case can't be recognized in general, so this extension accepts
+    // any out-of-bounds constant subscript with a warning.
+    msg->set_severity(parser::Severity::Warning);
+    AttachDeclaration(
+        context.Warn(messages, common::LanguageFeature::OutOfBoundsSubscripts,
+            std::move(*msg), co, static_cast<std::intmax_t>(val), co,
+            static_cast<std::intmax_t>(bound.value()), co, dim + 1),
+        symbol);
+  } else {
     AttachDeclaration(
         messages.Say(std::move(*msg), co, static_cast<std::intmax_t>(val), co,
             static_cast<std::intmax_t>(bound.value()), co, dim + 1),
@@ -416,8 +433,8 @@ static void ValidateSubscripts(semantics::SemanticsContext &context,
     }
     for (int j{0}; j < vals; ++j) {
       if (val[j]) {
-        ValidateSubscriptValue(context.foldingContext().messages(), arraySymbol,
-            *val[j], dimLB, dimUB, dim);
+        ValidateSubscriptValue(
+            context, arraySymbol, *val[j], dimLB, dimUB, dim);
       }
     }
     ++dim;
@@ -441,7 +458,7 @@ static void CheckCosubscripts(
   for (auto &expr : ref.cosubscript()) {
     expr = Fold(foldingContext, std::move(expr));
     if (auto val{ToInt64(expr)}) {
-      ValidateSubscriptValue(foldingContext.messages(), coarraySymbol, *val,
+      ValidateSubscriptValue(context, coarraySymbol, *val,
           ToInt64(GetLCOBOUND(coarraySymbol, dim)),
           ToInt64(GetUCOBOUND(coarraySymbol, dim)), dim, "co");
     }
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 28faddfc65c66..309ada5813ed7 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -156,6 +156,9 @@ LanguageFeatureControl::LanguageFeatureControl() {
   disable_.set(LanguageFeature::AssumedRankPassedToNonAssumedRank);
   disable_.set(LanguageFeature::Coarray);
   disable_.set(LanguageFeature::OpenAccDefaultNoneScalarsStrict);
+  // An out-of-bounds constant subscript is a hard error by default; enabling
+  // this extension reduces it to a warning.
+  disable_.set(LanguageFeature::OutOfBoundsSubscripts);
   // These warnings are enabled by default, but only because they used
   // to be unconditional.  TODO: prune this list
   warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);
@@ -228,6 +231,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
   warnLanguage_.set(LanguageFeature::OpenAccDefaultNoneScalarsStrict);
   warnLanguage_.set(LanguageFeature::OpenACCMultipleNamesInRoutine);
   warnLanguage_.set(LanguageFeature::MultipleCommonBlockInit);
+  warnLanguage_.set(LanguageFeature::OutOfBoundsSubscripts);
 }
 
 std::optional<LanguageControlFlag> LanguageFeatureControl::FindWarning(
diff --git a/flang/test/Semantics/bug82684.f90 b/flang/test/Semantics/bug82684.f90
new file mode 100644
index 0000000000000..8732959fa10f2
--- /dev/null
+++ b/flang/test/Semantics/bug82684.f90
@@ -0,0 +1,30 @@
+! Out-of-bounds constant subscripts are errors by default, but
+! -fout-of-bounds-subscripts reduces them to warnings, since such a
+! reference is nonconforming only if it is actually executed.
+! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+! RUN: %flang_fc1 -fsyntax-only -fout-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
+! RUN: %flang_fc1 -fsyntax-only -fout-of-bounds-subscripts -Wno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-SILENT --allow-empty %s
+
+module m
+  integer, parameter :: n_dims = 2
+  type :: grid_type
+    real :: cells(1000, n_dims)
+  end type
+ contains
+  ! This subprogram is never called, so it never renders the program
+  ! nonconforming, but that can't be proven here.
+  subroutine init_3Dgrid(node)
+    type(grid_type), intent(inout) :: node
+    !CHECK-ERROR: error: subscript 3 is greater than upper bound 2 for dimension 2 of array
+    !CHECK-WARNING: warning: subscript 3 is greater than upper bound 2 for dimension 2 of array [-Wout-of-bounds-subscripts]
+    !CHECK-SILENT-NOT: subscript 3
+    node%cells(:,3) = 3.0
+  end subroutine
+  subroutine lower(node)
+    type(grid_type), intent(inout) :: node
+    !CHECK-ERROR: error: subscript 0 is less than lower bound 1 for dimension 2 of array
+    !CHECK-WARNING: warning: subscript 0 is less than lower bound 1 for dimension 2 of array [-Wout-of-bounds-subscripts]
+    !CHECK-SILENT-NOT: subscript 0
+    node%cells(:,0) = 0.0
+  end subroutine
+end module

>From 3664863bc99e32668fc56812edffa90436bdbefd Mon Sep 17 00:00:00 2001
From: Ronald Green <rogreen at nvidia.com>
Date: Wed, 2 Sep 2026 13:23:22 -0700
Subject: [PATCH 2/4] [flang] Warn rather than error on out-of-range constant
 subscripts

Change the default so that a reference with an out-of-range constant
subscript is accepted with a warning instead of being rejected, and add
-fno-out-of-bounds-subscripts to restore the error.  A subscript value is
required to be within its bounds only when the reference is executed
(F'2023 9.5.3.1 paragraph 2), and whether a reference is ever executed
cannot be determined in general, so rejecting these outright turns away
conforming programs.

The endpoints of array sections get the same treatment.  Cosubscripts do
not: their requirement is F'2023 9.6 paragraph 2 rather than 9.5.3.1
paragraph 2, and a cosubscript list determines an image index, so an
out-of-cobounds constant cosubscript remains an error.

expr-errors06.f90 and bug171844.f90 now pass -fno-out-of-bounds-subscripts
so that they keep testing the error path and the downgrade of errors to
warnings in code known to be dead.

Addresses #82684
---
 clang/include/clang/Options/FlangOptions.td   |  5 +--
 flang/docs/Extensions.md                      | 24 +++++++++-----
 flang/docs/ReleaseNotes.md                    | 13 ++++++++
 flang/lib/Frontend/CompilerInvocation.cpp     |  2 +-
 flang/lib/Semantics/expression.cpp            | 14 ++++++--
 flang/lib/Support/Fortran-features.cpp        |  3 --
 .../test/Driver/fout-of-bounds-subscripts.f90 | 22 +++++++++++++
 flang/test/Semantics/bug171844.f90            | 21 +++++++-----
 flang/test/Semantics/bug82684.f90             | 33 +++++++++++++++----
 flang/test/Semantics/expr-errors06.f90        |  3 +-
 10 files changed, 106 insertions(+), 34 deletions(-)
 create mode 100644 flang/test/Driver/fout-of-bounds-subscripts.f90

diff --git a/clang/include/clang/Options/FlangOptions.td b/clang/include/clang/Options/FlangOptions.td
index a966bf152c3e0..9dfe50593f33d 100644
--- a/clang/include/clang/Options/FlangOptions.td
+++ b/clang/include/clang/Options/FlangOptions.td
@@ -189,8 +189,9 @@ defm ppc_native_vec_elem_order: BoolOptionWithoutMarshalling<"f", "ppc-native-ve
   PosFlag<SetTrue, [], [ClangOption], "Specifies PowerPC native vector element order (default)">,
   NegFlag<SetFalse, [], [ClangOption], "Specifies PowerPC non-native vector element order">>;
 defm unsigned : OptInFC1FFlag<"unsigned", "Enables UNSIGNED type">;
-defm out_of_bounds_subscripts : OptInFC1FFlag<"out-of-bounds-subscripts",
-  "Warn instead of erroring when a constant subscript is out of bounds (extension)">;
+defm out_of_bounds_subscripts : OptOutFC1FFlag<"out-of-bounds-subscripts",
+  "Accept a constant subscript that is out of bounds, with a warning (default)",
+  "Reject a constant subscript that is out of bounds with an error">;
 defm enumeration_type : OptInFC1FFlag<"enumeration-type", "Enables F2023 ENUMERATION TYPE (experimental; FIR lowering is incomplete)">;
 defm openacc_default_none_scalars_strict : OptOutFC1FFlag<"openacc-default-none-scalars-strict",
   "Require explicit data clauses for all variables (including scalars) under OpenACC DEFAULT(NONE)",
diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index c57d0863eeef8..e80925170923a 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -1081,14 +1081,22 @@ print *, [(j,j=1,10)]
   are noted only as warnings when they appear in code known to be
   dead anyway at compilation time.
 
-* A subscript value is required to be within its bounds only when the
-  reference is actually executed, so a reference with an out-of-range
-  constant subscript that never runs does not make a program
-  nonconforming.  That case cannot be recognized in general -- consider a
-  procedure whose only call is in dead code, or one that is never called
-  at all -- so these subscripts are errors by default.  Use
-  `-fout-of-bounds-subscripts` to accept them with a warning instead;
-  the warning can then be silenced with `-Wno-out-of-bounds-subscripts`.
+* A reference with a constant subscript that is out of range is accepted
+  with a warning rather than rejected with an error.  A subscript value is
+  required to be within its bounds only when the reference is executed
+  (F'2023 9.5.3.1 paragraph 2), so a reference that never runs does not
+  render a program nonconforming; that case cannot be recognized in general
+  -- consider a procedure whose only call site is in dead code, or one that
+  is never called at all.  Note that the warning, not an error, is also what
+  appears when the reference *is* executed.  The endpoints of array sections
+  get the same treatment.  Cosubscripts do not: their requirement is F'2023
+  9.6 paragraph 2 and a cosubscript list determines an image index, so an
+  out-of-cobounds constant cosubscript remains an error.
+  Use `-fno-out-of-bounds-subscripts` to make these references errors again,
+  or `-Wno-out-of-bounds-subscripts` to silence the warning entirely.
+  Note that a module file compiled with the warning may produce errors in a
+  dependent compilation that uses `-fno-out-of-bounds-subscripts`, since the
+  interface is re-analyzed there; those errors point into the module file.
 
 ## Behavior in cases where the standard is clear but disputed
 
diff --git a/flang/docs/ReleaseNotes.md b/flang/docs/ReleaseNotes.md
index a5705fe18983c..0f5c1548f943d 100644
--- a/flang/docs/ReleaseNotes.md
+++ b/flang/docs/ReleaseNotes.md
@@ -69,7 +69,20 @@ page](https://llvm.org/releases/).
   that unit. Constants of an intrinsic module such as `iso_fortran_env` are
   not described yet, because no compilation unit defines them.
 
+- A reference with a constant subscript that is out of range is now accepted with
+  a warning instead of being rejected with an error. A subscript is required to be
+  within its bounds only when the reference is executed (F'2023 9.5.3.1 paragraph
+  2), and that cannot be determined in general, so programs that keep such a
+  reference in a branch or procedure that never runs are no longer rejected. The
+  same applies to array section endpoints, but not to cosubscripts, which remain
+  errors. Use `-fno-out-of-bounds-subscripts` to get an error again, or
+  `-Wno-out-of-bounds-subscripts` to silence the warning.
+
 ## New Compiler Flags
+- Added `-fno-out-of-bounds-subscripts`, which restores the previous behavior of
+  rejecting an out-of-range constant subscript with an error. See the entry above
+  for the change in default behavior.
+
 - Added the gfortran-compatible `-ffpe-trap=` flag, which sets the initial
   floating-point exception halting mode of the main program. It takes a
   comma-separated list of `invalid`, `zero`, `overflow`, `underflow`, `inexact`,
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index 1ba3c2b312d3c..7cfd89e120b7d 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -923,7 +923,7 @@ static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,
   opts.features.Enable(
       Fortran::common::LanguageFeature::OutOfBoundsSubscripts,
       args.hasFlag(clang::options::OPT_fout_of_bounds_subscripts,
-                   clang::options::OPT_fno_out_of_bounds_subscripts, false));
+                   clang::options::OPT_fno_out_of_bounds_subscripts, true));
 
   // -f{no-}enumeration-type (experimental; FIR lowering is incomplete)
   opts.features.Enable(Fortran::common::LanguageFeature::EnumerationType,
diff --git a/flang/lib/Semantics/expression.cpp b/flang/lib/Semantics/expression.cpp
index 03832d84d70d1..91e98d5c8018c 100644
--- a/flang/lib/Semantics/expression.cpp
+++ b/flang/lib/Semantics/expression.cpp
@@ -367,13 +367,21 @@ static void ValidateSubscriptValue(semantics::SemanticsContext &context,
     return;
   }
   parser::ContextualMessages &messages{context.foldingContext().messages()};
-  if (msg->severity() == parser::Severity::ErrorUnlessDeadCode &&
+  if (msg->severity() == parser::Severity::ErrorUnlessDeadCode && *co == '\0' &&
       context.IsEnabled(common::LanguageFeature::OutOfBoundsSubscripts)) {
     // A subscript value is required to be within its bounds only when the
     // reference is executed (F'2023 9.5.3.1 p2), so a reference that appears
     // in code that never runs does not render the program nonconforming.
-    // That case can't be recognized in general, so this extension accepts
-    // any out-of-bounds constant subscript with a warning.
+    // That case can't be recognized in general -- consider a procedure whose
+    // only call site is in dead code, or one that is never called at all --
+    // so by default these references are accepted with a warning, and
+    // -fno-out-of-bounds-subscripts restores a hard error.  The endpoints of
+    // array sections are validated here too and get the same treatment.
+    //
+    // Cosubscripts (a nonempty 'co') are deliberately excluded: their
+    // requirement is F'2023 9.6 p2 rather than 9.5.3.1 p2, and a cosubscript
+    // list determines an image index, so an out-of-cobounds constant
+    // cosubscript remains a hard error.
     msg->set_severity(parser::Severity::Warning);
     AttachDeclaration(
         context.Warn(messages, common::LanguageFeature::OutOfBoundsSubscripts,
diff --git a/flang/lib/Support/Fortran-features.cpp b/flang/lib/Support/Fortran-features.cpp
index 309ada5813ed7..3dd1602e29103 100644
--- a/flang/lib/Support/Fortran-features.cpp
+++ b/flang/lib/Support/Fortran-features.cpp
@@ -156,9 +156,6 @@ LanguageFeatureControl::LanguageFeatureControl() {
   disable_.set(LanguageFeature::AssumedRankPassedToNonAssumedRank);
   disable_.set(LanguageFeature::Coarray);
   disable_.set(LanguageFeature::OpenAccDefaultNoneScalarsStrict);
-  // An out-of-bounds constant subscript is a hard error by default; enabling
-  // this extension reduces it to a warning.
-  disable_.set(LanguageFeature::OutOfBoundsSubscripts);
   // These warnings are enabled by default, but only because they used
   // to be unconditional.  TODO: prune this list
   warnLanguage_.set(LanguageFeature::ExponentMatchingKindParam);
diff --git a/flang/test/Driver/fout-of-bounds-subscripts.f90 b/flang/test/Driver/fout-of-bounds-subscripts.f90
new file mode 100644
index 0000000000000..22c607327da26
--- /dev/null
+++ b/flang/test/Driver/fout-of-bounds-subscripts.f90
@@ -0,0 +1,22 @@
+! Check driver handling of -f[no-]out-of-bounds-subscripts.  An out-of-range
+! constant subscript is a warning by default; -fno-out-of-bounds-subscripts
+! makes it an error.  The last of the two spellings on the command line wins.
+
+! RUN: %flang -fsyntax-only %s 2>&1 | FileCheck --check-prefix=WARN %s
+! RUN: %flang -fsyntax-only -fout-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=WARN %s
+! RUN: not %flang -fsyntax-only -fno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=ERROR %s
+! RUN: not %flang -fsyntax-only -fout-of-bounds-subscripts -fno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=ERROR %s
+! RUN: %flang -fsyntax-only -fno-out-of-bounds-subscripts -fout-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=WARN %s
+! RUN: %flang -fsyntax-only -Wno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=SILENT --allow-empty %s
+
+module m
+  real :: a(5)
+ contains
+  ! This subprogram is never called.
+  subroutine never_called()
+    !WARN: warning: subscript 6 is greater than upper bound 5 for dimension 1 of array [-Wout-of-bounds-subscripts]
+    !ERROR: error: subscript 6 is greater than upper bound 5 for dimension 1 of array
+    !SILENT-NOT: subscript 6
+    a(6) = 0.
+  end subroutine
+end module
diff --git a/flang/test/Semantics/bug171844.f90 b/flang/test/Semantics/bug171844.f90
index 2dd4bfbf8625f..5563f3d817e3e 100644
--- a/flang/test/Semantics/bug171844.f90
+++ b/flang/test/Semantics/bug171844.f90
@@ -1,36 +1,39 @@
-! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
-! RUN: not %flang_fc1 -fsyntax-only -Wno-bad-value-in-dead-code %s 2>&1 | FileCheck %s
+! Out-of-range constant subscripts are warnings by default, so use
+! -fno-out-of-bounds-subscripts here to exercise the downgrade of errors to
+! warnings in code that is known at compilation time to be dead.
+! RUN: not %flang_fc1 -fsyntax-only -fno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
+! RUN: not %flang_fc1 -fsyntax-only -fno-out-of-bounds-subscripts -Wno-bad-value-in-dead-code %s 2>&1 | FileCheck %s
 
 real a(2)
 
 if (.false.) then
-  !CHECK-WARNING::8:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING::11:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(3)
 end if
 
 if (.true.) then
-  !CHECK::13:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
+  !CHECK::16:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
   print *, a(0)
 else
-  !CHECK-WARNING::16:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING::19:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(0)
 end if
 
 if (.false.) then
 else if (.true.) then
-  !CHECK::22:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
+  !CHECK::25:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
   print *, a(0)
 else
-  !CHECK-WARNING::25:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING::28:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(0)
 end if
 
 if (.true.) then
 else if (.true.) then
-  !CHECK-WARNING::31:12: warning: subscript -1 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING::34:12: warning: subscript -1 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(-1)
 else
-  !CHECK-WARNING::34:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING::37:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(3)
 end if
 
diff --git a/flang/test/Semantics/bug82684.f90 b/flang/test/Semantics/bug82684.f90
index 8732959fa10f2..224bd91ae8bf8 100644
--- a/flang/test/Semantics/bug82684.f90
+++ b/flang/test/Semantics/bug82684.f90
@@ -1,30 +1,49 @@
-! Out-of-bounds constant subscripts are errors by default, but
-! -fout-of-bounds-subscripts reduces them to warnings, since such a
+! An out-of-range constant subscript is accepted with a warning, because such a
 ! reference is nonconforming only if it is actually executed.
-! RUN: not %flang_fc1 -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
-! RUN: %flang_fc1 -fsyntax-only -fout-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
-! RUN: %flang_fc1 -fsyntax-only -fout-of-bounds-subscripts -Wno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-SILENT --allow-empty %s
+! -fno-out-of-bounds-subscripts restores the error.
+! A cosubscript is not covered: it stays an error in every mode, so every RUN
+! line below expects a failing compilation.
+! RUN: not %flang_fc1 -fsyntax-only -fcoarray %s 2>&1 | FileCheck --check-prefix=CHECK-WARNING %s
+! RUN: not %flang_fc1 -fsyntax-only -fcoarray -fno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-ERROR %s
+! RUN: not %flang_fc1 -fsyntax-only -fcoarray -Wno-out-of-bounds-subscripts %s 2>&1 | FileCheck --check-prefix=CHECK-SILENT %s
 
 module m
   integer, parameter :: n_dims = 2
   type :: grid_type
     real :: cells(1000, n_dims)
   end type
+  real :: a(5)
+  integer :: c(3)[2:4,*]
  contains
   ! This subprogram is never called, so it never renders the program
   ! nonconforming, but that can't be proven here.
   subroutine init_3Dgrid(node)
     type(grid_type), intent(inout) :: node
-    !CHECK-ERROR: error: subscript 3 is greater than upper bound 2 for dimension 2 of array
     !CHECK-WARNING: warning: subscript 3 is greater than upper bound 2 for dimension 2 of array [-Wout-of-bounds-subscripts]
+    !CHECK-ERROR: error: subscript 3 is greater than upper bound 2 for dimension 2 of array
     !CHECK-SILENT-NOT: subscript 3
     node%cells(:,3) = 3.0
   end subroutine
   subroutine lower(node)
     type(grid_type), intent(inout) :: node
-    !CHECK-ERROR: error: subscript 0 is less than lower bound 1 for dimension 2 of array
     !CHECK-WARNING: warning: subscript 0 is less than lower bound 1 for dimension 2 of array [-Wout-of-bounds-subscripts]
+    !CHECK-ERROR: error: subscript 0 is less than lower bound 1 for dimension 2 of array
     !CHECK-SILENT-NOT: subscript 0
     node%cells(:,0) = 0.0
   end subroutine
+  ! An array section endpoint is validated by the same code path.
+  subroutine section()
+    !CHECK-WARNING: warning: subscript 6 is greater than upper bound 5 for dimension 1 of array [-Wout-of-bounds-subscripts]
+    !CHECK-ERROR: error: subscript 6 is greater than upper bound 5 for dimension 1 of array
+    !CHECK-SILENT-NOT: subscript 6
+    a(4:6) = 0.
+  end subroutine
+  ! A cosubscript is NOT covered: its requirement is F'2023 9.6 p2 and it
+  ! determines an image index, so it stays an error in every mode.
+  subroutine cosubscript()
+    !CHECK-WARNING: error: cosubscript 1 is less than lower cobound 2 for codimension 1 of array
+    !CHECK-ERROR: error: cosubscript 1 is less than lower cobound 2 for codimension 1 of array
+    !CHECK-SILENT: error: cosubscript 1 is less than lower cobound 2 for codimension 1 of array
+    c(1)[1,1] = 0
+  end subroutine
 end module
diff --git a/flang/test/Semantics/expr-errors06.f90 b/flang/test/Semantics/expr-errors06.f90
index c366060691556..b062b993961d4 100644
--- a/flang/test/Semantics/expr-errors06.f90
+++ b/flang/test/Semantics/expr-errors06.f90
@@ -1,5 +1,6 @@
-! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror
+! RUN: %python %S/test_errors.py %s %flang_fc1 -pedantic -Werror -fno-out-of-bounds-subscripts
 ! Check out-of-range subscripts
+! These are warnings by default; -fno-out-of-bounds-subscripts makes them errors.
 subroutine subr(da)
   real a(10), da(2,1), empty(1:0,1)
   integer, parameter :: n(2) = [1, 2]

>From c17f045a72ee80cf5d900ad242473f7bf7991609 Mon Sep 17 00:00:00 2001
From: Ronald Green <rogreen at nvidia.com>
Date: Wed, 2 Sep 2026 13:31:07 -0700
Subject: [PATCH 3/4] [flang] Document what out-of-range diagnostics remain
 errors

A reference to a named constant array, a DATA statement designator, and a
substring with an out-of-range bound are all still rejected with an error;
only subscripts of variables and the endpoints of array sections became
warnings.  Say so in Extensions.md, and pin the behavior in the test.
---
 flang/docs/Extensions.md          |  5 ++++-
 flang/test/Semantics/bug82684.f90 | 16 ++++++++++++++++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/flang/docs/Extensions.md b/flang/docs/Extensions.md
index e80925170923a..0b16348074cfc 100644
--- a/flang/docs/Extensions.md
+++ b/flang/docs/Extensions.md
@@ -1091,7 +1091,10 @@ print *, [(j,j=1,10)]
   appears when the reference *is* executed.  The endpoints of array sections
   get the same treatment.  Cosubscripts do not: their requirement is F'2023
   9.6 paragraph 2 and a cosubscript list determines an image index, so an
-  out-of-cobounds constant cosubscript remains an error.
+  out-of-cobounds constant cosubscript remains an error.  Neither do an
+  out-of-range subscript in a reference to a named constant array, an
+  out-of-range `DATA` statement designator, or an out-of-range substring;
+  those remain errors as well.
   Use `-fno-out-of-bounds-subscripts` to make these references errors again,
   or `-Wno-out-of-bounds-subscripts` to silence the warning entirely.
   Note that a module file compiled with the warning may produce errors in a
diff --git a/flang/test/Semantics/bug82684.f90 b/flang/test/Semantics/bug82684.f90
index 224bd91ae8bf8..791b8eb176062 100644
--- a/flang/test/Semantics/bug82684.f90
+++ b/flang/test/Semantics/bug82684.f90
@@ -14,6 +14,7 @@ module m
   end type
   real :: a(5)
   integer :: c(3)[2:4,*]
+  integer, parameter :: k(2) = [1, 2]
  contains
   ! This subprogram is never called, so it never renders the program
   ! nonconforming, but that can't be proven here.
@@ -46,4 +47,19 @@ subroutine cosubscript()
     !CHECK-SILENT: error: cosubscript 1 is less than lower cobound 2 for codimension 1 of array
     c(1)[1,1] = 0
   end subroutine
+  ! Nor is a reference to a named constant array, a DATA statement
+  ! designator, or a substring; those stay errors in every mode too.
+  subroutine still_errors()
+    real :: d(10)
+    character(4) :: s
+    data d(0)/0./
+    !CHECK-WARNING: error: Subscript value (0) is out of range on dimension 1 in reference to a constant array value
+    !CHECK-ERROR: error: Subscript value (0) is out of range on dimension 1 in reference to a constant array value
+    !CHECK-SILENT: error: Subscript value (0) is out of range on dimension 1 in reference to a constant array value
+    print *, k(0)
+    !CHECK-WARNING: error: Substring must end at 4 or earlier, not 9
+    !CHECK-ERROR: error: Substring must end at 4 or earlier, not 9
+    !CHECK-SILENT: error: Substring must end at 4 or earlier, not 9
+    print *, s(2:9)
+  end subroutine
 end module

>From 0c4bb7b40e2ad5abb1c7a9ba7dec871a2149b215 Mon Sep 17 00:00:00 2001
From: Ronald Green <rogreen at nvidia.com>
Date: Thu, 3 Sep 2026 14:56:46 -0700
Subject: [PATCH 4/4] [flang] Drop embedded line numbers from bug171844.f90
 checks

The expected diagnostics are distinguished by their text and by the order
in which FileCheck matches them, and line information is verified by other
tests, so the absolute line numbers only made the test brittle against
edits to the file.
---
 flang/test/Semantics/bug171844.f90 | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/flang/test/Semantics/bug171844.f90 b/flang/test/Semantics/bug171844.f90
index 5563f3d817e3e..e603626110b81 100644
--- a/flang/test/Semantics/bug171844.f90
+++ b/flang/test/Semantics/bug171844.f90
@@ -7,33 +7,33 @@
 real a(2)
 
 if (.false.) then
-  !CHECK-WARNING::11:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(3)
 end if
 
 if (.true.) then
-  !CHECK::16:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
+  !CHECK: error: subscript 0 is less than lower bound 1 for dimension 1 of array
   print *, a(0)
 else
-  !CHECK-WARNING::19:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(0)
 end if
 
 if (.false.) then
 else if (.true.) then
-  !CHECK::25:12: error: subscript 0 is less than lower bound 1 for dimension 1 of array
+  !CHECK: error: subscript 0 is less than lower bound 1 for dimension 1 of array
   print *, a(0)
 else
-  !CHECK-WARNING::28:12: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING: warning: subscript 0 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(0)
 end if
 
 if (.true.) then
 else if (.true.) then
-  !CHECK-WARNING::34:12: warning: subscript -1 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING: warning: subscript -1 is less than lower bound 1 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(-1)
 else
-  !CHECK-WARNING::37:12: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
+  !CHECK-WARNING: warning: subscript 3 is greater than upper bound 2 for dimension 1 of array [-Wbad-value-in-dead-code]
   print *, a(3)
 end if
 



More information about the flang-commits mailing list