Skip to content

Commit 722c7c0

Browse files
[flang][Semantics] Ensure deterministic mod file output (#128655)
This PR adds a test to ensure deterministic ordering in `.mod` files. It also includes related changes to prevent non-deterministic symbol ordering caused by pointers outside the cooked source. This issue is particularly noticeable when using Flang as a library and compiling the same files multiple times.
1 parent 7717a54 commit 722c7c0

File tree

3 files changed

+43
-19
lines changed

3 files changed

+43
-19
lines changed

flang/lib/Semantics/mod-file.cpp

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -836,18 +836,6 @@ void ModFileWriter::PutUseExtraAttr(
836836
}
837837
}
838838

839-
static inline SourceName NameInModuleFile(const Symbol &symbol) {
840-
if (const auto *use{symbol.detailsIf<UseDetails>()}) {
841-
if (use->symbol().attrs().test(Attr::PRIVATE)) {
842-
// Avoid the use in sorting of names created to access private
843-
// specific procedures as a result of generic resolution;
844-
// they're not in the cooked source.
845-
return use->symbol().name();
846-
}
847-
}
848-
return symbol.name();
849-
}
850-
851839
// Collect the symbols of this scope sorted by their original order, not name.
852840
// Generics and namelists are exceptions: they are sorted after other symbols.
853841
void CollectSymbols(const Scope &scope, SymbolVector &sorted,
@@ -882,13 +870,8 @@ void CollectSymbols(const Scope &scope, SymbolVector &sorted,
882870
sorted.push_back(symbol);
883871
}
884872
}
885-
// Sort most symbols by name: use of Symbol::ReplaceName ensures the source
886-
// location of a symbol's name is the first "real" use.
887-
auto sorter{[](SymbolRef x, SymbolRef y) {
888-
return NameInModuleFile(*x).begin() < NameInModuleFile(*y).begin();
889-
}};
890-
std::sort(sorted.begin(), sorted.end(), sorter);
891-
std::sort(generics.begin(), generics.end(), sorter);
873+
std::sort(sorted.begin(), sorted.end(), SymbolSourcePositionCompare{});
874+
std::sort(generics.begin(), generics.end(), SymbolSourcePositionCompare{});
892875
sorted.insert(sorted.end(), generics.begin(), generics.end());
893876
sorted.insert(sorted.end(), namelist.begin(), namelist.end());
894877
for (const auto &pair : scope.commonBlocks()) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module foo
2+
interface do_foo
3+
procedure do_foo_impl
4+
end interface
5+
interface do_bar
6+
procedure do_bar_impl
7+
end interface
8+
contains
9+
subroutine do_foo_impl()
10+
end
11+
subroutine do_bar_impl()
12+
end
13+
end

flang/test/Semantics/modfile72.f90

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
! This test verifies that both invocations produce a consistent order in the
2+
! generated `.mod` file. Previous versions of Flang exhibited non-deterministic
3+
! behavior due to pointers outside the cooked source being used to order symbols
4+
! in the `.mod` file.
5+
6+
! RUN: rm -rf %t && mkdir -p %t
7+
! RUN: %flang_fc1 -fsyntax-only -J%t %S/Inputs/modfile72.f90
8+
! RUN: %flang_fc1 -fsyntax-only -J%t %s
9+
! RUN: cat %t/bar.mod | FileCheck %s
10+
11+
! RUN: rm -rf %t && mkdir -p %t
12+
! RUN: %flang_fc1 -fsyntax-only -J%t %S/Inputs/modfile72.f90 %s
13+
! RUN: cat %t/bar.mod | FileCheck %s
14+
15+
module bar
16+
use foo, only : do_foo
17+
use foo, only : do_bar
18+
contains
19+
subroutine do_baz()
20+
call do_foo()
21+
call do_bar()
22+
end
23+
end
24+
25+
! CHECK: use foo,only:do_foo
26+
! CHECK-NEXT: use foo,only:do_bar
27+
! CHECK-NEXT: use foo,only:foo$foo$do_bar_impl=>do_bar_impl
28+
! CHECK-NEXT: use foo,only:foo$foo$do_foo_impl=>do_foo_impl

0 commit comments

Comments
 (0)