History, Standards and Compilers

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

This section is written against Fortran 2023 (ISO/IEC 1539-1:2023, read here through the free final draft J3/23-007r1). Every example was checked on 2026-10-18 with GNU Fortran (gfortran) 16.2 using -std=f2023 -Wall -Wextra -pedantic -fimplicit-none -fcheck=all, and, where the example says so, also with LLVM Flang 23. Fortran is the oldest high-level programming language still in wide use, and it is also a language that keeps being revised: eight standards between 1966 and 2023, with a ninth, Fortran 2028, at Committee Draft stage. Knowing which revision a feature belongs to, who decides what goes into the next one, and which compilers implement it is not trivia. It decides whether a program written today compiles on the cluster you were given, and whether a 1990s code base can be modernized in place.

This page covers four things. First, the history: what each revision added and which technical reports (TRs) and technical specifications (TSs) were folded into later standards. Second, how the standard is produced and what "conforming" means for a program and for a compiler. Third, the compiler landscape. Fourth, a table of compiler support for every Fortran 2023 feature, which other pages of this section link to whenever they show a Fortran 2023 feature. The examples follow the running heatflow project (a 2D heat diffusion solver) introduced in Getting Started.

Related pages: Compilers and Compiler Options (installing and driving each compiler), Legacy Features and Modernization (the obsolescent and deleted features in depth), What’s New and Fortran 2028 Preview (the Fortran 2023 additions in detail and the 2028 work items), and Intrinsic Modules and iso_fortran_env.

A short history

Fortran (FORTRAN until Fortran 90, from "formula translation") was designed by a team at IBM led by John Backus. The first compiler shipped in 1957 for the IBM 704. Its aim was to let scientists write formulas instead of machine code and still obtain code almost as fast as hand-written assembly, an aim that has shaped every later revision: Fortran gives the compiler enough information (no aliasing between dummy arguments, whole-array semantics, do concurrent) to optimize aggressively.

Vendors soon diverged, so the American standards body standardized the language. The first ISO designation, ISO R 1539-1972, is what everyone calls Fortran 66. Since then each edition has an official designation and an informal name. S 4.3.1 lists them all; the table below adds the headline contribution of each revision. The informal names are the ones used in compiler manuals and in this section.

Informal name Official designation What it added (headline features)

FORTRAN I (1957), II (1958), IV (1962)

vendor languages

Formulas, do loops, if, formatted read/write, subroutines and functions (II), logical and double precision types (IV). No standard.

Fortran 66

ISO R 1539-1972 (ANSI X3.9-1966)

The first standard: a portable subset of the vendor dialects.

FORTRAN 77

ISO 1539-1980 (ANSI X3.9-1978)

character type, block if/else, do with negative steps and zero-trip loops, save, direct-access and inquire I/O, parameter. A minor revision that dominated for more than a decade.

Fortran 90

ISO/IEC 1539:1991

The major break: free source form, modules, derived types, whole-array operations and sections, allocatable arrays and pointers, dynamic memory, recursive, select case, kind parameters and selected_real_kind, implicit none, intent, optional and keyword arguments, new intrinsics.

Fortran 95

ISO/IEC 1539-1:1997

forall, pure and elemental procedures, where extensions, default initialization of components, null(), automatic deallocation of local allocatables. The first deleted features (see below).

Fortran 2003

ISO/IEC 1539-1:2004

Object orientation (type extension, polymorphism, type-bound procedures, abstract types, class, select type, final), parameterized derived types, C interoperability (iso_c_binding, bind(c)), procedure pointers, derived-type I/O, stream I/O, iso_fortran_env, IEEE arithmetic modules, command-line and environment intrinsics, associate, allocatable components and automatic reallocation on assignment.

Fortran 2008

ISO/IEC 1539-1:2010

Coarrays and the image model, submodules, do concurrent, contiguous, block, error stop, newunit=, bit-manipulation intrinsics, findloc, norm2, Bessel and error functions, execute_command_line, impure elemental, exit from any construct.

Fortran 2018

ISO/IEC 1539-1:2018

Teams, events, collectives, atomics and failed-image support (from TS 18508), assumed-rank and further C interoperability (from TS 29113), implicit none (type, external), select rank, the generic statement, reduce, random_init, non_recursive.

Fortran 2023

ISO/IEC 1539-1:2023 (Nov 2023); Cor 1:2026 (Jan 2026)

10,000-character lines, typeof/classof, conditional expressions and arguments, extended BOZ constants, split/tokenize, trigonometry in degrees (sind) and half-revolutions (sinpi), selected_logical_kind, IEEE 60559:2020 conformance, c_f_strpointer/f_c_string, the at edit descriptor and leading-zero control, simple procedures, integer arrays as subscripts and bounds, the rank clause, reduce in do concurrent, enumeration types, put with notify.

Fortran 2028

Committee Draft stage (WG5 N2258, not public); public working draft J3/26-007r1

Templates and generic subprograms, source-location intrinsics and further additions. Described only as "upcoming" in this section; see What’s New and Fortran 2028 Preview.

