A lot of Fortran programmers take the “belt and suspenders” approach to coding, with explicit declarations of every attribute they want for a symbol. In general, this is good practice, especially when combined with IMPLICIT NONE to force you to say what you mean. But some programmers take this a bit too far and it gets them into trouble. Let’s look at some cases…
Department of Redundancy Department
This is an oldie but a goodie. If one declaration is good, two should be better, right? I’ve seen some programs come in with such things as:
Whatever possessed them to write this, I don’t know. In some cases, there isn’t even the excuse of one of the declarations coming from an INCLUDE file. So what’s wrong with this? The Fortran 2003 standard says:
C508 An entity shall not be explicitly given any attribute more than once in a scoping unit.
The C508 indicates that this is a “constraint” – a rule that must be followed in order for the program to be valid standard Fortran and which the compiler must have the ability to check. Some compilers will allow this redundant declaration (when not asked to check standards conformance), but Intel Fortran does not. We’ve had requests over the years to be more relaxed here, but we believe that such redundant declarations are more likely to be an unintentional error. For example, we sometimes see declaratioins such as the following:
where it seems clear that the programmer meant to declare X4 but slipped. We’d rather alert the programmer to the error than have it go undetected and possibly cause problems later.
Fortran 90 added several more “scopes” – nested contexts where symbols can be found. The “host scope” is the traditional Fortran 77 one which is within a given program unit (subroutine, function, program or BLOCK DATA construct). “use association” comes into play when you have a USE of a module, and the module has its own scope. “host association” is when one scope is contained within another, such as a module procedure or a contained procedure.
Here again, it’s possible to get into trouble by adding a declaration that doesn’t need to be there. Consider the following case:
module MYMOD implicit none contains integer function F1 (X) integer, intent(IN) :: X integer F2 F1 = F2(2*X) end function F1 integer function F2 (X) integer, intent(IN) :: X F2 = 3 * X end function F2 end module MYMOD
When this code is built into an application using version 11 of the Intel compiler, a link error is generated for the call to F2 from within F1; an error that did not happen with version 10.1. Compiler bug? No, a compiler bug fix – version 11 is correct.
The trouble-maker is the “redundant” declaration of F2 inside F1. Without that, F2 already has an explicit interface from host association – it is a module procedure in the same module. But if you then add a declaration of F2 inside F1, the language says that this is declaring a different, external procedure F2, which may or may not exist in the program.
The key part of the standard governing this is Fortran 2003 section 12.4.4, “Resolving named procedure references”. It is essentially an algorithm to follow to determine which F2 is meant when you have a reference to a procedure F2. If you follow the steps using the above example, you’ll find that you end up at 22.214.171.124(3) “the reference is to an external procedure with that name”.
This is not restricted to procedures, though. Consider the following:
module MYMOD2 integer X contains subroutine SUB integer X X = 3 …
If you are expecting the module variable X to be updated when SUB is called, you’ll be disappointed. In general, local declarations of a name hide host-associated declarations of the same name. But if you’re expecting that behavior for use association as well, think again…
module MYMOD3 integer X end module MYMOD3 subroutine SUB use MYMOD3 integer X ! Error! …
This redeclaration of X is an error; unlike for host association, you can’t hide a use-associated name with a local declaration. If you want to do that, then use an ONLY or renaming clause to prevent the same-named symbol from becoming visible.
We often see these sorts of problems in code that has been “converted from Fortran 77” by taking a set of procedures and putting them in a module. Declarations which were necessary in the separate context are forbidden when host association comes into play.
One More Thing
Finally, consider this example:
module MYMOD4 integer X end module MYMOD4 program MAIN use MYMOD4 dimension X(10) …
This is also an error. Once you inherit a symbol through association, most of its attributes are “locked”; you are not allowed to add to them. An exception is made for the ASYNCHRONOUS and VOLATILE attributes which can be added-on inside a procedure.
Say No More
Now you have learned that, while it is good practice to explicitly specify attributes, you can get into trouble by over-doing it. I hope this has helpful to you.
(Originally posted at Intel Developer Zone, copied with permission)