I have been looking at the behavior of the check:bounds compiler option, and in particular I read through this forum thread. I had a memory corruption in a program I'm writing (which I fixed now) that I think should have been caught by the run-time check. I adapted an example from the forum thread to demonstrate the behavior:
program ex implicit none call modify(5) contains subroutine modify(n) implicit none integer :: n real(kind=8) :: a(3) print*, a(1:n) CALL modify2(a(1:n),n) a(1:n) = 10.5D0 end subroutine modify subroutine modify2(a,n) implicit none integer :: n real(kind=8) :: a(n) a(1:n) = 10.0 print*, a(1:n) end subroutine end
The behavior I am questioning is: Visual fortran gives me the error "Subscript #1 of the array A has value 4 which is greater than the upper bound of 3" at line 20. I agree that indeed, I go out of bounds at that moment. I understand why I do not get the error at line 30, since I think Fortran allows to pass only parts of arrays and then access the subsequent elements simply because they are contiguous in memory.
However, I do not understand why I do not get a runtime error at line 18: I am explicitely asking Fortran to pass an array of size n=5, when a is only size 3. Should that not result in a warning? Or what is the use of allowing such behavior?
Thanks in advance!
EDIT: I am running Intel Parallel Studio XE 2016 Composer, Version 16.0.0046.12
As long as you don't actually reference out of bounds in subroutine modify, there will be no error. But once you're in modify2, all the compiler knows is that you declared the array with dimension 5. Bounds checking doesn't catch every possible error - it is specific to subscript (and substring) references that either fetch or store values.
I can see your point that it would be nice if the argument slice was also checked - sounds like a good feature request. Of course, if you use assumed-shape arrays everywhere, you won't have the chance to get into trouble like this.
Thank you for your very quick answer Steve, it's good to see that even retirement doesn't change certain things!
Should I start a new post to make a feature request?
I have a subsequent question: I am not using a whole lot of assumed-shape arrays (started off with legacy code), would I lose any speed by switching my code to assumed-shape arrays? Are there any drawbacks to the switch?
P.S.: just realized I posted in the wrong OS forum... My apologies...
Regarding your question on performance, the data I have seen says that in most cases it is not noticeable, especially if you are comparing to adjustable arrays (where you pass the bounds separately). My general position is that you should write the clearest code and don't worry about relative performance unless and until you find it's an issue AND you have used a performance profiler, such as VTune, to see where the bottlenecks really are. If you just guess, you'll almost certainly be wrong.
I would think this thread could serve as a feature request, if Intel folks pick up on it. That you're using Windows isn't relevant to the issues raised here (but watch it for next time!)
>>Of course, if you use assumed-shape arrays everywhere, you won't have the chance to get into trouble like this.
program ex implicit none call modify(5) contains subroutine modify(n) implicit none integer :: n real(kind=8) :: a(3) ! print*, a(1:n) CALL modify2(a(1:n),n) a(1:n) = 10.5D0 end subroutine modify subroutine modify2(a,n) implicit none integer :: n real(kind=8) :: a(:) a(1:n) = 10.0 print*, a(1:n) end subroutine end
The above code was modified to use assumed shape in modify2. However, the CALL modify2, using a slice that is out of bounds does not error... and produces an array descriptor for use in modify2 that has the extended bounds.
Of course, removing the slice (1:n) from the call corrects the problem as written, however consider
CALL modify2(a(m,n), j)
IOW an arbitrary slice, and an arbitrary offset.
Bounds checking on the slice would be nice to have.