The WG5 paper N2212, written by John Reid, summarizes the Fortran 2023 additions in prose and notes the alternation between major and minor revisions (1978 minor, 1991 major, 1997 minor, 2004 major, 2010 minor; 2018 avoided being major to give implementers time, and 2023 was planned as minor too): WG5 N2212, The new features of Fortran 2023. The equivalent papers for the earlier revisions are N2161 (Fortran 2018), N1891 (Fortran 2008) and N1648 (Fortran 2003).

The diagram shows the same history as a timeline.

timeline title Fortran standards 1957 to 2028 1957 : FORTRAN I at IBM - formulas to machine code 1966 : Fortran 66 - the first standard 1978 : FORTRAN 77 - character type and block if 1991 : Fortran 90 - free form, modules, arrays, pointers 1997 : Fortran 95 - forall, pure and elemental 2004 : Fortran 2003 - objects, C interoperability, IEEE modules 2010 : Fortran 2008 - coarrays, submodules, do concurrent 2018 : Fortran 2018 - teams, events, collectives, assumed rank 2023 : Fortran 2023 - long lines, conditional expressions, enumerations, trig in degrees 2028 : Fortran 2028 - templates (Committee Draft stage)

Technical reports and specifications folded into later standards

Between two revisions, WG5 sometimes publishes a technical report (TR) or technical specification (TS) that specifies a large feature early, so that implementers can gain experience before it is promised forever. The feature then moves into the next revision, normally with small changes. A compiler manual that says "supports TS 29113" or "supports the TS 18508 features" therefore refers to a subset of a later standard.

Document Subject Folded into

TR 15580 and TR 15581

Floating-point exception handling (the ieee_* modules), and enhanced allocatable arrays (allocatable dummy arguments, function results and structure components)

Fortran 2003

TR 19767

Enhanced module facilities: submodules and separate module procedures

Fortran 2008

ISO/IEC TS 29113:2012

Further interoperability of Fortran with C: assumed-type type(*), assumed-rank, ISO_Fortran_binding.h, optional and asynchronous interoperable arguments

Fortran 2018

TS 18508

Additional parallel features: teams, events, collectives, atomics, failed images

Fortran 2018

A consequence for library authors: code that needs only the TS 29113 features can be described as "Fortran 2018", but processors that never reached full F2018 may still offer the TS. gfortran documents full support for TS 29113, and a partial implementation of the TS 18508 parallel features (the gfortran manual lists the polymorphic-type gap in co_min, co_max, co_sum, co_broadcast and co_reduce).

Deleted and obsolescent features

Fortran is unusual in how seldom it deletes anything. S 4.4 states the policy: the standard "protects the users' investment in existing software" and keeps all but six language elements of Fortran 90 that are not processor dependent. It identifies two categories:

  • Deleted features were redundant already in FORTRAN 77 and largely unused in Fortran 90. There are two groups. The first group was dropped with Fortran 95 (real and double precision do variables, branching to end if from outside the block, pause, assign and assigned go to/assigned formats, the H edit descriptor, and vertical format control). The second group (the arithmetic if statement and the nonblock do construct) was still in Fortran 2008 and is deleted from the current standard.

  • Obsolescent features were redundant already in Fortran 90 and 95 but are still frequently used. Annex B lists alternate return, computed go to, statement functions, data among executable statements, assumed-length character functions, fixed source form, the character*n form, entry, the labelled do, common/equivalence/block data, specific names of intrinsic functions, and forall.

Deleted does not mean unsupported by compilers: gfortran, for instance, accepts most of them in its default -std=gnu mode and only rejects them under -std=f2023. A processor is required to be able to report both categories (S 4.2, below). This section shows these features only on Legacy Features and Modernization, next to the modern replacement.

How Fortran is standardized

Three organizations are involved, with deliberately different roles.

Body Role

ISO/IEC JTC 1/SC 22/WG 5 (WG5)

The international working group for Fortran. It chooses the content of each revision through resolutions at its meetings, publishes numbered papers (the N documents such as N2212, N2244 and N2258) and keeps the schedule. Its site is the index of the standards and of the committee papers.

J3

The US Fortran committee (the technical committee called INCITS PL22.3 and, long ago, ANSI X3J3). J3 is the US national body for WG5 and is the primary development body for Fortran 95 and later: it writes the technical content, and its website publishes the papers, draft and interpretation on its website. Membership and meetings are open to anyone worldwide.

ISO

Publishes the standard as ISO/IEC 1539-1 (Part 1, Base language). This is the document the section describes.

The diagram shows how an idea becomes part of the standard, and how the standard is maintained afterwards.

flowchart LR A["Idea or issue on fortran_proposals"] --> B["J3 paper with a committee advocate"] B --> C["J3 working draft J3/yy-007"] C --> D["WG5 work list and requirements"] D --> E["Committee Draft and ISO ballots"] E --> F["Published ISO/IEC 1539-1"] F --> G["Interpretations and corrigenda"] G --> C

