Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Use of the intrinsic ALLOCATED

Zernow__Richard
New Contributor I
1,548 Views

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

0 Kudos
15 Replies
Zernow__Richard
New Contributor I
1,547 Views

CORRECTION, the topic should have read: Use of the intrinsic ASSOCIATED.

0 Kudos
Steve_Lionel
Honored Contributor III
1,530 Views

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.

0 Kudos
Zernow__Richard
New Contributor I
1,511 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,505 Views

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.)

 
0 Kudos
Zernow__Richard
New Contributor I
1,495 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,487 Views

Ah, you might have a PARAMETER constant named NULL defined?

 
0 Kudos
Zernow__Richard
New Contributor I
1,448 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,440 Views

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.

 
 
 
 
0 Kudos
Zernow__Richard
New Contributor I
1,423 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,416 Views

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.

 
0 Kudos
andrew_4619
Honored Contributor II
1,406 Views

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.

0 Kudos
Zernow__Richard
New Contributor I
1,390 Views

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

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,385 Views

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

0 Kudos
Steve_Lionel
Honored Contributor III
1,368 Views

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.

 
0 Kudos
Zernow__Richard
New Contributor I
1,351 Views

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

0 Kudos
Reply