Use association of two ultimate entities

Hi,

I have put it in the “Help” category but maybe I misclassified and it should be in compilers.

I have stumbled on the following curiosity. Consider the code below:

module A 
  implicit none
contains 

subroutine foo()
  print *, "A"
end subroutine

end module A

module B 
implicit none

contains 
subroutine foo()
  print *, "B"
end subroutine

end module B

program main 
  use A, only: foo 
  use B, only: foo

  implicit none


end program main

On godbolt: Compiler Explorer

This code is accepted by gfortran,flang and LFortran, which is kind of consistent with my reading on the section 14.2.2 paragraph 8 of Fortran 2023 standard (https://j3-fortran.org/doc/year/24/24-007.pdf), which reads:

An ultimate entity is a module entity that is not accessed by use association. An accessed entity shall not be associated with two or more ultimate entities unless its identifier is not used, or the ultimate entities are generic interfaces. Generic interfaces are handled as described in 15.4.3.4.

However the above snippet is rejected by Intel compilers e.g. Compiler Explorer

Out of pure curiosity I just wonder what is the “correct” behavior in this case. Should explicitly specifying use association (? not sue I am using the term right) in use A, only: foo be considered “using an identifier”.

I was just hoping that people more knowledgeable about Fortran could have some extra insight :slight_smile:

Welcome to the forum!

You create an ambiguity this way and the compiler should warn about it at the very least. It cannot decide which one to use. Of course, since you do not use the subroutine, no harm is done, but I would say this is a situation that is to the discretion of the compiler. But that is my feeble attempt at understanding the standard :slight_smile:

Fortunately, Fortran provides for a way to avoid naming conflicts with module entities

You can do one of the following

USE A, ONLY : fooa=>foo
USE B, ONLY : foo

or

USE A,ONLY: foo
USE B, ONLY:foob=>foo

or

USE A, ONLY:fooa=>foo
USE B, ONLY:foob=>foo

The code is non-conforming but there is no obligation on a compiler to report it as non-conforming.

I think the issue is that the ONLY clause conveys intention to use.

Since ifort/ifx accepts the code then the ONLY clause is not involved (and the symbol is not referenced), it seems that clause means the symbol explicitly becomes part of the program-unit USEing it.

It’s the same as if instead of a main-program-unit you had a third module:

module A
  implicit none
contains
    subroutine foo()
      print *, "A"
    end subroutine
end module A

module B
    implicit none
contains
    subroutine foo()
      print *, "B"
    end subroutine
end module B

module C
  use A, only: foo
  use B, only: foo

  implicit none

end module C

In this case, which foo should be made public from C?

The way I read the standard, there is no need to decide, because foo is not “used” anywhere in module c, which I think means it is not invoked in any statements. This seems like a nice feature, because it would permit you to use two modules that have some conflicting names without needing to rename all the conflicts, rather only the ones you actually invoke.

For example,

module A
  implicit none
  real x, y, z, aaa
  integer i, j, k
contains
    subroutine foo()
      print *, "A"
    end subroutine
end module A

module B
  implicit none
  real x, y, z, bbb
  integer i, j, k
contains
    subroutine foo()
      print *, "B"
    end subroutine
end module B

module C
  use A
  use B

  implicit none
  real x, y, z, ccc
  integer i, j, k

  ! z = x + y ! would cause compiler error because of name conflicts
  aaa = sqrt(bbb**2 + ccc**2)  ! ok because names don't conflict

end module C

How is this line “aaa = sqrt(bbb2 + ccc2)” okay, because the variables aaa and bbb are not defined. There are variables of that name in the modules, but these are explicitly not imported.

I guess that is why it was not made an official constraint in the Fortran spec, and was not given a number.

On the other hand, others might think that this is a horrible feature.

2 Likes

Yes you’re right, my oversight. I copied the code and forgot to remove the “only”.

I’ll fix it.

Both gfortran and ifx complain about the additional scalars :slight_smile: . Not a big deal to correct it.

Yes, it’s not used anywhere in the module, but as I said, I think the ONLY clause makes it a public part of that module. Without the ONLY clause, the compiler will recursively search the modules USEd by C until it finds what it needs, when the module is eventually used.

A module is a compiled thing, so it cannot retroactively adjust itself depending on how it’s used.

(Btw, I’m just speculating in regards to ifort/ifx behavior.)

I think here is a better test example:

module A
  implicit none
contains

subroutine foo()
  print *, "A"
end subroutine

end module A

module B
implicit none

contains
subroutine foo()
  print *, "B"
end subroutine

end module B

program main
  use A
  use B

  implicit none

  call foo()

end program main

This is rejected by GFortran, Flang and ifx. LFortran right now accepts it, but we’ll fix it. An example error from Flang:

$ flang a.f90
error: Semantic errors in a.f90
./a.f90:27:8: error: Reference to 'foo' is ambiguous
    call foo()
         ^^^
./a.f90:22:7: 'foo' was use-associated from module 'a'
    use A
        ^
./a.f90:23:7: 'foo' was use-associated from module 'b'
    use B
        ^

I think you are correct that the variables aaa and bbb are undefined. One way to define them would be to initialize them within their modules.

real x, y, z, aaa = 42.0
...
real x, y, z, bbb = -1.0

However, the last statement is misleading. By default, all public entities are imported by a use statement, so those two variables are in fact imported into module C.

The part that I do not understand is where the error occurs regarding the conflicts. Suppose the three modules and the main program are all in separate files and they are all compiled separately. Suppose further that module C is supposed to be the only public module, and that modules A and B are supposed to be just implementation details of module C. I think modules A and B are correct, meaning standard conforming with no errors. But should module C show an error when compiled? I don’t think so, since it never references any of the entities that have a name conflict (specifically: x, y, z, i, j, k, foo). Similarly if the main program uses C (but not A or B directly) and never references any of those entities, then I think it is correct too. But if the main program does reference one of those entities, then there is a conflict, but that conflict cannot be resolved with the only clause in the main program. The error can only be corrected by modifying module C, which was already standard conforming and correct.

Maybe it is more correct to say that module C can be used correctly, but it has latent conflicts that can arise when it is used and if those conflicts are referenced?

Can the main program resolve those conflicts by using A and B directly?

use A, only: a_foo => foo
use B, only: b_foo => foo
use C
...
call a_foo()
call b_foo()
call foo()

I think the conflict within C is still triggered, right? However the first two calls are now alright. However, this violates the requirement that only C is known to the public, it requires the implementation details of C to be exposed.

Regarding the original question of whether the ONLY clause itself constitutes a reference, I do not know the answer to that part.

@Machalot already corrected some of the code - the original had the lines “use a/b, only: foo”. :slight_smile:

To get more information, I’ve tried compiling the following code

module A 
implicit none
contains 
  subroutine foo()
    print *, "A"
  end subroutine
end module

module B 
implicit none
contains 
  subroutine foo()
    print *, "B"
  end subroutine
end module

module AB 
  use A, only: foo   !! (L1)
  use B, only: foo   !! (L2)
  implicit none
end module

with gfortran-15 -c -fdump-fortran-original, then I get:

(...)
procedure name = ab
  symtree: 'a'           || symbol: 'a'            
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(a) USE-ONLY)
  symtree: 'ab'          || symbol: 'ab'           
    type spec : (UNKNOWN 0)
    attributes: (MODULE )
  symtree: 'b'           || symbol: 'b'            
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(b) USE-ONLY)
  symtree: 'foo'          Ambiguous|| symbol: 'foo'          
    type spec : (UNKNOWN 0)
    attributes: (PROCEDURE MODULE-PROC  USE-ASSOC(a) SUBROUTINE USE-ONLY USE-RENAME IFSRC-DECL)
(...)

So, it seems that gfortran embeds the information that foo is ambiguous into somewhere at compile time (I guess it is embedded in ab.mod file, but I cannot understand the format of the latter…) If I change Lines L1 and L2 as

  use A
  use B

then the output changes as follows (where the difference is the lack of “USE-ONLY”)

procedure name = ab
  symtree: 'a'           || symbol: 'a'            
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(a))
  symtree: 'ab'          || symbol: 'ab'           
    type spec : (UNKNOWN 0)
    attributes: (MODULE )
  symtree: 'b'           || symbol: 'b'            
    type spec : (UNKNOWN 0)
    attributes: (MODULE  USE-ASSOC(b))
  symtree: 'foo'          Ambiguous|| symbol: 'foo'          
    type spec : (UNKNOWN 0)
    attributes: (PROCEDURE MODULE-PROC  USE-ASSOC(a) SUBROUTINE IFSRC-DECL)

so gfortran seems to treat the two codes similarly regardless of whether foo is declared with the only clause.

I hope I could try a similar thing for other compilers but don’t know how to…