Revision cycle, interpretations and corrigenda

  • Revisions arrive about every five to eight years (1991, 1997, 2004, 2010, 2018, 2023). WG5 votes a work list, J3 turns it into a working draft named J3/yy-007 (yy is the year, 007 the fixed number of the draft and r1 its first revision), and the draft goes through Committee Draft and ISO ballots.

  • Interpretations answer questions about what the published text means. J3 and WG5 process each one, and an accepted answer that fixes a defect becomes a corrigendum.

  • Corrigenda are small published corrections to a standard. Fortran 2018 received two. Fortran 2023 has Corrigendum 1 (ISO/IEC 1539-1:2023/Cor 1:2026, January 2026; WG5 paper N2244).

  • The free text of a standard is the final draft: J3/23-007r1 (13 June 2023) is what this section cites with clause numbers. The authoritative document is the ISO text, which is sold by ISO and may differ editorially from the last J3 draft. For contractual or certification work, check the clause against the ISO publication and the corrigendum.

  • Proposals for the next revision are discussed in public on the GitHub repository j3-fortran/fortran_proposals: an idea is opened as an issue, discussed by the community, and, if it has merit and a committee member willing to advocate it, written up as a text-file proposal for J3. Negative feedback closes the issue with documented reasons; a new issue can ask for reconsideration.

The history of the standardization meetings from 1963 to 2026 is in WG5 N2263.

Conformance: what the standard requires of programs and compilers

Fortran standardizes two things: the programs that are allowed, and what a processor must do with them. "Processor" is the standard’s word for compiler plus runtime plus hardware. S 4.2 defines both sides.

A standard-conforming program uses only the forms and relationships described by the standard, and has an interpretation according to it. A program unit conforms if it can be included in a program in a way that allows the program to be standard-conforming. Conformance does not guarantee portable behaviour: a conforming program may depend on things outside the standard (for example external procedures written in C) or on processor-dependent behaviour, whose semantics the standard leaves to the processor (Annex A lists them).

A standard-conforming processor must:

  1. execute any conforming program as the standard specifies, subject to documented limits on size and complexity;

  2. be able to detect and report use of an obsolescent form, where this can be determined from the numbered syntax rules and constraints;

  3. be able to detect and report any form not permitted by the syntax rules or constraints, including the deleted features;

  4. detect and report an intrinsic type with an unsupported kind;

  5. detect and report source form or characters not permitted by Clause 6;

  6. detect and report name usage that violates the scope rules;

  7. detect and report use of a nonstandard intrinsic procedure or nonstandard intrinsic module, or of a procedure of a standard intrinsic module that the standard does not define;

  8. detect and report the reason for rejecting a program.

"Detect and report" means the processor can do so, not that it does so by default. This is why compiler options such as -std=f2023 exist: they switch the reporting on. A processor may also allow additional forms and relationships (extensions), provided they do not conflict with the standard, and may add intrinsic procedures even if this clashes with a name used by a conforming program (unless that name has the external attribute where it is used). A conforming program must not use the processor’s added intrinsics. The processor should also come with documentation of its limits, its extensions and how their use is reported.

The first example below shows a processor reporting a nonstandard intrinsic. The program is intentionally non-conforming: getpid is a GNU extension. By default gfortran accepts it silently (it compiles and runs), while under -std=f2023 the name is not an intrinsic, so with implicit none it is rejected.

! INTENTIONALLY NON-CONFORMING: GETPID is a GNU extension, not a standard
! intrinsic, so a conforming processor must be able to report its use (4.2).
program nonstandard_intrinsic
  implicit none
  integer :: pid
  pid = getpid()
  print '(a)', 'process id obtained'
end program nonstandard_intrinsic
gfortran 07_nonstandard_intrinsic.f90 -o nonstandard && ./nonstandard
gfortran -std=f2023 07_nonstandard_intrinsic.f90 -o nonstandard
process id obtained
07_nonstandard_intrinsic.f90:6:8:

    6 |   pid = getpid()
      |        1
Error: Function 'getpid' at (1) has no IMPLICIT type

LLVM Flang 23 accepted the same file without a diagnostic, even with -pedantic: reporting extensions is a processor choice, and compilers differ in how much they report. If you target several compilers, compile with each of them.

Compatibility between revisions

The compatibility subclauses (S 4.3) state that each revision is an upward-compatible extension of the previous one, except for a short, explicit list. A standard-conforming Fortran 2018 program that avoids those items is a conforming Fortran 2023 program. The items in S 4.3.3 that can change meaning or stop being permitted are:

  • system_clock: all integer arguments of one reference must now have the same kind, with a decimal exponent range at least that of default integer, and a processor may provide several clocks selected by the kind of the arguments;

  • a variable of a block construct declared only by a data statement can no longer be used before the data statement;

  • the pointer and target arguments of associated can no longer have different ranks;

  • deferred-length allocatable character variables assigned by iomsg=, errmsg=, an internal write or an intent-out argument of an intrinsic subroutine now get intrinsic-assignment semantics, so their length can differ from Fortran 2018;

  • ieee_max_num, ieee_min_num and their _mag variants return the number when the other argument is a signaling NaN.

The system_clock change is a good example of a rule that compilers enforce under -std=f2023. The conforming form uses one kind (here the 64-bit lp from the heatflow kinds module) for every integer argument:

module heatflow_kinds
  use, intrinsic :: iso_fortran_env, only: int64, real64
  implicit none
  private
  public :: dp, lp
  integer, parameter :: dp = real64
  integer, parameter :: lp = int64
end module heatflow_kinds

