Conflicting definitions of NULL

Conflicting definitions of NULL

I have a (rather old, created with Digital Visual Fortran) win32 gui program which I compile now and then (with current versions of Intel Fortran).
Now it failed to compile with:

WGUTIL.F90(127): error #7112: This actual argument must not be the name of a procedure.   [NULL]
       ret=RegOpenKeyEx(HKEY_CURRENT_USER,C_SOFTWARE,NULL,  &

Obviously there is a conflict between INTEGER, PARAMETER :: NULL = 0 (somewhere in the win api modules, ifwinty actually) and the intrinsic function NULL().

To demonstrate this I have included here a demo code NULL-Intrinsic.f90.

The conflicting definitions in the demo are in module wintypes (INTEGER, PARAMETER :: NULL = 0) and in module dyndef, type declaration of dynstring_ (character(len=1), pointer :: s(:) => NULL()).

My questions:

1) The elements of derived type dynstring_ are declared private. Why does the definition of NULL() leak out there? Is this a compiler error? Is the Fortran standard precise enough to define such things?

2) The real program consists of about 10 source files (and approximately the same number of modules). The win32 api defines more than a dozen modules and I have a "utility" library with about 100 modules. So it took me some time to find out, from where the conflicting definitions came. Is there some aid in the compiler to help in such situations? Something like a cross reference or similar which tells from where type defnitions come from?

Markus

AttachmentSize
Downloadapplication/octet-stream null-intrinsic.f901.01 KB
18 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

(Your working code is missing an end statement.)

How current a current Intel Fortran? I get an error about conflicting declarations with 13.0.0, which is what I'd (now) expect after a recent discussion on c.l.f that surprised me at the time (and I see there have been historical discussion on similar topics).

The components of the derived type are private in your example, but the module entities are not. That means that anything "known" in the specification section of the module that isn't explicitly made private, including any intrinsic procedure used in the specification section, is a public entity of the module.

This reinforced for me that good coding practice is to have a private statement in a module's specification part, and only explicitly make public the things that you really want to. So do that - pop a private statement in module dyndef (in the module itself, not in the derived type - you'll also need public :: init_p) to make your problem go away.

Well, now I'm going to contradict myself, because the scoping unit that has the NULL() intrinsic is not the module's scoping unit (it's a nested scoping unit of the module's scoping unit), so the intrinsic NULL() shouldn't leak out, but regardless - use a private statement and avoid all this hapless confusion!

I respectfully disagree with Ian - with some hesitation because he is almost always right when it comes to language issues. Not this time, I fear...

In the "not working" case, NULL is used in an initialization expression while declaring the derived type dynstring_. It does not matter that the component being declared is private - that doesn't make references in initialization expressions private. The use of NULL is an implicit declaration of the NULL intrinsic and this does "leak out" of the module, since it is in module scope. It is NOT the use of NULL in the subroutine that is the problem, as noted in the comments.

As for DVF/CVF, here is what CVF 6.6 does:


C:Projects>df /c null-intrinsic.f90 /fpp

Compaq Visual Fortran Optimizing Compiler Version 6.6 (Update C)

Copyright 2003 Compaq Computer Corp. All rights reserved.
Compaq (R) Fortran Preprocessor Version 6.6-25

Copyright 2001 Compaq Computer Corporation.
null-intrinsic.i90

null-intrinsic.f90(42) : Error: The same named entity from different modules and

/or program units cannot be referenced.   [NULL]

  write(*,*) 'NULL = ', null

------------------------^

null-intrinsic.f90(42) : Error: This name has already been used as an intrinsic

function name.   [NULL]

  write(*,*) 'NULL = ', null

------------------------^

The compiler is correct. I agree that it would be nice if the compiler would help you identify the conflicting module - I will enter a feature request for this.

Steve - Intel Developer Support

[Edit: This is a response to IanH Mon, 10/15/2012 - 08:41
Steve's post crossed my answer. Don't be confused! ]

First, thanks for your help!

Regarding to your second post, it is a compiler error, isn't it?

But:
I don't share your opinion about "declaring everything". This is not Fortran style! Fortran style is to define only non default attributes. Or do you define i, j and n as integer?

That said, there are two possible ways: Use the standalone statement "public" to set the default and define anything not public via private attributes. Or, secondly, the same the other way around. This are the obvious options if you look at the compiler documents.

