Control Flow

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 page is written against Fortran 2023 (ISO/IEC 1539-1:2023, J3/23-007r1) and was checked on 2026-10-18. Every example was compiled warning-free with gfortran -std=f2023 -Wall -Wextra -pedantic -fimplicit-none -fcheck=all (GNU Fortran 16.2) and run, and most also with LLVM Flang 23; the output shown is real output. Examples that are deliberately wrong or that deliberately trigger a diagnostic are labelled as such. Execution control is defined in clause 11 of the standard ("Execution control"): 11.1 covers the constructs that contain blocks, 11.2 branching, 11.3 continue and 11.4 stop and error stop.

Fortran has no braces and no indentation rules: every block statement is closed by an explicit end statement (end if, end do, end select), which makes the structure unambiguous and lets you repeat the construct name for checking. There is no while or for keyword; both are spellings of do. The boolean operators are in Expressions and Assignment; procedures, which also transfer control, in Procedures, Functions and Subroutines. Readers coming from C will find the corresponding statements in C Control Flow and from Rust in Rust Control Flow; the differences that matter are called out below.

Construct Purpose Standard clause (J3/23-007r1)

if construct and statement

two-way and multi-way branching on logical expressions

11.1.8

select case

multi-way branching on an integer, character or logical value

11.1.9

do, do while, do without control

iteration; exit and cycle steer it

11.1.7, 11.1.12

block

executable region with its own declarations

11.1.4

associate

temporary names for expressions and long designators

11.1.3

select type

branch on the dynamic type of a polymorphic object

11.1.11

select rank

branch on the rank of an assumed-rank dummy

11.1.10

stop, error stop

terminate execution

11.4

go to, computed go to, continue

unstructured branching (legacy)

11.2, 11.3

The if construct and the if statement

An if construct (11.1.8) has a then after the condition, any number of else if (...) then branches, an optional else, and an end if. The conditions are scalar logical expressions; there is no implicit conversion from integers or reals, so if (n) is a compile-time error. The if statement is the single-line form: a condition followed by one action statement, with no then and no end if. The action cannot be another if statement or a block-opening statement. An if construct may carry a name, and when it does the name must be repeated on end if and on every else if and else keyword of that construct (else check).

The expression in an else if is evaluated only when every earlier condition was false. Within one expression, however, the standard does not require short-circuit evaluation: a .and. b may evaluate b even when a is false, and a processor may evaluate mathematically equivalent forms. The last statement of the example below is therefore guarded only by luck; the safe pattern is a nested if or, since Fortran 2023, a conditional expression (see below).

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

program if_demo
  use heatflow_kinds, only: dp
  implicit none
  real(dp) :: residual, tolerance
  integer :: step, max_steps
  character(len=*), parameter :: fmt = '(a, i0, a, es9.2)'

  tolerance = 1.0e-3_dp
  max_steps = 2000
  residual = 5.0e-4_dp
  step = 120

  ! if construct with else if / else
  if (residual < tolerance) then
    print fmt, 'converged at step ', step, ', residual ', residual
  else if (step >= max_steps) then
    print '(a)', 'step budget exhausted'
  else
    print '(a)', 'keep iterating'
  end if

  ! if statement: one action statement, no then / end if
  if (step > max_steps) stop 1

  ! named if construct; the name must be repeated on every branch keyword
  check: if (residual < 0.0_dp) then
    print '(a)', 'impossible: a residual is a norm'
  else check
    print '(a)', 'residual is non-negative'
  end if check

  ! .and. / .or. do not short circuit: both operands may be evaluated
  if (step >= 1 .and. residual / real(step, dp) < tolerance) print '(a)', 'ratio below tolerance'
end program if_demo

Output:

converged at step 120, residual  5.00E-04
residual is non-negative
ratio below tolerance

select case

select case (selector) (11.1.9) compares one scalar value against lists of constant values. The selector must be integer, character or logical; real selectors are not allowed. Each case takes a parenthesised list of values or ranges; a range is low:high, :high (everything up to and including high) or low: (everything from low). The case values must be constant expressions of the same type as the selector (for character, the kind must match, the length may differ), and the lists of all cases must not overlap. Exactly zero or one case is selected; there is no fall through and no break, so each case block ends where the next case begins. case default handles every remaining value and may appear anywhere, although putting it last reads best. Without a case default, an unmatched selector value simply skips the whole construct, so a function that assigns its result inside the cases would return an undefined result; grade therefore ends with a default for the lengths between its listed values.

