This is an archive of the discontinued LLVM Phabricator instance.

[flang] Do not ICE on recursive function definition in function result
ClosedPublic

Authored by unterumarmung on Apr 18 2022, 3:59 AM.

Details

Summary

The following code causes the compiler to ICE in several places due to
lack of support of recursive procedure definitions through the function
result.

function foo() result(r)
  procedure(foo), pointer :: r
end function foo

Diff Detail

Event Timeline

unterumarmung created this revision.Apr 18 2022, 3:59 AM
Herald added projects: Restricted Project, Restricted Project. · View Herald TranscriptApr 18 2022, 3:59 AM
unterumarmung requested review of this revision.Apr 18 2022, 3:59 AM
klausler added inline comments.Apr 18 2022, 9:11 AM
flang/include/flang/Semantics/symbol.h
694

Your changes make Symbol::Rank() and Symbol::GetType() more expensive to call and liable to allocate/deallocate memory for all programs. Would it be sufficient to just use an integer argument to limit the call depth? That would avoid a crash in erroneous tests without affecting compilation for correct programs.

flang/lib/Semantics/check-declarations.cpp
1789

When generic is not GenericDetails, what is it?

unterumarmung added inline comments.Apr 18 2022, 11:41 AM
flang/include/flang/Semantics/symbol.h
694

That's a great idea! But, to be honest, I'm having a hard time coming up with an initial value for such argument. Is there a limit for number of nested calls of these functions for correct programs? Or, maybe, we should use some big enough value that probably is not encountered in correct programs, yet lets us avoid the stack overflow?

flang/lib/Semantics/check-declarations.cpp
1789

Well, the generic was written not by me. If I understand correctly, generic is a Symbol that meant to have the GenericDetails.

klausler added inline comments.Apr 18 2022, 11:47 AM
flang/include/flang/Semantics/symbol.h
694

There is not a limit in the standard, but something like 100 should work. And then you should crash with CHECK() instead of returning a rank of 0 or a null type.

flang/lib/Semantics/check-declarations.cpp
1789

Yes, but you're going out of your way to pass it to Characterize(), so I assume that you've encountered this case in a test somewhere. If you keep this call here, why does it apply only to functions? Fortran has generic subroutines as well.

unterumarmung added inline comments.Apr 18 2022, 12:05 PM
flang/include/flang/Semantics/symbol.h
694

Ok, I'll try it and submit the updated patch if it works

flang/lib/Semantics/check-declarations.cpp
1789

Well, if we delete this chunk of code and run the test, we will get an ICE in the lowering part of the compiler because we do not call the Characterize on foo or r (from the test) because they do not have GenericDetails. And because there's not any other compile errors, the execution of compiler successfully goes to the lowering, where it tries to generate Procedure for foo via Characterize and crashes there. I added the code here specifically for functions, to enable at least some semantic checks for the generic symbol.

This is not the best solution and I'd be glad to consider your (or anyone else's) advices how to make it better, if you have any.

klausler added inline comments.Apr 18 2022, 12:12 PM
flang/lib/Semantics/check-declarations.cpp
1789

Ok, but I don't think that the Function flag on the symbol means what you think. Try testing for .has<SubprogramDetails>() so that it works for functions and subroutines.

unterumarmung marked 2 inline comments as not done.Apr 19 2022, 1:53 AM
unterumarmung added inline comments.
flang/lib/Semantics/check-declarations.cpp
1789

I tried and it creates a lot of new error messages for resolve102.f90
For example, for sub1 in this chunk of test: https://github.com/llvm/llvm-project/blob/main/flang/test/Semantics/resolve102.f90#L51-L65 it generates 3 errors instead of 1:

./flang/test/Semantics/resolve102.f90:48:16: error: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'sub1', 'arg', 'sub', 'p2'
      Subroutine sub1(arg)
                 ^^^^
./flang/test/Semantics/resolve102.f90:48:16: error: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'sub1', 'arg'
      Subroutine sub1(arg)
                 ^^^^
./flang/test/Semantics/resolve102.f90:48:16: error: Procedure 'sub1' is recursively defined.  Procedures in the cycle: 'p', 'sub1', 'arg'
      Subroutine sub1(arg)
                 ^^^^

All the errors seem fair. Is it an acceptable behavior? If it is, I'll proceed with the change.
Personally, I think that "more errors is better" - because it can help fix erroneous code faster.

Changed the recursion cycles approach

Fixed changes

unterumarmung added inline comments.Apr 19 2022, 3:00 AM
flang/include/flang/Semantics/symbol.h
694

Well, I do not think, that we should crash here. The whole point of the change was not to emit the internal compiler error, but proceed with nullptr or rank of 0 to give a readable error.
I added the updated version of recursion handling but with returning invalid values.

klausler added inline comments.Apr 19 2022, 9:00 AM
flang/include/flang/Semantics/symbol.h
691

Braced initialization, please.

unterumarmung marked an inline comment as not done.

Rebased, squashed commits, used braced initialization

0 -> nullptr

flang/include/flang/Semantics/symbol.h
691

Oops..
Done!

klausler accepted this revision.Apr 20 2022, 7:36 AM
This revision is now accepted and ready to land.Apr 20 2022, 7:36 AM