The problem here is the intrinsic function NULL(). It is not _defined_ within the module (so the private/public declaration rules do not apply), but it is _referenced_. Seems such references are not honored correctly.

This seems to be a flaw in the compiler(s). I ran the tests with good old CVF also and it behaves the same. Maybe I try it with CFAL on my DS20, but I'm rather sure it will be the same!.

Markus

I think our posts overlapped. The reference to NULL() is an implicit declaration of it, the same as if you had used a variable without declaring it. According to the standard, referencing an intrinsic procedure establishes its name as intrinsic in the scope where it appears.

Steve - Intel Developer Support

As a work-around
Use FPP
Add -DNULL=NULL_POINTER
(define NULL_POINTER appropriately)
Find and replace NULL() with null()
You might look for "NULL{whitespace}(" as well

This is a hack for sure.
Jim Dempsey

www.quickthreadprogramming.com

I think the only thing you can do is to make the default accessibility PRIVATE in all modules and then declare everything you want to leak out as PUBLIC. Does ifort handle the attached programs correctly? By the discussion of this thread it should accept all except use5.f90, right?

Attachments: 

AttachmentSize
Downloadtext/plain use1.txt223 bytes
Downloadtext/plain use2.txt219 bytes
Downloadtext/plain use3.txt288 bytes
Downloadtext/plain use4.txt835 bytes
Downloadtext/plain use5.txt893 bytes
Downloadtext/plain use6.txt204 bytes