character selectors are compared as if the shorter operand were padded with blanks, so 'go ' matches 'go'. Ranges use the collating sequence of the character kind. Because enum, bind(c) enumerators (see Enumerations) are named integer constants, they work directly as case values, as bc_names does for the heatflow boundary conditions. The F2023 enumeration type statement is not accepted by GNU Fortran 16.2 or, by default, LLVM Flang 23, so it is not used in the examples.

module bc_names
  implicit none
  private
  public :: dirichlet, neumann, periodic, describe, grade, command_kind

  enum, bind(c)
    enumerator :: dirichlet = 1, neumann = 2, periodic = 3
  end enum

contains

  function describe(bc) result(text)
    integer, intent(in) :: bc
    character(len=:), allocatable :: text

    select case (bc)
    case (dirichlet)
      text = 'fixed temperature'
    case (neumann)
      text = 'fixed flux'
    case (periodic)
      text = 'wrap around'
    case default
      text = 'unknown'
    end select
  end function describe

  ! ranges: low:high, :high and low: are all allowed for integer, character and logical selectors
  function grade(steps) result(text)
    integer, intent(in) :: steps
    character(len=:), allocatable :: text

    select case (steps)
    case (:0)
      text = 'nothing to do'
    case (1:99)
      text = 'short run'
    case (100, 200, 300:999)
      text = 'medium run'
    case (1000:)
      text = 'long run'
    case default
      text = 'odd length'
    end select
  end function grade

  ! character selector: compared as if the shorter value were padded with blanks
  function command_kind(word) result(kind)
    character(len=*), intent(in) :: word
    integer :: kind

    select case (word)
    case ('run', 'go')
      kind = 1
    case ('a':'f')
      kind = 2
    case default
      kind = 0
    end select
  end function command_kind

end module bc_names

program select_demo
  use bc_names
  implicit none
  integer :: i
  integer, parameter :: probes(5) = [-3, 5, 150, 200, 4000]

  do i = 1, 3
    print '(i0, 2a)', i, ': ', describe(i)
  end do
  print '(2a)', '9: ', describe(9)
  do i = 1, size(probes)
    print '(i0, 2a)', probes(i), ' -> ', grade(probes(i))
  end do
  print '(*(i0, 1x))', command_kind('run'), command_kind('go  '), command_kind('cat'), command_kind('zeta')
end program select_demo

Output:

1: fixed temperature
2: fixed flux
3: wrap around
9: unknown
-3 -> nothing to do
5 -> short run
150 -> odd length
200 -> medium run
4000 -> long run
1 1 2 0

The overlap rule is checked at compile time. Replacing 'a':'f' by 'a':'m' in command_kind is rejected by gfortran, because 'go' falls inside that range (this fragment was compiled to obtain the message, it is not one of the runnable examples above):

Error: CASE label at (1) overlaps with CASE label at (2)

The do construct

All iteration is do (11.1.7), in three spellings.

  • Counted — do i = first, last [, step]. The three expressions are evaluated once, before the loop starts. The number of iterations is max(0, (last - first + step) / step) using integer division, and it is fixed at that point; changing a variable that appears in last or step inside the body does not change the count. step defaults to 1 and must not be zero.

  • do while (condition) — the condition is tested before every pass, including the first.

  • Unbounded — do with no control; it runs until an exit, a return, a stop, or a branch out. Use it for loops that test their condition in the middle or at the end (a "repeat until" loop).

The do variable is an ordinary scalar integer variable that must not be redefined by the body; assigning it is a compile-time error (see the error example below). Fortran has no loop-local scope for it, so the variable survives the loop and holds the value the standard defines: first + iterations * step, which is one step beyond the last executed value (13 in the example, not 10). After a zero-trip loop it holds first, because it is assigned before the trip count is tested. Real and double precision do variables were deleted from the language long ago (Fortran 95), so the book-era idiom do x = 0.0, 1.0, 0.1 no longer compiles with -std=f2023; loop over an integer index and compute the real value.