program system_clock_f2023
  use heatflow_kinds, only: dp, lp
  implicit none
  integer(lp) :: t0, t1, rate, i
  real(dp) :: s
  call system_clock(t0, rate)          ! all integer arguments have the same kind
  s = 0.0_dp
  do i = 1_lp, 2000000_lp
    s = s + 1.0_dp / real(i, dp)
  end do
  call system_clock(t1)
  print '(a,l1)', 'clock is running: ', rate > 0_lp
  print '(a,l1)', 'elapsed time is non-negative: ', t1 >= t0
  print '(a,f8.5)', 'harmonic sum: ', s
end program system_clock_f2023
clock is running: T
elapsed time is non-negative: T
harmonic sum: 15.08587

The next program is intentionally non-conforming to Fortran 2023 (it is valid Fortran 2018): it mixes a default-kind and a 64-bit integer in one system_clock reference. gfortran rejects it under -std=f2023; Flang 23 accepts it (checked: it compiles and runs without any message), so the rule is not enforced uniformly yet.

! INTENTIONALLY NON-CONFORMING to Fortran 2023: the integer arguments of one
! SYSTEM_CLOCK reference have different kinds (allowed by Fortran 2018).
program system_clock_mixed
  use, intrinsic :: iso_fortran_env, only: int32, int64
  implicit none
  integer(int32) :: count
  integer(int64) :: rate
  call system_clock(count, rate)
  print '(a)', 'this line is never reached under -std=f2023'
end program system_clock_mixed
06b_system_clock_mixed_kinds.f90:8:27:

    8 |   call system_clock(count, rate)
      |                           1
Error: Prohibited in Fortran 2023: integer arguments to SYSTEM_CLOCK at (1) with different kind parameters

The compiler landscape

There is no reference implementation of Fortran, and the standard is large enough that no compiler implements every part of every revision at once. The list below is based on the fortran-lang.org compilers page and on each vendor’s own manual. The fortran-lang page is a useful index but it is not always current: on the check date it listed Intel ifort as a mature compiler with full Fortran 2018 support, although ifort was discontinued with oneAPI 2025.0, and it listed NAG 7.0 as the latest NAG release although the NAG manual set includes Release 7.2.

Compiler Vendor and licence Notes

gfortran (GNU Fortran, GCC 16.2)

GNU project, GPL

Part of the GNU Compiler Collection and the most widely available compiler. "Almost all" of Fortran 2003 and 2008, partial Fortran 2018, selected Fortran 2023 features through -std=f2023, and -std=f202y for experimental proposed features. GCC 16 added native shared-memory coarrays and teams, the Fortran 2023 trigonometric functions, split and the lower= argument of c_f_pointer. The manual has no Fortran 2023 status page.

LLVM Flang (LLVM 23)

LLVM project, Apache 2.0 with LLVM exceptions

The executable is called flang (it was flang-new until LLVM 20). Fortran 2018 is implemented except the multi-image features (coarrays, teams, events), which are experimental and disabled unless -fcoarray is given. The manual has a per-feature Fortran 2023 table. The basis for several vendor compilers.

Intel ifx (oneAPI 2026.1)

Intel, proprietary (free to download)

LLVM-based, Linux and Windows on x86-64. Intel states full support for the standards through Fortran 2018 and "several" Fortran 2023 features (see the table below). It replaces ifort, which is no longer shipped from oneAPI 2025.0.

NAG Fortran (Release 7.2)

NAG, commercial

Traditionally the strictest checker of the standard, widely used to validate that code is portable. Release 7.2 supports all of Fortran 2018 and lists a few Fortran 2023 features in its release notes.

HPE Cray CCE (Cray Compiling Environment 21)

HPE, with Cray systems

The compiler of Cray supercomputers. Fortran 2018 is described as fully supported, and Fortran 2023 support is documented with a single named exception, the .nil. conditional-argument value.

NVIDIA nvfortran (HPC SDK)

NVIDIA, free

Descended from the PGI compiler. OpenACC, CUDA Fortran, and offload of do concurrent loops to GPUs with -stdpar=gpu (see do concurrent and GPU Offload).

AMD compilers (AOCC, and an LLVM-Flang-based compiler for ROCm)

AMD, free

Flang-derived compilers for AMD CPUs and GPUs.

IBM XL Fortran

IBM, commercial (community edition free)

For Power systems on Linux and AIX.

LFortran (0.67)

LFortran project, BSD-3

A new LLVM-based compiler with an interactive mode, a WebAssembly target and several back ends. Its own site still describes it as alpha: it is not expected to work on arbitrary third-party code.

Source: LFortran

Which compiler to start with depends on the goal. Use gfortran for daily development and Flang or ifx as a second opinion, because a program that two independent compilers accept is much more likely to be conforming. Add NAG (if you have access) for the strictest checking. For a cluster, use whatever the site provides (often Cray CCE, ifx or nvfortran) and test with it early. The installation, the option sets and the diagnostics are in Compilers and Compiler Options.

Selecting a standard on the command line

The option that makes a compiler enforce a revision is the first thing to learn, because the default is usually not standard-conforming.

gfortran option Meaning

-std=gnu

The default. All GNU extensions, with warnings for obsolete ones.

-std=legacy

As gnu but without the warnings for obsolete extensions; for old nonstandard code.

-std=f95, -std=f2003, -std=f2008, -std=f2018, -std=f2023

Strict conformance to that revision. Extensions are errors; permitted but obsolescent features are warned about.

-std=f202y

Fortran 2023 plus experimental proposed features. They may change or disappear.