(I agree that the private components statement isn't relevant here.)

This whole thing surprised (and disappointed) me when I read the c.l.f discussion, so I'm not going to pretend I really have a clue what's supposed to happen, but the reference to NULL isn't in the scope of the module, it is in the scope of the derived type definition (and the scoping unit of the module excludes "any scoping units in it"). If NULL() was used in an initialisation expression for a module variable (the declaration of the module variable being in the scoping unit of the module) then I'd have to agree with Steve - but the realisation that there was a difference in scoping unit is what made me repost above.

I most surely do define i, j and n as integer, nearly all my modules have private accessibility by default.

I solved my problem by inserting a global private statement and declaring anything needed from outside public. (In the real program, not in the example code here, of course. It took some try and error compilation and link runs to identify those global items).

Now I can use INTEGER, PARAMETER :: NULL = 0 again without the renaming technique (BTW: Look at iflogm.f90, module iflogm included with the compiler. They use the same trick: use ifwinty, NULLPTR => NULL).

Just for clarification: The compilation error did not arise from changing compilers (as my first post may be interpreted). I added the dynstring module to my library more than a year ago so I was somewhat puzzled about the compiler error occuring recently. That's why I asked whether the compiler can help to detect the origin of conflicting declarations.

But still, I don't understand why NULL() is in the scope of module dyndef and not in the scope of type dynstring.

The IVF documentation suggests:

If you use module IFWIN or IFWINTY, you will have a name conflict if you use the NULL intrinsic. To avoid this problem, rename the integer parameter constant NULL to something else; for example:

USE IFWIN, NULL0 => NULL

This example lets you use both NULL0 and NULL( ) in the same program unit with no conflict.
This will require you editing your CALLs with NULL to NULL0 (or NULL_POINTER, or NULL_C_PTR which may be more self explanitory).

Jim Dempsey

www.quickthreadprogramming.com

Quote:

IanH wrote:

(I agree that the private components statement isn't relevant here.)

This whole thing surprised (and disappointed) me when I read the c.l.f discussion, so I'm not going to pretend I really have a clue what's supposed to happen, but the reference to NULL isn't in the scope of the module, it is in the scope of the derived type definition (and the scoping unit of the module excludes "any scoping units in it").

I agree that this is somewhat confusing in the standard. The text in the standard regarding implicit declarations in the context of type definitions was the subject of interpretation F03/0123 and the resulting edit incorporated in F2008 Corrigendum 1. Intel Fortran interprets this correctly.


NUMBER: F03/0123

TITLE: 	Implicit typing in derived types

KEYWORDS: Derived types, implicit typing

DEFECT TYPE: Erratum

STATUS: Passed by WG5 letter ballot
QUESTION:
Consider the program
       PROGRAM MAIN

         TYPE T

           INTEGER :: I = BIT_SIZE(J)

         END TYPE

         ! J = 0

         CALL SUBR1

       CONTAINS

         SUBROUTINE SUBR1

           J = 1

           CALL SUBR2

           PRINT *, J

         END SUBROUTINE

         SUBROUTINE SUBR2

           J = 2

         END SUBROUTINE

       END
Q1. Is this program standard-conforming?

    (In particular, is it permitted to have the first, or only,

     appearance of a local variable name appear within a type

     definition.  The definition of implicit typing says that

     J is explicitly declared within T.)
Q2. (a) If not, is it standard-conforming if the comment "! J = 0" is

        turned into the assignment statement "J = 0"?

    (b) If it is standard-conforming, what does it print?

        (If J is a local variable of MAIN, it should print 2.)
ANSWER:
A1. Yes, the program is standard-conforming.  The definition of

    implicit typing is erroneous - J is a local entity of MAIN.

    An edit is supplied to correct this error.
A2. (a) Not applicable.

    (b) The program will print the value 2.
EDITS to 10-007r1:
[109:22-23] In 5.5p4,

  After

    "The data entity is treated as if it were declared in an explicit

     type declaration"

  replace "in" with "; if",

  then after "the outermost inclusive scope in which it appears"

  insert

    "is not a type definition, it is declared in that scope, otherwise

     it is declared in the host of that scope".
Note: This makes the whole sentence read

  "The data entity is treated as if it were declared in an explicit

   type declaration; if the outermost inclusive scope in which it

   appears is not a type definition, it is declared in that scope,

   otherwise it is declared in the host of that scope".

Steve - Intel Developer Support

Okay, since we now we have the authoritative definition, can some lawyer please translate it to us ;-)

Excerpt from the example code:

module dyndef
integer, pointer :: p(:)

type, public :: dynstring_
private
! Though private here NULL() is visible as intrinsic function from outside
character(len=1), pointer :: s(:) => NULL()
integer n
end type

contains
subroutine init_p
! Using NULL() here does not leak the definition as intrinsic to outside
p => NULL()
end subroutine

end module

What is the "outermost inclusive scope" of NULL()? Is it type dynstring?

[I am irritated about the word "outermost". I would have expected "innermost", meaning "as tight as possible". I'm not sure if I catch the (english) meaning of the standard right.]

What is the motivation of the standard to declare implicit type declarations in the host scope if the scope is a type definition?

All this means is that references to "data entities" (and intrinsic functions are included in these) inside type declarations create implicit declarations in the scoping unit in which the type declaration appears (assuming the entity is not already declared). The scoping unit could be a program unit or a BLOCK (a F2008 feature we don't yet support). So in the context of your program, Markus, the appearance of NULL() in the initialization expression is an implicit declaration of NULL as an intrinsic function in the scope of module dyndef, NOT in type dynstring.

The confusion arises because the F2008 standard includes "type declaration" as one kind of scoping unit, and the mess results from that. This interpretation clarifies that, for the purpose of implicit declarations, the scope of an implicit declaration inside a type definition is the BLOCK or program unit containing the type definition.

Steve - Intel Developer Support

Thanks for the explanation.

Dare I ask what you think of RO's examples with the intrinsic operator in the only clause?

Regarding RO's test programs:

1. Doesn't compile because ifort doesn't yet support SUM in an initialization expression.

2. Not legal, as far as I can tell. This is an entertaining example, though, as many of RO's are. There is no defined generic spec for OPERATOR(+) in module mod2. Operators are not data entities.

3. Same as #2.

4. This is fine - program prints F

5. Ooooh, I like it! But ifort doesn't, complaining that "Intrinsic operator can not be used on the right hand side of an OPERATOR rename clause". Looks like a bug to me - I think this should work.

6. TYPE(INTEGER) is not legal - this has to be a derived type.

Steve - Intel Developer Support

It was 2 and 3 that I wondered about. If they are allowed they are not terribly useful, because they don't change program interpretation at all. 5 is ruled out by the syntax rules for defined operators - so things that look like the intrinsic operators are not allowed in a rename. The syntax TYPE(integer) is ok in F2008, whether the type is something that is a public entity of the module was the basis of the recent c.l.f discussion. I think the conclusion was that it was more important for everyone to have a good lie down first.

Ah, I had missed the bit about "not being the same as any intrinsic operator". Thanks for pointing that out.

Steve - Intel Developer Support

Leave a Comment

Please sign in to add a comment. Not a member? Join today