exit leaves the innermost do (or, with a name, the named one); cycle abandons the current pass and goes to the next iteration test. Both apply only to do constructs, apart from the named exit described next.

program do_demo
  implicit none
  integer :: i, n, count_down, lo, hi
  real :: total

  ! counted loop: iteration count = max(0, (end - start + step) / step), fixed before the first pass
  do i = 1, 10, 3
    write (*, '(i0, 1x)', advance='no') i
  end do
  print '(a, i0)', ' | i after the loop = ', i

  ! zero-trip loop: the body never runs and i is still assigned the start value
  lo = 5; hi = 1
  do i = lo, hi
    print '(a)', 'never printed'
  end do
  print '(a, i0)', 'i after a zero-trip loop = ', i

  ! decreasing loop needs a negative stride
  do count_down = 3, 1, -1
    write (*, '(i0, 1x)', advance='no') count_down
  end do
  print '(a)', 'liftoff'

  ! the end expression is evaluated once: changing n inside has no effect on the trip count
  n = 3
  total = 0.0
  do i = 1, n
    n = 100
    total = total + 1.0
  end do
  print '(a, f4.1, a, i0)', 'iterations = ', total, ', n = ', n

  ! do while and unbounded do with exit / cycle
  n = 1
  do while (n < 50)
    n = n * 2
  end do
  print '(a, i0)', 'first power of two >= 50 = ', n

  n = 0
  do
    n = n + 1
    if (mod(n, 2) == 0) cycle
    if (n > 7) exit
    write (*, '(i0, 1x)', advance='no') n
  end do
  print '(a, i0)', '| left with n = ', n
end program do_demo

Output:

1 4 7 10  | i after the loop = 13
i after a zero-trip loop = 5
3 2 1 liftoff
iterations =  3.0, n = 100
first power of two >= 50 = 64
1 3 5 7 | left with n = 9

Compiled with -Wall the zero-trip case warns about a loop that "will be executed zero times" if both bounds are literal constants (-Wzerotrip, enabled by -Wall); the example uses variables so the demonstration is warning-free.

Construct names, exit and cycle

Every if, select case, do, block, associate, select type, select rank, critical and change team construct can be given a name: name: do ... …​ end do name. The name is an identifier in the construct’s scoping unit and must be repeated on the closing statement (and, for if, on else if and else; for select case, an optional matching name may follow each case selector). Names let exit and cycle address an outer loop, which replaces the usual go to or flag variable for breaking out of nested loops.

Since Fortran 2008, exit construct-name is not limited to do: it can leave a named block, if, select case or other construct (11.1.12). This is the structured replacement for jumping to a label at the end of a region. cycle still needs a do construct.

program named_exit_demo
  use, intrinsic :: iso_fortran_env, only: real64
  implicit none
  integer, parameter :: dp = real64
  integer, parameter :: nx = 4, ny = 3
  real(dp) :: u(nx, ny)
  integer :: i, j

  u = 0.0_dp
  u(3, 2) = -1.0_dp   ! a nonphysical negative temperature

  ! exit and cycle accept a construct name: leave / continue the outer loop from the inner one
  scan: do j = 1, ny
    row: do i = 1, nx
      if (abs(u(i, j)) <= 0.0_dp) cycle row
      print '(a, i0, a, i0, a)', 'nonzero at (', i, ', ', j, ')'
      exit scan
    end do row
  end do scan
  print '(a, 2(i0, 1x))', 'stopped at i, j = ', i, j

  ! F2008: exit works on any named construct, not only on do
  validate: block
    if (any(u < 0.0_dp)) exit validate
    print '(a)', 'all temperatures valid'   ! skipped here
  end block validate

  pick: select case (nx)
  case (4)
    if (ny == 3) exit pick
    print '(a)', 'not reached'
  case default
    print '(a)', 'not reached either'
  end select pick

  check: if (nx > 0) then
    if (any(u < 0.0_dp)) exit check
    print '(a)', 'also skipped'
  end if check
  print '(a)', 'done'
end program named_exit_demo

Output:

nonzero at (3, 2)
stopped at i, j = 3 2
done

An unnamed exit or cycle must lie inside a do. The next two programs are deliberately non-conforming and were compiled only to capture the diagnostics.

