This is an archive of the discontinued LLVM Phabricator instance.

[flang] Detect circularly defined interfaces of procedures
ClosedPublic

Authored by PeteSteinfeld on Mar 1 2021, 5:00 PM.

Details

Summary

It's possible to define a procedure whose interface depends on a procedure
which has an interface that depends on the original procedure. Such a circular
definition was causing the compiler to fall into an infinite loop when
resolving the name of the second procedure. It's also possible to create
circular dependency chains of more than two procedures.

I fixed this by adding the function HasCycle() to the class DeclarationVisitor
and calling it from DeclareProcEntity() to detect procedures with such
circularly defined interfaces. I marked the associated symbols of such
procedures by calling SetError() on them. When processing subsequent
procedures, I called HasError() before attempting to analyze their interfaces.
Unfortunately, this did not work.

With help from Tim, we determined that the SymbolSet used to track the
erroneous symbols was instantiated using a "<" operator which was defined using
the location of the name of the procedure. But the location of the procedure
name was being changed by a call to ReplaceName() between the times that the
calls to SetError() and HasError() were made. This caused HasError() to
incorrectly report that a symbol was not in the set of erroneous symbols.

I fixed this by changing SymbolSet to be an unordered set that uses the
contents of the name of the symbol as the basis for its hash function. This
works because the contents of the name of the symbol is preserved by
ReplaceName() even though its location changes.

I also fixed the error message used when reporting recursively defined dummy
procedure arguments.

I also added tests that will crash the compiler without this change.

Note that the "<" operator is used in other contexts, for example, in the map
of characterized procedures, maps of items in equivalence sets, maps of
structure constructor values, ... All of these situations happen after name
resolution has been completed and all calls to ReplaceName() have already
happened and thus are not subject to the problem I ran into when ReplaceName()
was called when processing procedure entities.

Note also that the implementation of the "<" operator uses the relative
location in the cooked character stream as the basis of its implementation.
This is potentially problematic when symbols from diffent compilation units
(for example symbols originating in .mod files) are put into the same map since
their names will appear in two different source streams which may not be
allocated in the same relative positions in memory. But I was unable to create
a test that caused a problem. Using a direct comparison of the content of the
name of the symbol in the "<" operator has problems. Symbols in enclosing or
parallel scopes can have the same name. Also using the location of the symbol
in the cooked character stream has the advantage that it preserves the the
order of the symbols in a structure constructor constant, which makes matching
the values with the symbols relatively easy.

This change supersedes D97201.

Diff Detail

Event Timeline

PeteSteinfeld requested review of this revision.Mar 1 2021, 5:00 PM
PeteSteinfeld created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptMar 1 2021, 5:00 PM
PeteSteinfeld added a project: Restricted Project.Mar 1 2021, 5:01 PM
klausler accepted this revision.Mar 1 2021, 6:22 PM
klausler added inline comments.
flang/include/flang/Semantics/symbol.h
775

We should think about renaming this typedef. It's not really a set of arbitrary Symbol references any more, since two Symbols with the same name strings will clash. SymbolSet seems to me like a name for what would be an unordered_set that hashed the addresses of the Symbols instead.

We don't have to fix this in this patch; I'll try to clean things up more afterwards.

This revision is now accepted and ready to land.Mar 1 2021, 6:22 PM
This revision was landed with ongoing or failed builds.Mar 1 2021, 7:18 PM
This revision was automatically updated to reflect the committed changes.

@PeteSteinfeld, thank you for resubmitting https://reviews.llvm.org/D97201, but this is still failing on 6 out 8 our public Flang buildbots:

If I understand correctly, std::hash that you use here is implementation-dependent and hence the the expected result in resolve102.f90 is not 100% deterministic and hence it is not matched on certain platforms.

In D97201 I proposed a solution that to the best of my knowledge will work on every platform (I tested it on AArch64). If you prefer a different approach, I'm happy to test it on an AArch64 machine before this is merged. Please could you add me as a reviewer for that? I am very keen to help with this and to make it work on every of the supported platforms.