Fortran Naming Conflicts in Practice: Code Samples and Compiler Behavior
This article is a follow-up to Understanding Naming Conflicts in Fortran: Program Names vs File Names. That article covered the theory. Here, we run actual code through two different compilers — gfortran and nvfortran — and compare what happens.
If you only read one section, make it this: the same code can compile fine on one compiler and fail on another. This is the core portability issue every Fortran developer runs into sooner or later.
Each test below is shown inline as a code block, and is also available as a standalone, runnable file in the examples/ folder, so you can compile and try these yourself without copy-pasting out of markdown.
Setup
Each test below uses its own file, and both compilers are recent versions:
$ gfortran --version
GNU Fortran (Ubuntu 15.2.0-16ubuntu1) 15.2.0
$ nvfortran --version
nvfortran 24.11-0 64-bit target on x86-64 Linux -tp haswell
Each test is compiled the same simple way, using its own file name:
gfortran <filename>.f90 -o <output_name>
nvfortran <filename>.f90 -o <output_name>
Test 1: A Variable With the Same Name as the Program
program test
character :: test
print*, "Test"
end program test
Runnable file: examples/test1_variable_vs_program_name.f90
Here, the program is called test, and inside it we also declare a variable called test. This is the kind of thing that looks harmless but touches a real rule in Fortran: a name can’t be reused for two different purposes in the same scope.
gfortran result:
test1_variable_vs_program_name.f90:13:19:
13 | character :: test
| 1
Error: Symbol 'test' at (1) cannot have a type
nvfortran result:
NVFORTRAN-S-0043-Illegal attempt to redefine subprogram or entry name test (test1_variable_vs_program_name.f90: 13)
0 inform, 0 warnings, 1 severes, 0 fatal for test
Both compilers reject this, though the error messages are worded differently. This is a genuine conflict, not a compiler quirk — the program name test and the variable name test collide inside the same program unit, and every standards-conforming compiler should catch it.
Note
When both compilers reject the same code, you can be confident it maybe a real language violation, not a portability gray area.
Test 2: A Module and a Program With the Same Name
module test
contains
! procedures
end module test
program test
print *, "Running simulation"
end program test
Runnable file: examples/test2_module_vs_program_name.f90
This is where things get interesting.
gfortran result:
12 | module test
| 2~~~
......
17 | program test
| 1
Error: Global name ‘test’ at (1) is already being used as a MODULE at (2)
nvfortran result:
$ ./test2
Running simulation
nvfortran compiles and runs this without complaint. gfortran refuses to build it at all.
This is a real divergence between compilers, and it’s a good example of why “it compiles on my machine” isn’t the same as “it’s correct code.” A module and a program share the same global namespace in Fortran, so reusing a name across them is risky even when one particular compiler happens to allow it.
Warning
Code that compiles under nvfortran but not gfortran (or vice versa) is not portable, even if it “works.” Treat compiler acceptance as a hint, not a guarantee of correctness.
Test 3: A Derived Type with the Same Name as the Variable
module classmodule
implicit none
type :: car
character(10) :: color
real :: fuel
end type car
contains
subroutine createcar(car, color, fuel)
type(car), intent(out) :: car
character(*), intent(in) :: color
real, intent(in) :: fuel
car%color = color
car%fuel = fuel
print*, color, fuel
end subroutine createcar
end module classmodule
program test
use classmodule
implicit none
type(car) :: mycar
call createcar(mycar, "red", 50.0)
end program test
Runnable file: examples/test3_type_vs_variable_name.f90
When Test 3 is compiled on its own with the car subroutine argument reusing the derived type name car as a variable name, gfortran raises a chain of errors:
test3_type_vs_variable_name.f90:22:12:
22 | type(car), intent(out) :: car
| 1
Error: Derived type ‘car’ at (1) is being used before it is defined
test3_type_vs_variable_name.f90:25:7:
25 | car%color = color
| 1
Error: Symbol ‘car’ at (1) has no IMPLICIT type
test3_type_vs_variable_name.f90:26:7:
26 | car%fuel = fuel
| 1
Error: Symbol ‘car’ at (1) has no IMPLICIT type
test3_type_vs_variable_name.f90:21:22:
21 | subroutine createcar(car, color, fuel)
| 1~~
Error: Symbol ‘car’ at (1) has no IMPLICIT type
test3_type_vs_variable_name.f90:33:7:
33 | use classmodule
| 1
Fatal Error: Cannot open module file ‘classmodule.mod’ for reading at (1): No such file or directory
compilation terminated.
nvfortran result:
$ ./test3
red 50.00000
Again, nvfortran accepts what gfortran rejects. The lesson is the same as Test 2: naming a variable identically to its own derived type is legal in some compilers’ interpretation and not in others.
Side-by-Side Comparison
Test |
Code Pattern |
gfortran |
nvfortran |
|---|---|---|---|
1 |
Variable name same as program name |
❌ Rejected |
❌ Rejected |
2 |
Module name same as program name |
❌ Rejected |
✅ Compiles and runs |
3 |
Variable name same as its derived type |
❌ Rejected |
✅ Compiles and runs |
The pattern here is worth remembering: conflicts within a single program unit (Test 1) are caught everywhere. Conflicts across separate units — module vs. program, type vs. variable — are where compilers start to disagree.
Why This Matters for Portability
If you’re writing code for your own use on a single machine, a compiler that quietly accepts a naming clash might feel like a convenience. But scientific and HPC codebases are rarely built with just one compiler forever. Code gets:
Ported to a new cluster with a different toolchain
Picked up by a collaborator using Intel’s
ifx/ifortRebuilt years later on a newer compiler version with stricter checks
A project that “just works” on nvfortran can fail outright the first time someone runs gfortran on it. That’s not a bug in either compiler — both are allowed some latitude in how strictly they enforce certain naming rules, and the Fortran standard doesn’t always spell out every case with total precision.
Tip
If you want code that survives a compiler switch, don’t rely on what your current compiler allows. Rely on what good naming practice avoids in the first place.
Practical Naming Guidelines (Recap)
Based on the tests above, a few concrete habits go a long way:
Never give a variable the same name as the program or module it lives in
Never give a module and a program the same name, even if your compiler allows it
Avoid naming a variable the same as its own derived type
When in doubt, test on more than one compiler before trusting that “it compiles” means “it’s correct”
These are small habits, but they’re the difference between code that only works for you and code that works for whoever inherits your project next.
Final Takeaway
Compiler behavior is not a substitute for understanding the Fortran standard. Two compilers can look at the same file and reach different verdicts, and when that happens, the safer compiler’s answer (usually the stricter one) is the one to trust. Testing across compilers early — even with something as small as the three cases above — can save a lot of debugging time later in a project’s life.
For the conceptual background behind these tests — what actually distinguishes a program name, a file name, and an executable name — see the companion article.