! INTENTIONALLY NON-CONFORMING: the do variable is redefined inside its own loop.
program bad_do_variable
  implicit none
  integer :: i
  do i = 1, 3
    i = i + 1
  end do
end program bad_do_variable
09a_bad_do_variable.f90:6:13:

    5 |   do i = 1, 3
      |             2
    6 |     i = i + 1
      |             1
Error: Variable 'i' at (1) cannot be redefined inside loop beginning at (2)
! INTENTIONALLY NON-CONFORMING: exit and cycle outside the constructs they need.
program bad_exit
  implicit none
  integer :: i
  i = 1
  if (i > 3) exit
  cycle
end program bad_exit
09b_bad_exit.f90:6:17:

    6 |   if (i > 3) exit
      |                 1
Error: EXIT statement at (1) is not within a construct
09b_bad_exit.f90:7:7:

    7 |   cycle
      |       1
Error: CYCLE statement at (1) is not within a construct

block and associate

block (11.1.4) opens an executable region that may begin with specification statements. Variables declared inside are local to it, created when the block is entered and gone at end block, including automatic arrays whose bounds depend on runtime values. Use it to keep a temporary next to its single use, to give exit something to leave, or to declare allocatable variables that are deallocated automatically on exit. The specification part of a block has restrictions (for example it cannot contain an implicit statement), and a branch from outside into a block is not allowed.

associate (11.1.3) gives names to expressions or designators for the duration of the construct. If the selector is a variable (g%u, g%u(3, 2)), the associate-name is another name for that variable and may be assigned to; if it is an expression (sum(g%u)), the name is read-only. The associate-name takes its type, kind, rank and shape from the selector, and inherits its target, asynchronous and volatile attributes. It is the Fortran replacement for the classic pointer alias (p => g%u(3, 2)): there is no pointer involved, nothing can dangle, the compiler knows nothing else is changed through it, and the name disappears at end associate. The selector is evaluated once, on entry. associate is also what makes long derived-type chains readable in numeric kernels.

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

module grid_mod
  use heatflow_kinds, only: dp
  implicit none
  private
  public :: grid_t

  type :: grid_t
    integer :: nx = 0, ny = 0
    real(dp) :: dx = 0, dy = 0
    real(dp), allocatable :: u(:, :)
  end type grid_t
end module grid_mod

program block_associate_demo
  use heatflow_kinds, only: dp
  use grid_mod, only: grid_t
  implicit none
  type(grid_t) :: g
  integer :: i

  g%nx = 5; g%ny = 4; g%dx = 0.25_dp; g%dy = 0.5_dp
  allocate (g%u(g%nx, g%ny), source=20.0_dp)
  g%u(3, 2) = 100.0_dp

  ! associate: names for expressions or long designators, valid only inside the construct
  associate (u => g%u, hx => g%dx, hy => g%dy, centre => g%u(3, 2))
    print '(a, f6.3)', 'dx*dy        = ', hx * hy
    print '(a, f6.1)', 'centre       = ', centre
    centre = 90.0_dp            ! a variable selector is definable through its associate-name
    u(1, 1) = 0.0_dp
  end associate
  print '(a, 2f6.1)', 'modified via associate: ', g%u(3, 2), g%u(1, 1)

  ! an expression selector is an expression value: it cannot be assigned to
  associate (total => sum(g%u))
    print '(a, f8.1)', 'sum          = ', total
  end associate

  ! block: local declarations with a limited scope
  do i = 1, 2
    block
      real(dp) :: scratch(g%nx)       ! automatic, sized when the block is entered
      integer :: k
      scratch = [(real(k, dp) * real(i, dp), k = 1, g%nx)]
      print '(a, i0, a, f5.1)', 'pass ', i, ': sum(scratch) = ', sum(scratch)
    end block
  end do
end program block_associate_demo

Output:

dx*dy        =  0.125
centre       =  100.0
modified via associate:   90.0   0.0
sum          =    450.0
pass 1: sum(scratch) =  15.0
pass 2: sum(scratch) =  30.0

select type and select rank (preview)

select type (11.1.11) tests the dynamic type of a class(...) selector and gives each branch a correctly typed view. type is (t) matches the exact type, class is (t) matches t or any extension (the most specific such branch wins), and class default catches the rest. Inside a type is branch the associate-name is not polymorphic and the components of that type are accessible; the construct needs the selector to be class(...). select type belongs to the object-oriented material, which is developed in Object Oriented Programming and Type-Bound Procedures, Abstract Types and Finalization.

