My earlier post, "I've Come Here For An Argument", was very popular with my fellow support engineers, as it provided a convenient answer to questions they frequently receive. (For me too, which in part is why I wrote it!) But some people (cough, Ron, cough) are never satisfied, and I've been asked to write a follow-up on what else can go wrong when you don't understand all of Fortran's argument-passing rules. So, here we go...
Look, But Don't Touch
Consider the following subroutine:
subroutine sub (i)
if (i > 2) i = i + 1
Now, what happens when you call this with:
a) The value 3 changes to the value 4 in the caller
b) Access violation or segmentation fault
c) Nothing, the variable changes value in the subroutine but not the caller
d) World War III starts
The answer, for many older compilers, was (a)! For current Intel compilers, the correct answer, however, is (b) - a run-time error that is "access violation (on Windows) or "segmentation fault: on Linux and Mac OS. Why? The compiler has to put the value 3 in memory somewhere. By default, it puts it in a section of memory it has asked the operating system to make "read-only". When the value of variable i changes in the subroutine, that is an attempt to write to read-only memory and you get a run-time error.
The Intel compiler has an option, /assume:[no]protect_constants (Windows) or -assume [no]protect_constants (Linux/Mac OS) which can change this behavior to (c). If "noprotect_constants" is specified, then the compiler creates a temporary copy of the value 3 and passes the address of the copy. The subroutine can change the value all it wants but the changes will be discarded on return. (Those who have been with the Doctor for a long time may recall that I wrote about this back in the CVF days, almost nine years ago. You can read that item here.
I will point out now that the above call is not legal Fortran - the literal constant 3 is not "definable" and that means you are not allowed to "redefine or cause to become undefined" the associated dummy argument. However, code like this has appeared in many applications over the years.
Now, what if you did this?
What is being passed here is an expression, not a literal, so is that legal? No! An expression is not definable either! However, Intel Fortran treats this differently and will always pass a temporary copy of the value, as if you had said /assume:noprotect_constants.
But what if you wanted to pass any variable to this subroutine but have the original value preserved? You could write:
and take advantage of Intel Fortran's extension where it passes a copy, but Fortran 2003 has another way. If you give the dummy argument the VALUE attribute, which requires an explicit interface to be visible, then the effect is similar in some ways to passing an expression. Actually, what happens is that on entry to the subroutine, a new local variable is created that copies the value of the argument, and all references in the subroutine are to that local variable, which is definable. On exit, like other local variables, the copy is discarded. VALUE has another purpose as part of C interoperability, but I'll discuss that another time.
By the way, there's a less obvious way that you can pass an argument that is not definable: an array with a vector subscript. For example, A([1,3,5]). Here too, you're not allowed to assign into a dummy argument that is associated with such an actual argument.
Alias Smith and Jones
It is often said that Fortran is faster than C because Fortran disallows variable aliasing, where the same storage can be referred to by two or more different names, and in C everything can be aliased. There is some truth to this on both sides, but it is not absolute - especially when more recent versions of the C standard are considered.
It is true that in most cases, a Fortran compiler can assume that no aliasing occurs, but not always. Unfortunately, a lot of programmers inadvertently violate the language rules and run int trouble. Here's the basic text that the standard has to say about aliasing:
While an entity is associated with a dummy argument, the following restrictions hold:
(1) Action that affects the allocation status of the entity or a subobject thereof shall be taken
through the dummy argument. Action that affects the value of the entity or any subobject
of it shall be taken only through the dummy argument unless
(a) the dummy argument has the POINTER attribute or
(b) the dummy argument has the TARGET attribute, the dummy argument does not
have INTENT (IN), the dummy argument is a scalar object or an assumed-shape
array, and the actual argument is a target other than an array section with a vector
[22.214.171.124 Restrictions on entities associated with dummy arguments]
Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.
Notice revision #20110804