|
| 1 | +# PWR083: Match dummy and actual argument types in procedure calls |
| 2 | + |
| 3 | +### Issue |
| 4 | + |
| 5 | +Calling a procedure with actual arguments that are incompatible with the |
| 6 | +characteristics of the procedure's dummy arguments (e.g., different `type`, |
| 7 | +`kind`, `rank`, etc.) can lead to compilation failures or, if not caught, |
| 8 | +undefined behavior at runtime. |
| 9 | + |
| 10 | +### Actions |
| 11 | + |
| 12 | +Ensure the arguments supplied at the call site match the characteristics of the |
| 13 | +procedure's dummy arguments. Depending on the situation, this may involve |
| 14 | +actions such as: |
| 15 | + |
| 16 | +- Changing the `type` and/or `kind` of the actual argument declarations. |
| 17 | +- Applying explicit type conversions (e.g., `int(...)`, `real(...)`). |
| 18 | +- Providing alternative procedure implementations for different argument types. |
| 19 | + |
| 20 | +Also verify that arguments are passed in the intended order; a type mismatch |
| 21 | +can be caused by accidentally swapping argument positions. |
| 22 | + |
| 23 | +### Relevance |
| 24 | + |
| 25 | +When calling a Fortran procedure, actual and dummy arguments are expected to |
| 26 | +have compatible characteristics (`type`, `kind`, `rank`, etc.). A common |
| 27 | +mistake is to inadvertently mix numeric types; for example: |
| 28 | + |
| 29 | +- Passing a `real` where an `integer` is expected. |
| 30 | +- Using the wrong `kind` (e.g., `real32` instead of `real64`). |
| 31 | + |
| 32 | +When an explicit procedure interface is available at the call site, compilers |
| 33 | +can typically catch and report type mismatch issues during compilation. |
| 34 | + |
| 35 | +However, Fortran also allows calling procedures without information about the |
| 36 | +expected arguments; in such cases, an _implicit interface_ is used. The caller |
| 37 | +effectively passes a list of memory addresses, which the called procedure |
| 38 | +interprets according to its dummy argument declarations. If the actual |
| 39 | +arguments do not match the dummy arguments, the result is undefined behavior |
| 40 | +and may manifest as incorrect results, "random" behavior, or even crashes. |
| 41 | + |
| 42 | +> [!TIP] |
| 43 | +> To enhance code safety and reliability, ensure procedures provide |
| 44 | +> explicit interfaces to their callers. Check the [PWR068 entry](../PWR068/) |
| 45 | +> for more details! |
| 46 | +
|
| 47 | +### Code examples |
| 48 | + |
| 49 | +The following example advances a simulation time using a step count |
| 50 | +`numberSteps`. The procedure expects an `integer` step count, but the caller |
| 51 | +accidentally provides a `real` value: |
| 52 | + |
| 53 | +```fortran {6} showLineNumbers |
| 54 | +! simulation.f90 |
| 55 | +pure subroutine updateSimulationTime(numberSteps, prevTime, newTime) |
| 56 | + use iso_fortran_env, only: real32 |
| 57 | + implicit none |
| 58 | +
|
| 59 | + integer, intent(in) :: numberSteps |
| 60 | + real(kind=real32), intent(in) :: prevTime |
| 61 | + real(kind=real32), intent(out) :: newTime |
| 62 | +
|
| 63 | + ! Each step is 0.1 seconds |
| 64 | + newTime = prevTime + numberSteps * 0.1_real32 |
| 65 | +end subroutine updateSimulationTime |
| 66 | +``` |
| 67 | + |
| 68 | +```fortran {6,7,12} showLineNumbers |
| 69 | +! example.f90 |
| 70 | +program call_with_type_mismatch |
| 71 | + use iso_fortran_env, only: real32 |
| 72 | + implicit none |
| 73 | +
|
| 74 | + external :: updateSimulationTime |
| 75 | + real(kind=real32) :: numberSteps, prevTime, newTime |
| 76 | +
|
| 77 | + numberSteps = 10 |
| 78 | + prevTime = 0.0 |
| 79 | +
|
| 80 | + call updateSimulationTime(numberSteps, prevTime, newTime) |
| 81 | + print *, "New time = ", newTime |
| 82 | +end program call_with_type_mismatch |
| 83 | +``` |
| 84 | + |
| 85 | +Because `updateSimulationTime()` is an `external` procedure defined in another |
| 86 | +source file, the call uses an implicit interface. Compilers will typically |
| 87 | +allow this program to compile despite the type mismatch, producing an incorrect |
| 88 | +result at runtime: |
| 89 | + |
| 90 | +```txt |
| 91 | +$ gfortran --version |
| 92 | +GNU Fortran (Ubuntu 13.3.0-6ubuntu2~24.04) 13.3.0 |
| 93 | +$ gfortran simulation.f90 example.f90 |
| 94 | +$ ./a.out |
| 95 | + New time = 109261624. |
| 96 | +``` |
| 97 | + |
| 98 | +A simple solution is to declare `numberSteps` using the type expected by the |
| 99 | +procedure: |
| 100 | + |
| 101 | +```fortran {7} showLineNumbers |
| 102 | +! solution.f90 |
| 103 | +program correct_call |
| 104 | + use iso_fortran_env, only: real32 |
| 105 | + implicit none |
| 106 | +
|
| 107 | + external :: updateSimulationTime |
| 108 | + integer :: numberSteps |
| 109 | + real(kind=real32) :: prevTime, newTime |
| 110 | +
|
| 111 | + numberSteps = 10 |
| 112 | + prevTime = 0.0 |
| 113 | +
|
| 114 | + call updateSimulationTime(numberSteps, prevTime, newTime) |
| 115 | + print *, "New time = ", newTime |
| 116 | +end program correct_call |
| 117 | +``` |
| 118 | + |
| 119 | +Now, the program will produce the correct result: |
| 120 | + |
| 121 | +```txt |
| 122 | +$ gfortran simulation.f90 solution.f90 |
| 123 | +$ ./a.out |
| 124 | + New time = 1.00000000 |
| 125 | +``` |
| 126 | + |
| 127 | +Ultimately, it is recommended to encapsulate all procedures within modules so |
| 128 | +that callers have explicit interfaces. This enables the compiler to verify the |
| 129 | +provided arguments against the actual dummy arguments, preventing |
| 130 | +difficult-to-diagnose runtime bugs. |
| 131 | + |
| 132 | +> [!TIP] |
| 133 | +> Check the [PWR068 entry](../PWR068/) for more details on implicit and |
| 134 | +> explicit interfaces! |
| 135 | +
|
| 136 | +### Related resources |
| 137 | + |
| 138 | +- [PWR083 |
| 139 | + examples](https://github.com/codee-com/open-catalog/tree/main/Checks/PWR083/) |
| 140 | + |
| 141 | +### References |
| 142 | + |
| 143 | +- ["Implicit |
| 144 | +Interfaces"](https://people.cs.vt.edu/~asandu/Courses/MTU/CS2911/fortran_notes/node44.html), |
| 145 | +Adrian Sandu. [last checked January 2026] |
| 146 | + |
| 147 | +- ["More on Implicit |
| 148 | +Interfaces"](https://people.cs.vt.edu/~asandu/Courses/MTU/CS2911/fortran_notes/node181.html), |
| 149 | +Adrian Sandu. [last checked January 2026] |
| 150 | + |
| 151 | +- ["Explicit |
| 152 | +Interfaces"](https://people.cs.vt.edu/~asandu/Courses/MTU/CS2911/fortran_notes/node182.html), |
| 153 | +Adrian Sandu. [last checked January 2026] |
| 154 | + |
| 155 | +- ["Doctor Fortran Gets |
| 156 | +Explicit!"](https://web.archive.org/web/20130803094211/http://software.intel.com/en-us/forums/topic/275071), |
| 157 | +Steve Lionel. [last checked January 2026] |
| 158 | + |
| 159 | +- ["Doctor Fortran Gets Explicit - Again! |
| 160 | +"](https://web.archive.org/web/20130113070703/http://software.intel.com/en-us/blogs/2012/01/05/doctor-fortran-gets-explicit-again), |
| 161 | +Steve Lionel. [last checked January 2026] |
0 commit comments