-fall-intrinsics

Accept all intrinsics, including GNU extensions, even under -std=.

-fimplicit-none, -pedantic, -Wall, -Wextra, -fcheck=all

Not language selectors, but the usual companions: disable implicit typing everywhere, warn about extensions, and enable runtime checks. All examples of this section are compiled with these options.

The effect of -std is visible with a Fortran 2023 intrinsic. The module below builds the initial temperature field of heatflow, one half sine wave across the plate in each direction. It uses sinpi (sine of a multiple of pi, new in Fortran 2023) so that no value of pi has to be written down, and sind (sine of an angle in degrees).

module heatflow_kinds
  use, intrinsic :: iso_fortran_env, only: real64
  implicit none
  private
  public :: dp
  integer, parameter :: dp = real64
end module heatflow_kinds

module heatflow_profile
  use heatflow_kinds, only: dp
  implicit none
  private
  public :: sine_plate
contains
  ! Initial temperature field: one half sine wave across each direction
  ! (Fortran 2023 sinpi works in half-revolutions, so no pi constant is needed).
  pure function sine_plate(nx, ny) result(u)
    integer, intent(in) :: nx, ny
    real(dp) :: u(nx, ny)
    integer :: i, j
    do j = 1, ny
      do i = 1, nx
        u(i, j) = sinpi(real(i - 1, dp) / real(nx - 1, dp)) &
                * sinpi(real(j - 1, dp) / real(ny - 1, dp))
      end do
    end do
  end function sine_plate
end module heatflow_profile

program degree_and_pi_trig
  use heatflow_kinds, only: dp
  use heatflow_profile, only: sine_plate
  implicit none
  real(dp) :: u(5, 5)
  u = sine_plate(5, 5)
  print '(a,f6.3)', 'centre value  = ', u(3, 3)
  print '(a,f6.3)', 'corner value  = ', u(1, 1)
  print '(a,f6.3)', 'sind(30.0_dp) = ', sind(30.0_dp)
  print '(a,f6.3)', 'cosd(60.0_dp) = ', cosd(60.0_dp)
end program degree_and_pi_trig
centre value  =  1.000
corner value  =  0.000
sind(30.0_dp) =  0.500
cosd(60.0_dp) =  0.500

The output is identical with LLVM Flang 23. To see the revision boundary, ask gfortran to compile the same file as Fortran 2018. This second command is intentionally run on a file that uses Fortran 2023 features, and it fails as it should (the later errors are consequences of the first):

gfortran -std=f2018 -c 02_degree_and_pi_trig.f90
02_degree_and_pi_trig.f90:23:23:

   23 |         u(i, j) = sinpi(real(i - 1, dp) / real(nx - 1, dp)) &
      |                       1
Error: Function 'sinpi' at (1) has no IMPLICIT type

Identifying the compiler from the program

Portable code sometimes needs to report, or branch on, the compiler that built it, for example in a bug report or a benchmark log. Fortran 2008 added two functions to iso_fortran_env for that purpose: compiler_version() returns a string identifying the compiler, and compiler_options() returns the options used to compile the program (the content of both strings is processor dependent). Parsing the strings to select code paths is fragile; prefer build-system feature tests or the preprocessor macros of each compiler, and use these functions for logging.

module heatflow_kinds
  use, intrinsic :: iso_fortran_env, only: int32, int64, real32, real64
  implicit none
  private
  public :: sp, dp, ip, lp
  integer, parameter :: sp = real32
  integer, parameter :: dp = real64
  integer, parameter :: ip = int32
  integer, parameter :: lp = int64
end module heatflow_kinds

program compiler_identity
  use, intrinsic :: iso_fortran_env, only: compiler_version, compiler_options
  use heatflow_kinds, only: dp
  implicit none
  print '(a)', 'compiler: ' // compiler_version()
  print '(a,i0)', 'working precision: digits = ', digits(1.0_dp)
  print '(a,l1)', 'options string present: ', len(compiler_options()) > 0
end program compiler_identity

Output with gfortran 16.2:

compiler: GCC version 16.2.0
working precision: digits = 53
options string present: T

Output with LLVM Flang 23:

compiler: Debian flang version 23.1.4
working precision: digits = 53
options string present: T

(Flang 23.1.4 is the build from the LLVM apt repository used for these checks; the upstream release is 23.1.x, so name "LLVM 23" in your own documentation unless you know the exact build.) This module is the same heatflow_kinds that every later page of the section uses.

Compiler support for every Fortran 2023 feature

Support for Fortran 2023 is uneven, and the published status pages are not uniform: the GNU Fortran manual has none, LLVM publishes a per-feature table, Intel and NAG describe what they added release by release, and HPE states the support in prose. So the table below combines two kinds of evidence, on the check date 2026-10-18:

  • the gfortran 16.2 and LLVM Flang 23 columns come from small probe programs I compiled and ran with those compilers (gfortran -std=f2023 and flang, with -fcoarray=single added for gfortran so that coarray syntax is accepted);

  • the ifx, NAG and Cray columns repeat what the vendor’s own release notes or manual state. A dash means that the page I could read does not mention the feature, which is not the same as "unsupported". Vendors change this quickly: use the manual of your installed release.

