3

Consider the following minimal working example:

module lib
    type t
    contains
        procedure::f,g
    end type
contains
    integer function f(this)
        class(t),intent(in)::this
        f=10
    end
    function g(this)result(r)
        class(t),intent(in)::this
        character(len=this%f())::r
        r='42'
    end
end

program prog
    use lib
    type(t)::o
    print*,o%g()
end

Compiling this code with the GNU (gfortran 11.1.0) compiler leads to the following message:

f951: internal compiler error: Segmentation fault
0x16463d7 internal_error(char const*, ...)
    ???:0
0x64b47c gfc_find_derived_vtab(gfc_symbol*)
    ???:0
0x672605 gfc_reduce_init_expr(gfc_expr*)
    ???:0
0x6572e3 gfc_match_char_spec(gfc_typespec*)
    ???:0
0x65e227 gfc_match_decl_type_spec(gfc_typespec*, int)
    ???:0
0x65f93c gfc_match_data_decl()
    ???:0
0x6d6236 gfc_parse_file()
    ???:0
Please submit a full bug report

The message says that it is a compiler bug, but I am not so sure. The NAG (nagfor 7.1) compiler also fails to compile the code with Error: line 13: Reference to non-specification function F in specification expression. However, the Intel (ifort 2021.8.0, ifx 2023.0.0) and Nvidia (nvfortran 22.9) compilers compile the code successfully. The problem in the first two compilers (GNU and NAG) is caused by the line character(len=this%f())::r.

Does Fortran standard allow declaration of the character length (in the automatic allocation) with the result of a function (here f)? Is it a bug of the GNU compiler or a feature of the Intel and Nvidia compilers?

V T
  • 103
  • 7
  • 1
    An internal compiler error is a bug in the compiler, whether or not the source that prompts it is valid Fortran. – francescalus Feb 23 '23 at 11:29
  • 1
    That said, the NAG compiler is correct _in this case_. There are changes which could make your program valid: are you interested in what those are, or simply an assessment of this one example? – francescalus Feb 23 '23 at 11:35
  • @francescalus I know, how to avoid this problem: I can declare the character variable as an allocatable and dynamically allocate the variable after the length is calculated with function `f`. But I would like to know, if the Fortran standard allows the automatic allocation like in this example. If I understand you correctly, it is not allowed and NAG detects it. Does this mean that the Intel compiler is wrong and shouldn't be able to compile this code? – V T Feb 23 '23 at 12:08
  • What flags did you use with the Intel compiler(s)? Did you use any to enforce standard conformance? – Ian Bush Feb 23 '23 at 12:28
  • OK, if I use `-stand f18` of ifx and ifort I get no warnings or errors - which looks like a compiler bug. – Ian Bush Feb 23 '23 at 12:32
  • @IanBush I didn't use any flags. – V T Feb 23 '23 at 13:02
  • You might argue that the Intel compiler recognizes the result of `f` and replaces `character(len=this%f())::r` with `character(len=10)::r`. But you can also replace `f=10` with something like `real::n;call RANDOM_NUMBER(n);f=INT((1+n)*10);print*,"I'm an impure function"`, and Intel will also compile it. I didn't show this here, but the Intel compiler also allows the results of impure functions in the automatic allocation of arrays. I have a real example of a linked-list implementation, where pointers are used in these impure functions (maybe it is worthy to add this example to the question). – V T Feb 23 '23 at 13:09
  • 1
    @VT by default all compilers (except maybe NAG which I don't currently have access to) compile something that is similar to but not quite exactly standard Fortran. I would strongly recommend always using the appropriate flags to try and ensure standard compliance to avoid these compiler specific extensions. – Ian Bush Feb 23 '23 at 14:09

1 Answers1

2

Some functions can be used to give the length of a character function result; the particular function used here cannot.

First: compilers shouldn't crash. What you see with gfortran is an internal compiler error (ICE), a bug. ICEs are bugs whether the code presented is valid Fortran or not.1

The terminology introduced by the NAG compiler in rejecting your code is key to whether a function is allowed to be used. The length of a character function result must be a specification expression.2 The rules around how a specification expression is made are fairly involved (see Fortran 2018 10.1.11 and other questions and answers here for more detail) but the reason F here is rejected by nagfor is that F is not a pure function.

For F to be a specification function it must be pure (F2018 10.1.11 Note 1):

The requirement that they be pure ensures that they cannot have side effects that could affect other objects being declared in the same specification-part.

At least with the version of gfortran I tested, you can work around the ICE, once you've made F pure, by changing the specification expression to:

character(len=f(this))::r

Finally, note that one cannot confidently say the Intel/NVIDIA compilers are wrong to accept this code. The code is not valid Fortran so a compiler can chose to do anything, including accept it as an extension. This isn't a case where a compiler is required to be able to diagnose your error. (One could still call it a compiler bug as this particular violation may well be good to diagnose and easy to see.)


1 This isn't really true. If the code is not valid Fortran then the compiler is allowed to do anything in response (as long as it is capable of reporting those deficiencies it is required to be able to detect and report). Crashing is a thing it's allowed to do, although compiler vendors generally accept that an ICE is a bug even if it's an allowed response under the Fortran standard: it's a poor user experience.

2 This applies equally to array bounds and to automatic data objects of a procedure more widely.

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • I think, it is a bug of the Intel and Nvidia compilers, because you can add one `print` statement in `f` (in my example), and two identical messages will be printed, even though there is only one call of the `f` function. – V T Feb 23 '23 at 13:56
  • 2
    It seems @VT submitted a bug report for gfortran. I've provided a patch that removes the ICE. I can confirm that the suggested work-around of `character(len=f(this))::r` compiles once `f` is marked as `pure`, but the component reference form, `character(len=this%f())::r`, gives a few errors. – steve Feb 24 '23 at 19:55
  • Intel and Nvidia responded and filed bug reports for this issue: CMPLRLLVM-45330 and TPR #33181, respectively. – V T Mar 01 '23 at 21:41