MSC01-F. Avoid using legacy or obsolescent Fortran constructs
Programmers shall avoid using features identified as "deleted" or "obsolescent" by the Fortran standard, as well as legacy constructs that reduce clarity, maintainability, or compiler optimization potential.
Modern Fortran standard classifies legacy features into two categories:
- Deleted features. Redundant or removed constructs that are no longer standard-conforming (e.g.,
PAUSE,ASSIGN). - Obsolescent features. Redundant constructs for which safer or clearer alternatives exist (e.g.,
COMMONblocks,EQUIVALENCE, ArithmeticIF).
Relying on these features increases the risk of errors, reduces portability, and can inhibit compiler optimizations.
Deleted Features
These constructs are no longer part of the Fortran standard and are not permitted in strictly conforming modern code:
- Non-block
DOloops (implicitDOwithoutEND DOorCONTINUE). - Arithmetic
IF. ASSIGNand assignedGO TOstatements.PAUSEstatement.Hedit descriptor.- Real and double precision
DOloop control variables. - Branching to
END IFfrom outside its block. - Assigned
FORMATspecifier.
Obsolescent Features
These constructs are still supported by many compilers for backward compatibility, but are considered outdated and should be replaced with modern alternatives:
- Control flow
- Alternate return (
CALL sub(arg, 10, 20, ...)with numerical labels embedded). - Computed
GOTOstatements. - Statement functions.
- Alternate return (
- Data and data sharing
COMMONblocks.EQUIVALENCEstatements.
- Program structure
ENTRYstatement for multiple entry points.BLOCK DATAprogram units.
- Looping and branching
- Labeled
DOloops (using numeric labels instead of structuredEND DO). FORALLconstruct and statement.
- Labeled
- Legacy syntax and definitions
- Specific names for intrinsic procedures that duplicate generic functionality (e.g.,
DSINvsSIN). DATAstatements interspersed within executable code (considered obsolescent; use initialization in declarations instead).- Assumed-length character functions (deprecated approach; prefer explicit length or modern procedures).
- Fixed source form (classic column-based formatting).
- The
CHARACTER*lengthdeclaration syntax.
- Specific names for intrinsic procedures that duplicate generic functionality (e.g.,
Noncompliant Code Example
The arithmetic IF statement branches to one of three labels depending on whether an expression is negative, zero, or positive. This construct, common in early Fortran, obscures the control flow and makes the code difficult to read and maintain
program arithmetic_if
implicit none
integer :: i, x(10)
i = 1
! Noncompliant: Labeled loop with Arithmetic IF
10 continue
x(i) = i * 10
i = i + 1
if (i - 11) 10, 20, 30
20 continue
print *, "Final X:", x
stop
30 continue
print *, "Error: out of bounds"
end program arithmetic_if
Compliant Solution
This compliant solution demonstrates a bounded DO loop accessing an array strictly within its declared limits. The loop iteration space matches the array bounds, ensuring no out-of-range subscripting occurs and preserving defined program behavior.
program compliant_arithmetic_if
implicit none
integer :: i, x(10)
! Compliant: Modern DO loop with block IF logic implicit in bounds
do i = 1, 10
x(i) = i * 10
end do
print *, "Final X:", x
end program compliant_arithmetic_if
Noncompliant Code Example
Alternate returns allow a subroutine to control the execution flow of the calling program by branching to labels passed as arguments. This is an obsolete feature that results in unstructured control flow.
subroutine check_status(val, *, *)
integer, intent(in) :: val
if (val < 0) return 1
if (val == 0) return 2
end subroutine check_status
program alternate_return
integer :: v = -1
! Noncompliant: Passing labels (*10, *20) as arguments
call check_status(v, *10, *20)
print *, "Positive"
goto 30
10 print * , "Negative"
goto 30
20 print *, "Zero"
30 continue
end program alternate_return
Compliant Solution
The compliant solution returns an integer status code, and the calling program uses a SELECT CASE construct to handle control flow. This decouples the subroutine from the caller's line numbers and keeps the control flow logic within the caller.
subroutine check_status(val, status)
integer, intent(in) :: val
integer, intent(out) :: status
if (val < 0) then
status = 1
else if (val == 0) then
status = 2
else
status = 0
end if
end subroutine check_status
program alternate_return
integer :: v = -1, code
call check_status(v, code)
! Compliant: Structured handling of return status
select case (code)
case (1)
print *, "Negative"
case (2)
print *, "Zero"
case default
print *, "Positive"
end select
end program alternate_return
Risk Assessment
Legacy constructs often rely on implicit behaviors (like storage association in EQUIVALENTE and COMMON ) or unstructured jumps ( GO TO , Arithmetic IF ). These features prevent modern compilers from performing rigorous type checking, vectorization, and parallelization. They also significantly increase the cognitive load required to maintain the software.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
| MSC01-F | Medium | likely | Medium | P12 | L1 |
Bibliography
| [ Intel Fortran Compiler ] |
Attachments:
button_arrow_left.png (image/png)
button_arrow_up.png (image/png)
button_arrow_right.png (image/png)