Legend: Y the probe compiled and gave the expected result (or the vendor lists the feature); A the compiler accepts the syntax, but the behaviour was not run; N rejected, or the behaviour was wrong or the runtime failed; a dash, not stated. Where the Flang manual’s table disagrees with the probe (the manual lists at, simple, conditional expressions and several others as not implemented while the 23.1.4 build from apt.llvm.org accepted them), the table below gives the probe, since the probe tests the compiler you can install today. Always re-probe your own build.

Feature (J3/23-007r1 clause) Part gfortran 16.2 Flang 23 ifx 2026.1 NAG 7.2 Cray CCE

Long lines (10,000 characters) and statements (1,000,000), no continuation limit (6.3.2)

source form

Y

Y

-

Y

-

Deferred-length allocatable character allocated by the processor for iomsg=, errmsg=, internal write and intrinsic arguments (see 4.3.3)

data

N

N

-

-

-

typeof and classof type specifiers (7.3.2)

data

N

A (typeof)

-

-

-

Conditional expressions (10.1.2.3)

expressions

Y

Y

Y

-

Y

Conditional arguments, including .nil.

procedures

N

N

-

-

N

Extended BOZ constants (7.7)

data

N

Y

-

-

-

split (16.9.196)

intrinsics

Y

Y

-

-

Y

tokenize (16.9.210)

intrinsics

N (link error)

Y

-

-

Y

Trigonometry in degrees: sind, cosd, tand, asind, acosd, atand, atan2d (16.9)

intrinsics

Y

Y

-

-

-

Trigonometry in half-revolutions: sinpi, cospi, tanpi, asinpi, acospi, atanpi, atan2pi (16.9)

intrinsics

Y

Y

-

-

-

selected_logical_kind (16.9.182)

intrinsics

Y

Y

-

Y

-

logical8 to logical64, real16 in iso_fortran_env (16.10.2)

modules

Y

Y

-

Y (logical)

Y

system_clock argument rules (16.9.202)

intrinsics

Y

N (mixed kinds not diagnosed)

-

-

-

IEEE 60559:2020: ieee_max, ieee_min, _mag (17.11)

modules

N

Y

-

-

-

c_f_pointer with lower= (18.2.3.3)

C interop

Y

Y

-

-

-

f_c_string (18.2.3.9)

C interop

Y

Y

-

-

-

c_f_strpointer (18.2.3.5)

C interop

N (link error)

Y

-

-

-

at edit descriptor (13.7)

I/O

N

Y

-

Y

Y

Leading-zero control: leading_zero=, lz, lzp, lzs (12.5.6.12, 13.8)

I/O

N

Y

Y

-

-

Public namelist group with private objects (8.9)

I/O

N

N

-

-

-

Coarray ultimate components in arrays and allocatables

coarrays

N

A

-

-

-

notify_type, notify wait and notify= (11.6)

coarrays

N

-

Y

-

-

Error conditions in collective subroutines (16.6)

coarrays

-

-

-

-

-

simple procedures (15.8)

procedures

N

Y

-

-

-

Integer arrays as subscripts, the multiple subscript @ (9.5.3.2)

arrays

N

N

-

-

-

Integer arrays for bounds in declarations, allocate and pointer assignment (8.5.8, 9.7.1, 10.2.2)

arrays

N

N (reported as not yet implemented)

-

-

-

Integer constant for rank: the rank clause (8.5.17)

arrays

N

Y

-

-

-

reduce locality in do concurrent (11.1.7)

parallel

Y

Y

-

-

-

Enumeration types (7.6.2)

types

N

N

-

-

-

Notes on the table:

  • Cray CCE. HPE’s Cray Compiler Overview states that Fortran 2023 language features are supported with the exception of .nil. (conditional arguments), and its list of new intrinsics names tokenize and split; it also names conditional expressions, the at edit descriptor and the iso_fortran_env kind updates. I could read this only for CCE 20, through a search result: the HPE documentation server failed TLS verification when fetched, so the CCE 21 page was not read. Treat the Cray column as the vendor’s statement for the CCE 20/21 line, not as a result verified for CCE 21.

  • ifx. The Intel pages for 2026.0 and 2026.1 list conditional expressions, the leading-zero edit mode and the notify= specifier as new Fortran 2023 features. The 2026.1 conformance page states that the release adds no further Fortran 2023 features. The per-feature page of the Developer Guide could not be read in full, so the dashes mean "not stated on the pages read".

  • NAG. The Release 7.2 notes have a "Fortran 2023 support" section listing exactly four items: long free-form lines, selected_logical_kind, the logical8 to logical64 constants, and the at edit descriptor.

  • gfortran needs -std=f2023 (or -std=f202y) to enforce the revision, and on a 16.2 installation tokenize and c_f_strpointer compile but fail at link time (undefined reference to the library symbol), which is a good reason to test a feature with a link, not only with a syntax check. real16 is -2 on the aarch64 host used here (no 16-bit real; larger kinds exist) and 2 with Flang, which supports half precision: kind constants are processor dependent, and the negative values -1 and -2 mean "no such kind" and "no such kind but a larger one exists".

  • Flang did not run multi-image programs in these checks: coarray features need -fcoarray, and the compiler describes them as experimental.

  • Enumeration types (enumeration type) are the one Fortran 2023 data-declaration feature that neither installed compiler accepts. The heatflow boundary condition kinds therefore use the interoperable enum, bind(c) form, which both compilers accept and which is also valid Fortran 2023.