select rank (11.1.10, Fortran 2018) does the same for the rank of an assumed-rank dummy argument declared with dimension(..). The branches are rank (n), rank (*) for an assumed-size array, and rank default. Assumed-rank and select rank are used mainly to write one wrapper for every rank, especially for C interoperability; see Array Arguments: Assumed Shape, Size and Rank and Generic and Rank Independent Programming.

module shapes
  use, intrinsic :: iso_fortran_env, only: real64
  implicit none
  private
  public :: solver_t, jacobi_t, ftcs_t, name_of, rank_of

  type, abstract :: solver_t
    integer :: steps = 0
  end type solver_t
  type, extends(solver_t) :: jacobi_t
  end type jacobi_t
  type, extends(solver_t) :: ftcs_t
    real(real64) :: alpha = 1.0_real64
  end type ftcs_t

contains

  function name_of(s) result(text)
    class(solver_t), intent(in) :: s
    character(len=:), allocatable :: text
    select type (s)
    type is (jacobi_t)
      text = 'jacobi'
    class is (ftcs_t)
      text = 'ftcs, alpha=' // trim(adjustl(real_text(s%alpha)))
    class default
      text = 'unknown solver'
    end select
  end function name_of

  function real_text(x) result(t)
    real(real64), intent(in) :: x
    character(len=16) :: t
    write (t, '(f4.2)') x
  end function real_text

  function rank_of(a) result(text)
    real(real64), intent(in) :: a(..)
    character(len=:), allocatable :: text
    select rank (a)
    rank (0)
      text = 'scalar'
    rank (1)
      text = 'vector of ' // trim(adjustl(int_text(size(a))))
    rank (2)
      text = 'matrix ' // trim(adjustl(int_text(size(a, 1)))) // 'x' // trim(adjustl(int_text(size(a, 2))))
    rank default
      text = 'rank > 2'
    end select
  end function rank_of

  function int_text(n) result(t)
    integer, intent(in) :: n
    character(len=12) :: t
    write (t, '(i0)') n
  end function int_text
end module shapes

program select_type_demo
  use, intrinsic :: iso_fortran_env, only: real64
  use shapes
  implicit none
  class(solver_t), allocatable :: s
  real(real64) :: m(3, 2) = 0.0_real64, v(4) = 0.0_real64

  allocate (jacobi_t :: s)
  print '(2a)', 'solver: ', name_of(s)
  deallocate (s)
  allocate (ftcs_t :: s)
  select type (s)
  type is (ftcs_t)
    s%alpha = 0.25_real64
  end select
  print '(2a)', 'solver: ', name_of(s)
  print '(*(a, :, "; "))', rank_of(1.0_real64), rank_of(v), rank_of(m)
end program select_type_demo

Output:

solver: jacobi
solver: ftcs, alpha=0.25
scalar; vector of 4; matrix 3x2

Conditional expressions (Fortran 2023)

Fortran 2023 adds the conditional expression ( condition ? value-if-true : value-if-false ). Only the selected branch is evaluated, so it gives a standard way to write a guarded division or a guarded array access in a single expression, something .and. alone cannot promise. The surrounding parentheses are part of the syntax. GNU Fortran 16.2 and LLVM Flang 23 both accepted the example below (gfortran in strict -std=f2023 mode); other compilers may not support it yet, see Compilers and Compiler Options. The syntax and the operator rules are described on Expressions and Assignment.

program cond_expr
  use, intrinsic :: iso_fortran_env, only: real64
  implicit none
  integer, parameter :: dp = real64
  real(dp) :: residual, rate
  integer :: step

  residual = 2.0e-3_dp
  do step = 0, 2
    ! only the selected branch is evaluated, so step = 0 never divides by zero
    rate = (step > 0 ? residual / real(step, dp) : 0.0_dp)
    print '(a, i0, a, es9.2)', 'step ', step, ': rate = ', rate
  end do
end program cond_expr

Output:

step 0: rate =  0.00E+00
step 1: rate =  2.00E-03
step 2: rate =  1.00E-03

stop and error stop

