2

Is a Fortran 90+ compliant compiler required to always reject compiling functions marked as PURE, if the function violates a requirement of being PURE?

In other words, can I be sure (assuming the compiler is bug free), that if I mark an arbitrary function PURE, there will be a compile-time error instead of UB?

Contrast this with restrict in C++, where it is a promise from the programmer to the compiler, that the given pointer/reference is never aliased. The compiler does its job with this assumption and if at any point the pointers are aliased, you get UB at runtime.

uLoop
  • 225
  • 1
  • 8

2 Answers2

4

In Fortran 2018 all of the constraints listed that apply to a "pure" subprogram are so-called numbered constraints (F2018, 15.7 p.2). This means that the compiler is required to be able to diagnose violations of any such constraint. (In practice, there's little motivation for a compiler to choose to let the programmer off the hook and allow such violations.) A violation of a numbered constraint does not need to be diagnosed at compile-time (instead of run-time), although that's generally the time it would be.

However, the constraints that apply to a "pure" subprogram are not necessarily those that are required to make the subprogram pure in a pure computer science sense.


There is a complementary question which can also be addressed here. The constraints I mention apply to pure subprograms, but these aren't the only places where a programmer can mark a procedure to be pure.

The constraints on pure subprograms apply where we have something we want to compile:

function f(x, y, z)
  ...
end function

Adding the PURE prefix to give instead

pure function f(x, y, z)
  ...
end function

is where assessment of the constraints would be expected: something which makes PURE inappropriate for f will elicit complaints.

Consider, though:

subroutine s(f)
  interface
    pure function f(x,y,z)
      ...
    end function f
  end interface
end subroutine s

Here we can add the PURE prefix to the dummy procedure's interface block. But we aren't defining a subprogram here and so the numbered constraints don't apply: we can't expect a compiler to check whether the actual argument procedure is pure. There is no numbered constraint (or syntax rule) which says the interface block must be correct for the ultimate use. That's our responsibility as a programmer, and one the compiler may trust we give take seriously. Your compiler will make a good stab at checking and pick up many cases, but it doesn't have to account for our wilful desire to obfuscate.

francescalus
  • 30,576
  • 16
  • 61
  • 96
  • Therefore, adding "pure" may result in a compile or runtime error, but should never result in UB? – uLoop Sep 28 '21 at 15:14
  • At an ultra-high level I'd say, "yes, you will always get a compile-time error from your compiler", (compile-, rather than run-), but there is actually the possibility that there's a compiler out there with an option "--allow-pure-violations" which if used makes it accept programs which do violate the constraints: by definition such behaviour would be undefined. – francescalus Sep 28 '21 at 15:18
  • Oh, I meant without special flags that make the compiler accept just about everything. With compiler options, all bets are off. For GNU compilers you get things like -fpermissive and -Ofast, which abandon standards compliance in certain ways. – uLoop Sep 28 '21 at 15:29
  • The default could be for the compiler to allow violations (so needing an option like `--enforce-pure-constraints`), and this would still be a conforming compiler. The requirement is simply that a compiler must be _able to diagnose_, not that it _must diagnose by default_. (Again, in the real world there's no obvious benefit from a compiler which would allow such violations.) See for example `-std=` with GCC: some extensions, etc., are allowed by default. – francescalus Sep 28 '21 at 15:38
  • I've often thought it would be useful to have a variation of "pure" which wouldn't make any "promises", but would invite a compiler to reorder, create, or delete calls to a function in cases that wouldn't affect behavior if the function were pure, without regard for whether that would affect the function as written. Such a qualifier would be usable in many more circumstances than one which "promises" that a function is pure, while allowing most of the same useful optimizations. Do you know if any languages have such a qualifier? – supercat Sep 30 '21 at 15:05
  • @supercat, that seems an interesting question, but alas one I'm wholly unqualified to answer (even if you can't ask a real SO question, there are other SE sites where that could be answered by someone qualified). However, to some extant Fortran does a very small part of what you consider: there are uses of (non-pure) functions in a Fortran program where it is prohibited to rely on side effects (ie., assume whether the function was referenced at all, or if it was, at what point relative to other things). The gives the compiler some freedom, but probably not as much as you're after. – francescalus Sep 30 '21 at 15:23
  • @francescalus: One thing that annoys me about the C Standard is a presumption that the only way to allow a compiler to process a sequence of actions in a manner inconsistent with sequential program execution is to characterize at least one action in that sequence as invoking Undefined Behavior. I have no idea if Fortran suffers from that problem, but it creates needless conflicts between programmers and compiler writers. I'd like to see Fortran replace C in high-end computing applications, so compiler writers can stop trying to make the C language unsuitable for low-level programming. – supercat Sep 30 '21 at 15:28
2

If you are writing a Fortran function yourself and mark it pure then the compiler must check that it conforms to the requirements. However, there are many options where you can lie to the compiler and slip a non-pure external (or even a non-Fortran) function where a pure function is promised in an interface block. In such cases it is indeed a promise even if holding it is required by the standard and violating it makes the prohram non-conforming and thus non-Fortran.