The probe method is deliberately simple, and you can repeat it for your own compiler: one tiny file per feature, compiled with -std=f2023 (or its equivalent) and, if it compiles, run, because several rejections only appear at link or run time.

for f in probe_*.f90; do
  if gfortran -std=f2023 -fcoarray=single "$f" -o probe.out 2> probe.err; then
    echo "$f: compiled -> $(./probe.out 2>&1 | head -n 2 | tr '\n' ' ')"
  else
    echo "$f: rejected -> $(head -n 3 probe.err | tr '\n' ' ')"
  fi
done

Checking features with real programs

The two programs below were used as part of the probes and are runnable examples in their own right. They are part of the heatflow project and use features that both gfortran 16.2 and Flang 23 accept.

The first reads simple key=value pairs from a text line with the Fortran 2023 intrinsic subroutine split, which moves a position to the next separator, one token at a time. The heatflow application reads a namelist file for its real run (see Internal Files, Namelist and Non-Advancing I/O); this is the same idea for a quick command-line style string. The array form tokenize returns all tokens at once, but the gfortran 16.2 library does not provide it (the link error in the table), so the portable choice today is split.

module heatflow_kinds
  use, intrinsic :: iso_fortran_env, only: int32, real64
  implicit none
  private
  public :: dp, ip
  integer, parameter :: dp = real64
  integer, parameter :: ip = int32
end module heatflow_kinds

program split_config
  use heatflow_kinds, only: dp, ip
  implicit none
  character(len=*), parameter :: line = 'nx=64;ny=32;alpha=0.01'
  integer(ip) :: nx, ny
  real(dp) :: alpha
  integer :: start, finish, eq, ios
  character(len=:), allocatable :: item, key

  nx = 0_ip
  ny = 0_ip
  alpha = 0.0_dp
  start = 1
  finish = 0
  do
    ! split moves finish to the next ';' (or len(line)+1 when there is none)
    call split(line, ';', finish)
    item = line(start:finish - 1)
    eq = index(item, '=')
    key = item(1:eq - 1)
    select case (key)
    case ('nx')
      read (item(eq + 1:), *, iostat=ios) nx
    case ('ny')
      read (item(eq + 1:), *, iostat=ios) ny
    case ('alpha')
      read (item(eq + 1:), *, iostat=ios) alpha
    case default
      print '(a)', 'unknown key: ' // key
    end select
    start = finish + 1
    if (finish > len(line)) exit
  end do
  print '(a,i0,a,i0,a,f5.3)', 'nx=', nx, ' ny=', ny, ' alpha=', alpha
end program split_config
nx=64 ny=32 alpha=0.010

The output is identical with Flang 23. With gfortran 15 and earlier, split does not exist, and the build stops with an error about an undefined subroutine, so a library that must support older gfortran releases should keep its own tokenizer.

The second program uses a conditional expression, a Fortran 2023 form ( condition ? value : condition ? value : value ) that selects one of several values, and evaluates only the chosen one. Here it chooses the time step of the explicit (forward-time, centred-space) heat scheme: a request of zero or less means "use the stability limit", a request above the limit is clamped to it, and anything else is accepted. The stability limit of the scheme on a grid of spacing dx by dy is computed by stable_dt in the code. Before Fortran 2023 this took a function with an if chain, or a combination of merge and an extra evaluation of both branches.

module heatflow_kinds
  use, intrinsic :: iso_fortran_env, only: real64
  implicit none
  private
  public :: dp
  integer, parameter :: dp = real64
end module heatflow_kinds

module heatflow_timestep
  use heatflow_kinds, only: dp
  implicit none
  private
  public :: stable_dt, clamp_dt, describe
contains
  ! Largest time step the explicit FTCS scheme allows on a dx-by-dy grid.
  pure function stable_dt(alpha, dx, dy) result(dt)
    real(dp), intent(in) :: alpha, dx, dy
    real(dp) :: dt
    dt = 0.5_dp * (dx * dx * dy * dy) / (alpha * (dx * dx + dy * dy))
  end function stable_dt

  ! Fortran 2023 conditional expression: a value chosen by a chain of tests.
  pure function clamp_dt(requested, alpha, dx, dy) result(dt)
    real(dp), intent(in) :: requested, alpha, dx, dy
    real(dp) :: dt
    dt = (requested <= 0.0_dp ? stable_dt(alpha, dx, dy) &
        : requested > stable_dt(alpha, dx, dy) ? stable_dt(alpha, dx, dy) &
        : requested)
  end function clamp_dt

  pure function describe(dt, limit) result(text)
    real(dp), intent(in) :: dt, limit
    character(len=:), allocatable :: text
    text = (dt >= limit ? 'at the stability limit' : 'below the stability limit')
  end function describe
end module heatflow_timestep

program conditional_expression
  use heatflow_kinds, only: dp
  use heatflow_timestep, only: stable_dt, clamp_dt, describe
  implicit none
  real(dp), parameter :: alpha = 0.01_dp, dx = 0.1_dp, dy = 0.1_dp
  real(dp) :: limit, requested(3), dt
  integer :: k

  limit = stable_dt(alpha, dx, dy)
  requested = [0.0_dp, 0.1_dp, 0.5_dp * limit]
  print '(a,es10.3)', 'stability limit = ', limit
  do k = 1, size(requested)
    dt = clamp_dt(requested(k), alpha, dx, dy)
    print '(a,es10.3,a,es10.3,2a)', 'requested ', requested(k), ' -> dt ', dt, &
      ': ', describe(dt, limit)
  end do