stop (11.4) ends the program normally from anywhere, including from inside a procedure; error stop ends it as an error termination. Both accept an optional stop code, either a scalar integer or a scalar default-character expression. Without a code stop yields exit status 0 and prints nothing, and error stop yields a non-zero status. A character code is written to the error unit; an integer code is written as STOP n and, on the tested platform, becomes the process exit status. The meaning of the exit status is processor-dependent. Fortran 2018 added the optional quiet= specifier (a scalar logical): when true, the processor does not print the stop code or the error-termination report, but the termination is still an error stop. error stop may also appear in a pure procedure, which stop may not. In a program that uses images, stop stops that image normally and error stop makes all images terminate; see Error Handling and Program Termination and Coarrays, Images and Synchronization.

program stop_demo
  implicit none
  integer :: mode
  character(len=8) :: arg

  mode = 0
  if (command_argument_count() >= 1) then
    call get_command_argument(1, arg)
    read (arg, *) mode
  end if

  select case (mode)
  case (0)
    print '(a)', 'normal end'
  case (1)
    stop                       ! exit status 0, no message
  case (2)
    stop 'finished early'      ! message to stderr, exit status 0
  case (3)
    stop 7                     ! stop code is also the exit status on most systems
  case (4)
    error stop 'solver diverged'   ! exit status non-zero, error termination
  case (5)
    error stop 3, quiet=.true.     ! F2018: quiet= suppresses the termination report
  end select
end program stop_demo

Running it with the mode as a command-line argument, compiled with -fno-backtrace to keep the report short, gave:

$ ./stop_demo 0
normal end
exit status 0
$ ./stop_demo 1
exit status 0
$ ./stop_demo 2
STOP finished early
exit status 0
$ ./stop_demo 3
STOP 7
exit status 7
$ ./stop_demo 4
ERROR STOP solver diverged
exit status 1
$ ./stop_demo 5
exit status 3

By default gfortran also prints a backtrace after Error termination. for error stop; -fno-backtrace removes it and the exit status is the same.

continue and go to: recognition only

Old code expresses control flow with labels. continue (11.3) does nothing and exists to carry a label. go to label (11.2.2) branches unconditionally; the target must be an executable statement in the same scoping unit, and a branch into a construct from outside is not allowed. The computed go to (l1, l2, ...) expr (11.2.3) selects a label by an integer and is obsolescent: gfortran warns about it, as the compile output below shows, and select case replaces it. The arithmetic if (if (x) 10, 20, 30) and the nonblock do, in which several loops share a labelled terminal statement or end on a statement other than end do or continue, were deleted in Fortran 2018 and no longer compile under -std=f2023; both are covered, with their rewrites, on Legacy Features and Modernization. New code should use do while, exit, cycle and select case, which compile to the same jumps but state intent.

The example compiles in Fortran 2023 mode, with the one warning that the labelled form earns; that warning is expected and shown below.

! Recognition only: legacy-style control flow that still compiles in Fortran 2023.
program legacy_flow
  implicit none
  integer :: i, total
  integer :: choice

  total = 0
  i = 0
10 continue                  ! labelled continue: a branch target
  i = i + 1
  total = total + i
  if (i < 5) go to 10        ! a backward go to is a hand-made loop
  print '(a, i0)', 'total = ', total

  choice = 2
  go to (20, 30) choice      ! computed go to: obsolescent
20 print '(a)', 'label 20'
  go to 40
30 print '(a)', 'label 30'
40 continue
end program legacy_flow

Compiler output (a warning, not an error) and run output:

08_goto.f90:16:58:

   16 |   go to (20, 30) choice      ! computed go to: obsolescent
      |                                                          1
Warning: Obsolescent feature: Computed GOTO at (1)
total = 15
label 30

Where the books are outdated

The books on the reference list predate Fortran 2023 and do not describe the conditional expression, which is now a standard way to guard evaluation. Their control-flow examples may also use constructs that the standard has since removed or that GNU Fortran flags with -std=f2023: real do variables, shared or nonblock do terminators and the arithmetic if. Use the structured forms shown here instead (integer do variable, end do, select case). Where a book states that exit and cycle apply only to do, remember that exit may name any construct since Fortran 2008. Statements such as pause and assigned go to are gone entirely (Fortran 95).