- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Compiler: Intel Visual Fortran Compiler - Professional - extension version 19.1.0057.15
I have an old version of a program that I need to get running again, circa 2001/2002, in order to trouble shoot a new program. Don't have the time or money to re-write the old version.
Problem: I have a kinked list. When I start the program I check if the list has anything in it. If it does I systematically work through the list and clear it out. I test the list by using the ASSOCIATED statement. No matter what I do, the if (associated (mylist)) test is ALWAYS TRUE. Under the original compiler (possibly Compaq VF) this worked. Meaning upon execution the test for associated was FALSE. Other than rewriting tons of code, is there a fix, a compiler setting, anything that will make this work the way it used to?
Here are snippits from the code that I think are important.
In module_user_type:
Type DEBRIS_PROPS_TYPE
type (CLOUD_PROPS) :: Debris
type (PEN_PROPS_TYPE), dimension(4) :: Pen
type (HIT_PROPS_TYPE) :: Hit
type (DEBRIS_PROPS_TYPE), Pointer :: Next
End Type DEBRIS_PROPS_TYPE
where: CLOUD_PROPS is a derived type that contains some fixed size arrays and other real variables, PEN_PROPS_TYPE is derived type containing a bunch of other derived types, and HIT_PROPS_TYPE is a derived type containing integers and reals. Nowhere are there arrays that are not fixed in size.
In my subroutine, which include the USE statement for the above module, where I initialize/clear the list I have the following:
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead !Pointer to head of list
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisTail !Pointer to tail of list
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisPtr !Temporary pointer to new value
At the beginning of this subroutine I have the following block of code to clear the list:
ClearList: do
if (.not. associated (DebrisHead)) then !Check if there is still a list from previous run)
exit
else
DebrisPtr => DebrisHead !Point to head of list
DebrisHead => DebrisPtr%Next !Point head to next item in list
deallocate (DebrisPtr) !Deallocate the node
nullify (DebrisPtr)
endif
enddo ClearList
The problem is even at the start where I know I have no content in the list, associated(DebrisHead) is always true. The code drops into the ELSE code and I get an exception error on the second line of the block. Under the old compiler the block of code functioned as I expected, exiting if the list was empty, and systematically clearing it if it wasn't.
Again, I only need to get this running so I can compare some output to a new code that I am modifying that does not use this logic. And I can't rewrite the entire old program with new logic just to perform a short code output comparison. The old code contains LOTS of list creation and manipulation.
If this was covered elsewhere I apologize for the redundancy.
Thank you in advance for any help you may provide.
Richard
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
CORRECTION, the topic should have read: Use of the intrinsic ASSOCIATED.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
If the pointer is not initialized, the return of ASSOCIATED is undefined. The lesson here is to make sure all pointers are properly initialized. If they're in a type, add => NULL() to their component declaration.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Steve:
Thank you for your quick reply. Let me make sure I know where and how to apply the NULL stmt, as I have tried two ways, one gives compiler errors and the other a runtime error. There are no Fortran programmers left in my company and I've been trying my best to figure this out on my own, without success.
When I apply the NULL to the variable declarations in my subroutine,
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead => NULL() !Pointer to head of list
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisPtr => NULL() !Temporary pointer
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisTail => NULL() !Pointer to tail of list
I get compiler errors (6414 and 6678) for each of the three lines.
So I removed those three NULL assignments and placed it in my type declaration statement:
Type DEBRIS_PROPS_TYPE
type (CLOUD_PROPS) :: Debris
type (PEN_PROPS_TYPE), dimension(4) :: Pen
type (HIT_PROPS_TYPE) :: Hit
type (DEBRIS_PROPS_TYPE), Pointer :: Next => NULL()
End Type DEBRIS_PROPS_TYPE
The code compiles without any errors but when I run the program this time I enter my subroutine where I first clear my list, if it exists, using the block of code below. The first thing I note is that associated(DebrisHead) is still TRUE when I know it should be FALSE. So, naturally, it enters the ELSE block and throws a exception on the second line in the block, read access violation.
ClearList: do
if (.not. associated (DebrisHead)) then !Check if there is still a list from previous run)
exit
else
DebrisPtr => DebrisHead !Point to head of list
DebrisHead => DebrisPtr%Next !Point head to next item in list
deallocate (DebrisPtr) !Deallocate the node
nullify (DebrisPtr)
endif
enddo ClearList
I appreciate all your help and patience.
Respectfully,
Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Please show a small but compilable source that shows the errors, as well as the actual text of the error messages. I can't do anything with just error numbers (Intel no longer publishes lists of compiler error messages.)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
I'll try to make a file you can compile. My code is huge and generates a DLL. I'll see if I can generate an EXE that replicates the problem.
I apologize about the error numbers, I didn't realize Intel no longer publishes lists of compiler error messages.
The error messages I receive are a function of where I place the NULL assignment.
My code structure is: I have an entry point to the DLL. It calls subroutine #1 which is an overarching controller program. Subroutine 1 calls subroutine 2 which contains the list clearing code. I do have a separate module that I USE in subroutine 1 that contains an interface statement for subroutine 2.
The following variable declaration exists in both subroutine 1 and subroutine 2:
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead => NULL() !Pointer to head of list
The variable declaration line of code in subroutine 1 generates the following compile errors:
Error error #6678: When the target is an expression it must deliver a pointer result. [NULL]
Error error #6414: This PARAMETER constant name is invalid in this context. [NULL]
The variable declaration line of code in subroutine 2 generates this error:
Error error #6562: A data initialization-expr is not valid for this object. [DEBRISHEAD].
Removing the NULL assignment from either subroutine does not affect the error message(s) generated in the other subroutine.
Thank you,
Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Ah, you might have a PARAMETER constant named NULL defined?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
I checked my code thoroughly and found no evidence of a PARAMETER statement referring to NULL.
The program where this is occurring is a DLL that is driven by a VB6 GUI, if that is useful.
I wrote a small console EXE file to try to duplicate the error. While the place in which the error occurs is different I suspect the crux of the problem may be the same as I am experiencing in my actual program. I also tried to maintain a semblance of the layout of the actual program in terms of using subroutines and interface modules, etc.
In my sample program assigned NULL to my pointers in MAIN as you suggested.
When I enter subroutine SetupQueue I am expecting the test if (.not. associated (DebrisHead)) then to return TRUE causing the do loop to exit. Instead, when I execute that line I get an exception DEBRISHEAD was nullptr. However, when I highlight "associated (DebrisHead)" in the debugger it shows TRUE, which also makes no sense to me.
In my actual program the IF test returns FALSE and the program fails on the line DebrisHead => DebrisPtr%Next. I wish I could make an example that does EXACTLY what the actual program does, but alas...
Thank you.
Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Your call to SetupQueue from the main program (in this example) is invalid because of the lack of an explicit interface. The language requires that if a dummy argument is a POINTER, an explicit interface is required. (For more background, see Doctor Fortran Gets Explicit - Again! - Doctor Fortran (stevelionel.com))
Intel Fortran has an option that will warn you about this. It is on by default in new projects, but if you migrated your project from 2001/2002, it would not be present. With the new option, the compiler complains:
Error #8055: The procedure has a dummy argument that has the ALLOCATABLE, ASYNCHRONOUS, OPTIONAL, POINTER, TARGET, VALUE or VOLATILE attribute. Required explicit interface is missing from original source. [DEBRISTAIL] D:\Projects\Console5\Main.f90 10
Because of the lack of an explicit interface, the compiler does not know it has to pass a pointer, and the receiving routine misinterprets the result.
The option is Fortran > Diagnostics > Check routine interfaces. It might be a good idea for you to create a new project for the DLL and add the existing sources to it. The best way to add an explicit interface is to move the procedure into a module and USE the module.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
My error. I wrote the explicit interface, Module_Pointer_Routines.f90, and promptly forgot to add it as a USE in Main. Guess I'm stressed.
After adding the USE line the program runs without an error but still shows associated (DebrisHead) is TRUE. Guess I need to work on expanding this example to replicate the original problem. However, I am beginning to get a clearer picture of what may be going on there, too.
Most interesting is that in SetupQueue I added a three "tracking" lines of code assigning values to MyVariable, depending on where the code went. (See the attached files) By single stepping through the code, MyVariable is initialized to 0. Using the debugger, the IF clause examination says it is FALSE because associated(DebrisHead) is TRUE, so it "should" drop down to the ELSE clause. Yet the code stays in the IF clause, hits MyVariable=1, then EXIT, and then drops out of the ClearList loop. Not the reaction I was expecting.
I guess I'll keep muddling through my code to try an solve it. I wish I could send you the code but I can't
I appreciate you time and help. I may be back if I can't solve the problem.
Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I am not seeing that behavior - The ".not. associated" path is taken.
I will comment that, sometimes, the debugger does not properly reflect the state of the variables. This is especially likely to happen if you enable optimization, but even without it sometimes happens.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I will comment that there are numerous reports (including my own) where the debugger cannot see allocatable or pointer components of derived types properly. That said I do not recall seeing that for a little while so maybe some (all) of those problems are fixed in the latest release. My vague last sentence is in part due to the fact that we no longer get any idea of what is fixed in the release notes and have to go back and redo our own tests to see if we can stop using workarounds to known problems.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
I just discovered the source of the compile errors: (Can't say I understand, however)
Error error #6678: When the target is an expression it must deliver a pointer result. [NULL]
and
Error error #6414: This PARAMETER constant name is invalid in this context. [NULL]
on the line of code
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead => NULL() !Pointer to head of list
It occurred to me that in my real code I have
use dfwin
If I add this line of code to the sample I provided to you I get the error codes. When I remove it I get no compile errors.
As I recall from long time ago I needed to do this because my code tests for the presence of another DLL and then loads and calls calls it if found.
If, instead of using the line of code:
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead => NULL()
I, instead, do the following, it appears to work.
type (DEBRIS_PROPS_TYPE), Pointer :: DebrisHead
nullify (DebrisHead)
Am I doing this correctly or is there another pitfall I am about to crash into?
Thank you
Richard
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
NULLIFY(...) is an execution statement. You will need to place the nullify(...) at/near the start of the program where you do your initialization.
Alternatively you can...
use dfwin, only : the, procedures, and, variables, you, need, here
(excluding NULL)
if you need NULL as a parameter, then consider
use dfwin, dfwinNULL=>NULL
or whatever name you want to substitute for NULL.
IMHO, the compiler should disambiguate between NULL and NULL()
Jim Dempsey
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
DFWIN declares a named (PARAMETER) constant named NULL, so that hides the NULL() intrinsic. You can get around that with a rename, for example:
USE DFWIN, NOTUSED => NULL
Or use an ONLY clause to name only the symbols you want from DFWIN. (Might be good to switch to IFWIN while you're in there.) My personal preference is to not use the xxWIN module but instead the individual library modules such as KERNEL32, USER32, etc., but there's nothing wrong with xxWIN.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
Many thanks for all your help on this. I was beginning to panic because my deliverable on this project is the end of February. But I needed to get this old version running to compare logic flow. Now I can proceed forward at full steam, thanks to you.
At the time when I wrote that program I recall I was trying to figure out how to solve a problem and my internet search said dfwin was the solution, and it worked. I had no idea what was in it, only that it worked and continues to work. However, you just made me aware of ifwin and I am going to change over to it in my current version of the code.
I am recently becoming aware of the ability to limit the scope of a USE statement. Most all of the Fortran I write I try to stay as close to basics as I can because I have to maintain multi-platform compatibility.
Again, thank you.
Very Respectfully,
Richard
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page