end program conditional_expression
stability limit =  2.500E-01
requested  0.000E+00 -> dt  2.500E-01: at the stability limit
requested  1.000E-01 -> dt  1.000E-01: below the stability limit
requested  1.250E-01 -> dt  1.250E-01: below the stability limit

Both gfortran 16.2 and Flang 23 give this output. The conditional argument form, call sub(x, (flag ? y : .nil.)), which passes an absent optional argument when the condition is false, was rejected by both compilers in the probes, so this section does not use it. Conditional expressions are described fully on Expressions and Assignment.

The last program prints the kind constants that Fortran 2023 added to iso_fortran_env (logical8 to logical64, real16) together with selected_logical_kind. Run it with both compilers and the two answers for real16 differ, which is a correct demonstration that the values of kind constants are processor dependent and that a negative value is a legal answer.

program kind_constants
  use, intrinsic :: iso_fortran_env, only: logical8, logical16, logical32, logical64, &
                                           real16, real32, real64, real128
  implicit none
  print '(a,4(1x,i0))', 'logical kinds 8/16/32/64:', logical8, logical16, logical32, logical64
  print '(a,4(1x,i0))', 'real kinds 16/32/64/128: ', real16, real32, real64, real128
  print '(a,i0)', 'selected_logical_kind(16) = ', selected_logical_kind(16)
  print '(a,i0)', 'selected_logical_kind(8)  = ', selected_logical_kind(8)
end program kind_constants

gfortran 16.2 (aarch64):

logical kinds 8/16/32/64: 1 2 4 8
real kinds 16/32/64/128:  -2 4 8 16
selected_logical_kind(16) = 2
selected_logical_kind(8)  = 1

LLVM Flang 23 (aarch64):

logical kinds 8/16/32/64: 1 2 4 8
real kinds 16/32/64/128:  2 4 8 16
selected_logical_kind(16) = 2
selected_logical_kind(8)  = 1

Fortran 2028 in brief

Fortran 2028 (formerly "F202Y") is the next revision. On the check date WG5 lists the Committee Draft (N2258) as not a public document, and the latest public working draft is J3/26-007r1. The stage and the ballot outcome are therefore not documented publicly here, and this section describes Fortran 2028 only as "upcoming". The main item is templates: a new clause for parameterized generic programming with requirements, instantiation and generic subprograms. The Fortran 2023 text of this section is the stable baseline; What’s New and Fortran 2028 Preview lists the 2028 work items. Compilers expose proposed features of the next revision through -std=f202y (gfortran), which changes between releases.

Where the books are outdated

The book Modern Fortran Explained: Incorporating Fortran 2023 covers the standards in its first chapter and is current for the language itself. What it cannot give is what happened afterwards, and what compilers do:

  • It gives no ISO number or publication date for Fortran 2023 (ISO/IEC 1539-1:2023, November 2023), and does not know Corrigendum 1 (2026).

  • It speaks of templates only as a future direction. Fortran 2028 is now at Committee Draft stage with templates and generic subprograms in the working draft.

  • It contains no compiler-support information, and its only compiler version string is an old NAG release. The table above replaces that gap for gfortran, Flang, ifx, NAG and Cray.

  • It cites IEEE 754-2008 and ISO/IEC/IEEE 60559:2011 for floating-point arithmetic. Fortran 2023 adopts ISO/IEC 60559:2020 (IEEE 754-2019); see Floating-Point and IEEE Arithmetic.

  • Its Appendix A lists the authors' recommended deprecations, which are not the standard’s obsolescent or deleted lists; the standard’s own lists are the ones summarized above and in Annex B.

  • It mentions only make for the recompilation problem; the tools used today are described on Building with Make, CMake and Meson and Fortran Package Manager (fpm).

Common pitfalls

  • Trusting the default compiler mode. gfortran’s default -std=gnu accepts extensions silently and the deleted features with only a warning. A program that compiles by default is not necessarily conforming. Add -std=f2023 -Wall -Wextra -pedantic in development.

  • Using a Fortran 2023 feature without checking the oldest compiler you support. The last two rows of the table are the usual traps: an intrinsic that exists in the compiler manual but is missing from its library (tokenize, c_f_strpointer in gfortran 16.2), and a feature accepted by one compiler and rejected by another. Test with a link and a run, not only a syntax check.

  • Reading a status page as a promise. The fortran-lang compilers page and a compiler’s status page can lag the compiler you installed, in either direction.

  • Citing a draft as the standard. J3/23-007r1 is the free final draft; for formal citation use ISO/IEC 1539-1:2023 and its Corrigendum 1:2026.

  • Equating "obsolescent" with "unsupported". Obsolescent and deleted features still compile on most processors; the standard only requires that the processor can report them. Do not rely on that for new code.

  • Assuming kind values are portable. real16 was -2 with gfortran and 2 with Flang in the example above. Use selected_real_kind and selected_logical_kind, or the iso_fortran_env constants with a check that they are positive.